@quikturn/logos

May 29, 2026 · View on GitHub

TypeScript SDK for the Quikturn Logos API -- fetch any company's logo by domain name.

Get your API key -- free tier available, no credit card required.

PackageDescriptionInstall
@quikturn/logosCore SDK -- URL builder, browser client, server client, web componentpnpm add @quikturn/logos
@quikturn/logos-reactReact components -- logo, carousel, gridpnpm add @quikturn/logos-react
@quikturn/logos-nextNext.js -- next/image wrapper, loaders, server helperspnpm add @quikturn/logos-next
@quikturn/logos-vueVue 3 components -- logo, carousel, grid, pluginpnpm add @quikturn/logos-vue
@quikturn/logos-svelteSvelte 5 components -- logo, carousel, grid, runespnpm add @quikturn/logos-svelte
@quikturn/logos-angularAngular 17+ -- standalone components, signals, pipepnpm add @quikturn/logos-angular

Install

pnpm add @quikturn/logos

Requires Node.js >= 18. Works with pnpm, npm, or yarn.

Need an API key? Sign up at getquikturn.io -- takes 30 seconds.

Pick Your Entry Point

Entry PointImportUse Case
Universal@quikturn/logosURL builder, types, constants -- zero dependencies, any runtime
Browser@quikturn/logos/clientBlob URLs, retry/backoff, scrape polling, events
Server@quikturn/logos/serverBuffer output, streaming, batch operations
Element@quikturn/logos/element<quikturn-logo> web component with built-in attribution

Framework Packages

PackageImportFramework
React@quikturn/logos-reactReact 18+ -- components, hooks, context
Next.js@quikturn/logos-nextNext.js 14+ -- next/image wrapper, server helpers
Vue@quikturn/logos-vueVue 3.3+ -- SFCs, composables, plugin
Svelte@quikturn/logos-svelteSvelte 5 -- runes, snippets, context
Angular@quikturn/logos-angularAngular 17+ -- standalone components, signals, pipe

Quick Start

URL Builder

The simplest way to get a logo URL. Runs everywhere -- browsers, Node.js, edge runtimes -- with no network calls.

import { logoUrl } from "@quikturn/logos";

const url = logoUrl("github.com");
// => "https://logos.getquikturn.io/github.com"

const url = logoUrl("stripe.com", {
  token: "qt_abc123",
  size: 256,
  format: "webp",
  greyscale: true,
  theme: "dark",
});

Search for company logos by name or domain:

import { searchLogos } from "@quikturn/logos";

const results = await searchLogos({
  q: "stripe",
  token: "pk_live_xxx",
});

for (const result of results.results) {
  console.log(result.domain, result.logoUrl);
}

SSR Note: searchLogos deduplicates concurrent identical requests at the module level. In server-side rendering environments, pass an AbortSignal to bypass deduplication and ensure per-request isolation. Note: providing your own signal opts out of the default 10-second fetch timeout — use AbortSignal.timeout(10000) (or your preferred duration) to prevent hung requests in server environments.

Search Options

OptionTypeDefaultDescription
qstringrequiredSearch query
mode"autocomplete" | "search""autocomplete"Search mode
pagenumber1Page number
limitnumber10 (autocomplete) / 25 (search)Results per page. Capped at 20 (autocomplete) / 100 (search).
filtersSearchFiltersOptional field filters
sortstringSort expression
tokenstringAPI token (publishable key)
baseUrlstringOverride API base URL (staging)
signalAbortSignalOptional AbortSignal for request cancellation

Browser Client

import { QuikturnLogos } from "@quikturn/logos/client";

const client = new QuikturnLogos({ token: "qt_your_publishable_key" });

const { url, blob, contentType } = await client.get("github.com", {
  size: 256,
  format: "webp",
});

document.querySelector("img")!.src = url;

// Clean up blob URLs when done
client.destroy();

Server Client

import { QuikturnLogos } from "@quikturn/logos/server";

const client = new QuikturnLogos({ secretKey: "sk_your_secret_key" });

// Single logo
const { buffer, contentType } = await client.get("github.com");

// Batch fetch
for await (const result of client.getMany(["github.com", "stripe.com", "vercel.com"])) {
  if (result.success) console.log(`${result.domain}: ${result.buffer!.byteLength} bytes`);
}

// Stream to file
import { createWriteStream } from "node:fs";
import { Readable } from "node:stream";

const stream = await client.getStream("github.com", { format: "png" });
Readable.fromWeb(stream).pipe(createWriteStream("logo.png"));

Web Component

No framework needed. Import the element entry and use it in plain HTML:

<script type="module">
  import "@quikturn/logos/element";
</script>

<quikturn-logo domain="github.com" token="qt_abc123" size="64"></quikturn-logo>

