
# Drop a company logo into your app — copy-paste recipes

> Practical snippets for the common shapes a logo ends up in: an `<img>` tag, a React component, a Next.js Image, a Tailwind avatar slot, a dark-mode-aware `<picture>` element, an OG image fallback, and a server-signed URL. Every snippet works against the public `https://api.clearlogo.dev` endpoint.
>
> All examples assume you have a browser key (for client code) or a server key (for backend code). [Create a key](https://clearlogo.dev/login?lang=en) from the dashboard.

## 1. Plain HTML

Fastest possible integration — paste the URL into an `<img>` tag.

```html
<img
  src="https://api.clearlogo.dev/logo/github.com?size=64&content=80&token=YOUR_BROWSER_KEY"
  alt="GitHub"
  width="64"
  height="64"
/>
```

Set `size` to match the rendered dimension so the browser doesn't waste bandwidth scaling a larger asset.

## 2. React component

A small reusable component covers most product UI needs.

```tsx
type CompanyLogoProps = {
  domain: string;
  size?: 32 | 48 | 64 | 96 | 128;
  alt?: string;
};

const BROWSER_KEY = process.env.NEXT_PUBLIC_CLEARLOGO_KEY!;

export function CompanyLogo({ domain, size = 64, alt }: CompanyLogoProps) {
  return (
    <img
      src={`https://api.clearlogo.dev/logo/${domain}?size=${size}&content=80&token=${BROWSER_KEY}`}
      alt={alt ?? `${domain} logo`}
      width={size}
      height={size}
      loading="lazy"
      decoding="async"
    />
  );
}
```

`loading="lazy"` and `decoding="async"` keep long lists (CRMs, directories, account tables) from blocking paint.

## 3. Next.js `<Image>`

Add the API host to `next.config.js` once, then use the optimized `<Image>` component everywhere.

```js
// next.config.js
module.exports = {
  images: {
    remotePatterns: [
      { protocol: "https", hostname: "api.clearlogo.dev" },
    ],
  },
};
```

```tsx
import Image from "next/image";

export function CompanyLogo({ domain, size = 64 }: { domain: string; size?: number }) {
  return (
    <Image
      src={`https://api.clearlogo.dev/logo/${domain}?size=${size * 2}&content=80&token=${process.env.NEXT_PUBLIC_CLEARLOGO_KEY}`}
      alt={`${domain} logo`}
      width={size}
      height={size}
      unoptimized
    />
  );
}
```

Request `size * 2` for retina sharpness on HiDPI displays. Use `unoptimized` if you want the WebP negotiation from the API to flow through to the client; remove it if you want Next.js to handle format negotiation itself.

## 4. Tailwind avatar slot

Drop the logo into a fixed UI slot that stays visually consistent across brands.

```tsx
<div className="flex items-center gap-3">
  <div className="h-10 w-10 overflow-hidden rounded-md bg-neutral-100 ring-1 ring-neutral-200">
    <img
      src={`https://api.clearlogo.dev/logo/${domain}?size=64&content=80&token=${BROWSER_KEY}`}
      alt=""
      className="h-full w-full object-contain"
    />
  </div>
  <div>
    <div className="font-medium">{name}</div>
    <div className="text-sm text-neutral-500">{domain}</div>
  </div>
</div>
```

`object-contain` plus a fixed slot size is the most reliable shape for tables and lists. Pair with the `content=80` parameter so the logo never butts up against the slot edge.

## 5. Dark-mode-aware logo

Use `<picture>` with `prefers-color-scheme` to swap dark/light variants at paint time, with zero JavaScript or per-logo rerenders.

```html
<picture>
  <source
    srcset="https://api.clearlogo.dev/logo/github.com?size=64&theme=dark&token=YOUR_BROWSER_KEY"
    media="(prefers-color-scheme: dark)"
  />
  <img
    src="https://api.clearlogo.dev/logo/github.com?size=64&theme=light&token=YOUR_BROWSER_KEY"
    alt="GitHub"
    width="64"
    height="64"
  />