Renders the logo with a "Powered by Quikturn" attribution badge protected by shadow DOM.

React

pnpm add @quikturn/logos-react
import { QuikturnProvider, QuikturnLogo, QuikturnLogoCarousel } from "@quikturn/logos-react";

function App() {
  return (
    <QuikturnProvider token="qt_your_key">
      <QuikturnLogo domain="github.com" size={64} />

      <QuikturnLogoCarousel
        domains={["github.com", "stripe.com", "vercel.com", "figma.com"]}
        speed={120}
        fadeOut
        pauseOnHover
      />
    </QuikturnProvider>
  );
}

Full API reference: @quikturn/logos-react docs

Next.js

pnpm add @quikturn/logos-next
import { QuikturnProvider, QuikturnImage } from "@quikturn/logos-next";

export default function Page() {
  return (
    <QuikturnProvider token="qt_your_key">
      <QuikturnImage domain="github.com" width={128} height={128} alt="GitHub" />
    </QuikturnProvider>
  );
}

Full API reference: @quikturn/logos-next docs

Vue

pnpm add @quikturn/logos-vue
<script setup lang="ts">
import { QuikturnLogo, QuikturnLogoCarousel } from "@quikturn/logos-vue";
</script>

<template>
  <QuikturnLogo domain="github.com" :size="64" />

  <QuikturnLogoCarousel
    :domains="['github.com', 'stripe.com', 'vercel.com', 'figma.com']"
    :speed="120"
    fade-out
    pause-on-hover
  />
</template>

Full API reference: @quikturn/logos-vue docs

Svelte

pnpm add @quikturn/logos-svelte
<script>
  import { QuikturnProvider, QuikturnLogo, QuikturnLogoCarousel } from "@quikturn/logos-svelte";
</script>

<QuikturnProvider token="qt_your_key">
  <QuikturnLogo domain="github.com" size={64} />

  <QuikturnLogoCarousel
    domains={["github.com", "stripe.com", "vercel.com", "figma.com"]}
    speed={120}
    fadeOut
    pauseOnHover
  />
</QuikturnProvider>

Full API reference: @quikturn/logos-svelte docs

Angular

pnpm add @quikturn/logos-angular
// app.config.ts
import { provideQuikturnLogos } from "@quikturn/logos-angular";

export const appConfig = {
  providers: [provideQuikturnLogos({ token: "qt_your_key" })],
};
import { Component } from "@angular/core";
import { QuikturnLogoComponent, QuikturnLogoCarouselComponent } from "@quikturn/logos-angular";

@Component({
  selector: "app-example",
  standalone: true,
  imports: [QuikturnLogoComponent, QuikturnLogoCarouselComponent],
  template: `
    <quikturn-logo domain="github.com" [size]="64" />

    <quikturn-logo-carousel
      [domains]="['github.com', 'stripe.com', 'vercel.com', 'figma.com']"
      [speed]="120"
      [fadeOut]="true"
      [pauseOnHover]="true"
    />
  `,
})
export class ExampleComponent {}

Full API reference: @quikturn/logos-angular docs


Authentication

Key TypePrefixEnvironmentAuth Method
Publishableqt_ / pk_BrowserQuery parameter (?token=...)
Secretsk_Server onlyAuthorization: Bearer header

Publishable keys are safe to expose in client-side code (max 800px). Secret keys must never reach the browser (max 1200px). Manage your keys in the Quikturn dashboard.

// Browser
import { QuikturnLogos } from "@quikturn/logos/client";
const client = new QuikturnLogos({ token: "qt_your_publishable_key" });

// Server
import { QuikturnLogos } from "@quikturn/logos/server";
const client = new QuikturnLogos({ secretKey: "sk_your_secret_key" });

API Reference

logoUrl(domain, options?)

Pure URL builder. No network calls, no side effects.

import { logoUrl } from "@quikturn/logos";

Options:

PropertyTypeDefaultDescription
tokenstring--API key appended as query parameter
sizenumber128Output width in pixels
widthnumber128Alias for size
greyscalebooleanfalseDesaturation filter
theme"light" | "dark"--Background-optimized rendering
formatstring"image/png""png", "jpeg", "webp", "avif" (or full MIME type)

Returns: string | Throws: DomainValidationError


Browser Client

import { QuikturnLogos } from "@quikturn/logos/client";

Constructor

OptionTypeDefaultDescription
tokenstringrequiredPublishable key (qt_/pk_ prefix)

| maxRetries | number | 2 | Max retries for 429/5xx responses |

Methods

client.get(domain, options?) -- Fetches a logo and returns a blob URL.