</picture>
```

Wrapped as a React component:

```tsx
export function CompanyLogo({ domain, size = 64 }: { domain: string; size?: number }) {
  const base = `https://api.clearlogo.dev/logo/${domain}?size=${size}&content=80&token=${BROWSER_KEY}`;
  return (
    <picture>
      <source srcSet={`${base}&theme=dark`} media="(prefers-color-scheme: dark)" />
      <img src={`${base}&theme=light`} alt={`${domain} logo`} width={size} height={size} />
    </picture>
  );
}
```

The API falls back to the light variant when no dark version exists, so it's always safe to request `theme=dark`. For app-level theme switches (not OS-level), drive the source URL from your theme state instead of `prefers-color-scheme`.

## 6. List rendering with a placeholder

For long lists, render an immediate placeholder so empty slots don't flash.

```tsx
function LogoCell({ domain }: { domain: string }) {
  const [loaded, setLoaded] = useState(false);
  return (
    <div className="relative h-10 w-10 rounded-md bg-neutral-100">
      <img
        src={`https://api.clearlogo.dev/logo/${domain}?size=64&content=80&token=${BROWSER_KEY}`}
        alt=""
        loading="lazy"
        onLoad={() => setLoaded(true)}
        className={`h-full w-full object-contain transition-opacity ${
          loaded ? "opacity-100" : "opacity-0"
        }`}
      />
    </div>
  );
}
```


## 7. Error fallback with the first letter

If the API can't find a logo for a domain, render a deterministic letter avatar instead.

```tsx
function LogoOrFallback({ domain, name }: { domain: string; name: string }) {
  const [errored, setErrored] = useState(false);

  if (errored) {
    return (
      <div className="flex h-10 w-10 items-center justify-center rounded-md bg-neutral-200 font-medium text-neutral-600">
        {name[0]?.toUpperCase() ?? "?"}
      </div>
    );
  }

  return (
    <img
      src={`https://api.clearlogo.dev/logo/${domain}?size=64&content=80&token=${BROWSER_KEY}`}
      alt={`${name} logo`}
      width={40}
      height={40}
      className="rounded-md"
      onError={() => setErrored(true)}
    />
  );
}
```

The fallback never network-requests, so even cold rows stay snappy.

## 8. Open Graph image fallback

Embed a logo into a dynamically-generated OG image via a server-side fetch.

```ts
// app/og/route.ts (Next.js, Edge runtime)
import { ImageResponse } from "next/og";

export const runtime = "edge";

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const domain = searchParams.get("domain") ?? "example.com";

  const logoUrl = `https://api.clearlogo.dev/logo/${domain}?size=256&content=80&token=YOUR_SERVER_KEY`;

  return new ImageResponse(
    (
      <div style={{ display: "flex", alignItems: "center", padding: 64 }}>
        <img src={logoUrl} width={128} height={128} alt="" />
        <span style={{ marginLeft: 32, fontSize: 64 }}>{domain}</span>
      </div>
    ),
    { width: 1200, height: 630 },
  );
}
```

Use a **server** key here, not a browser key — Edge functions are server-side, and a server key is what survives unrestricted origin headers.

## 9. Backend signing for sensitive UIs

When you don't want the URL public (e.g. internal admin tools), proxy through your backend.

```ts
// app/api/logo/[domain]/route.ts (Next.js)
export async function GET(
  request: Request,
  { params }: { params: { domain: string } },
) {
  const upstream = await fetch(
    `https://api.clearlogo.dev/logo/${params.domain}?size=128&content=80`,
    { headers: { Authorization: `Bearer ${process.env.CLEARLOGO_SERVER_KEY}` } },
  );
  return new Response(upstream.body, {
    headers: {
      "Content-Type": upstream.headers.get("Content-Type") ?? "image/png",
      "Cache-Control": "public, max-age=86400, s-maxage=86400",
    },
  });
}
```

No API key in the page source, and you control caching at your own CDN.

## 10. TypeScript helper

A single helper keeps URL construction consistent across the codebase.

```ts
type LogoOptions = {
  size?: 16 | 32 | 48 | 64 | 96 | 128 | 192 | 256 | 512 | 1024;
  content?: number; // 50–100, step 5
  theme?: "light" | "dark";
  format?: "png" | "webp" | "jpeg";
};

export function logoUrl(domain: string, opts: LogoOptions = {}): string {
  const params = new URLSearchParams({
    size: String(opts.size ?? 64),
    content: String(opts.content ?? 80),
    token: process.env.NEXT_PUBLIC_CLEARLOGO_KEY!,
  });
  if (opts.theme) params.set("theme", opts.theme);
  if (opts.format) params.set("format", opts.format);
  return `https://api.clearlogo.dev/logo/${encodeURIComponent(domain)}?${params}`;
}
```

`encodeURIComponent` protects against unusual characters in domains and makes the helper safe to call with untrusted input.

## 11. Preconnect to warm the connection early

For dashboards that render dozens of logos above the fold, the first request pays for DNS, TCP, and TLS. Add a single `<link rel="preconnect">` to your document head so the connection is ready before the first `<img>` hits — every subsequent logo gets a head start without per-URL preload bloat.

```html
<link rel="preconnect" href="https://api.clearlogo.dev" crossorigin />
<link rel="dns-prefetch" href="https://api.clearlogo.dev" />
```

```tsx
// Next.js
import Head from "next/head";

export function ClearLogoPreconnect() {
  return (
    <Head>
      <link rel="preconnect" href="https://api.clearlogo.dev" crossOrigin="" />
      <link rel="dns-prefetch" href="https://api.clearlogo.dev" />
    </Head>
  );
}
```

`preconnect` resolves DNS and opens the TCP/TLS handshake immediately; `dns-prefetch` is a cheap fallback for browsers that ignore the preconnect. Two hints total, regardless of how many logos the page renders. Prefer this over `<link rel="preload" as="image">` per logo — preloads are heavyweight, count toward bandwidth budgets, and don't help if the rendered URL ends up slightly different (size, theme, token) from the preloaded one.

## FAQ

### Which recipe should I start with?

For a single logo, the plain `<img>` recipe is enough. For lists and tables, start with the Tailwind avatar slot + lazy-load pattern.

### Do I need a key for testing?

No. The endpoint works anonymously for low-volume browsing. Add a browser key before you ship to production so the request is properly attributed and counted against your plan.

### What size should I request?

Match the rendered size in CSS, then request `2x` that for retina sharpness. Don't request `1024` for a 32-pixel slot — it costs bandwidth and doesn't look any better.

### How do I handle dark mode without JavaScript?

Use a `<picture>` element with a `<source>` gated by `media="(prefers-color-scheme: dark)"`. The browser picks the right URL at paint time — no React hook, no rerender per logo, no per-row overhead even in long lists.

### How do I make a list of logos load faster?

Add a single `<link rel="preconnect" href="https://api.clearlogo.dev">` in your document head. That opens DNS/TCP/TLS once for every logo on the page, which is cheaper than `<link rel="preload">` per URL.

### How do I show a fallback when the API returns no logo?

Listen for `onError` on the `<img>` and swap in a letter-avatar or a generic icon. The error fallback recipe above is the production shape.

### Can I use a browser key from a server-side render?

You can — but a server key is a better fit because it sends the request via `Authorization: Bearer …` rather than relying on origin checks. For Next.js Server Components, OG routes, or backend proxies, use a server key.

### How do I cache logos at my own CDN?

Use the backend-signing recipe above. The upstream response includes long-lived `Cache-Control`, so you can set the same headers on your proxy and let your CDN do the rest.