OptionTypeDefault
sizenumber128
formatstring"image/png"
greyscalebooleanfalse
theme"light" | "dark"--
scrapeTimeoutnumber--
onScrapeProgress(event) => void--
signalAbortSignal--

Returns Promise<{ url: string, blob: Blob, contentType: string, metadata: LogoMetadata }>.

client.getUrl(domain, options?) -- Returns a plain URL string without a network request.

client.on(event, handler) / client.off(event, handler) -- Listen for "rateLimitWarning" or "quotaWarning" events.

client.destroy() -- Revokes all tracked blob URLs and removes event listeners. Call this to prevent memory leaks.


Server Client

import { QuikturnLogos } from "@quikturn/logos/server";

Constructor

OptionTypeDefaultDescription
secretKeystringrequiredSecret key (sk_ prefix)

| maxRetries | number | 2 | Max retries for 429/5xx responses |

Methods

client.get(domain, options?) -- Returns Promise<{ buffer: Buffer, contentType: string, metadata: LogoMetadata }>.

client.getMany(domains, options?) -- Batch fetch with concurrency control. Returns AsyncGenerator<BatchResult>.

OptionTypeDefault
concurrencynumber5
continueOnErrorbooleantrue
signalAbortSignal--

client.getStream(domain, options?) -- Returns Promise<ReadableStream> for zero-copy streaming.

client.getUrl(domain, options?) -- Returns a URL string (secret key NOT included -- use Authorization header).

client.on(event, handler) / client.off(event, handler) -- Same events as the browser client.


Web Component

import "@quikturn/logos/element";
AttributeTypeDescription
domainstringDomain to fetch logo for (required)
tokenstringPublishable API key
sizestringImage width in pixels
formatstring"png", "jpeg", "webp", or "avif"
greyscale(presence)Greyscale filter when attribute is present
themestring"light" or "dark"

Auto-registers as <quikturn-logo> on import. Shadow DOM protects the attribution badge with !important CSS rules.


Error Handling

All errors extend LogoError with a typed code property for exhaustive switch handling:

import { LogoError } from "@quikturn/logos";

try {
  const { url } = await client.get("example.com");
} catch (err) {
  if (err instanceof LogoError) {
    switch (err.code) {
      case "RATE_LIMIT_ERROR":   /* backoff */  break;
      case "NOT_FOUND_ERROR":    /* fallback */  break;
      case "AUTHENTICATION_ERROR": /* check key */ break;
      // ...
    }
  }
}
ErrorCodeStatusExtra Properties
DomainValidationErrorDOMAIN_VALIDATION_ERROR--domain
AuthenticationErrorAUTHENTICATION_ERROR401--
ForbiddenErrorFORBIDDEN_ERROR403reason
NotFoundErrorNOT_FOUND_ERROR404domain
BadRequestErrorBAD_REQUEST_ERROR400--
RateLimitErrorRATE_LIMIT_ERROR429retryAfter, remaining, resetAt
QuotaExceededErrorQUOTA_EXCEEDED_ERROR429retryAfter, limit, used
ScrapeTimeoutErrorSCRAPE_TIMEOUT_ERROR--jobId, elapsed

Types & Constants

import type {
  ThemeOption,           // "light" | "dark"
  SupportedOutputFormat, // "image/png" | "image/jpeg" | "image/webp" | "image/avif"
  FormatShorthand,       // "png" | "jpeg" | "webp" | "avif"
  LogoRequestOptions,
  LogoMetadata,
  BrowserLogoResponse,
  ServerLogoResponse,
  ScrapeProgressEvent,
  LogoErrorCode,         // discriminated union of all error codes
} from "@quikturn/logos";
ConstantValue
BASE_URL"https://logos.getquikturn.io"
DEFAULT_WIDTH128
DEFAULT_FORMAT"image/png"
SUPPORTED_FORMATSSet of 4 MIME types
FORMAT_ALIASES{ png, jpeg, webp, avif } -> MIME mapping

Configuration

Formats

FormatShorthandMIME Type
PNG"png"image/png
JPEG"jpeg"image/jpeg
WebP"webp"image/webp
AVIF"avif"image/avif

Both forms are accepted: format: "webp" and format: "image/webp" are equivalent.

Themes

Use "light" for light backgrounds and "dark" for dark backgrounds. The API adjusts the logo's color profile to maximize contrast.

Rate Limits & Quotas

Rate limits and monthly quotas are enforced server-side and vary by plan. The SDK automatically retries with exponential backoff when limits are hit and emits "rateLimitWarning" / "quotaWarning" events so you can react in your UI. See pricing & plan details.

Resources

Contributing

We welcome, appreciate, and applaud all contributions! See CONTRIBUTING.md for setup instructions and guidelines.

License

MIT -- built by Quikturn