
# Coloque um logo de empresa no seu app — receitas prontas para copiar e colar

> Snippets práticos para as formas comuns nas quais um logo acaba: uma tag `<img>`, um componente React, uma Next.js Image, um slot de avatar Tailwind, um elemento `<picture>` consciente de modo escuro, um fallback de imagem OG e uma URL assinada no servidor. Todo snippet funciona contra o endpoint público `https://api.clearlogo.dev`.
>
> Todos os exemplos assumem que você tem uma chave de navegador (para código de cliente) ou uma chave de servidor (para código de backend). [Crie uma chave](https://clearlogo.dev/login?lang=pt) no painel.

## 1. HTML simples

Integração mais rápida possível — cole a URL em uma tag `<img>`.

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

Defina `size` para corresponder à dimensão renderizada para que o navegador não desperdice largura de banda escalando um ativo maior.

## 2. Componente React

Um pequeno componente reutilizável cobre a maioria das necessidades de UI do produto.

```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"` e `decoding="async"` evitam que listas longas (CRMs, diretórios, tabelas de contas) bloqueiem a renderização.

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

Adicione o host da API a `next.config.js` uma vez, depois use o componente `<Image>` otimizado em qualquer lugar.

```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
    />
  );
}
```

Peça `size * 2` para nitidez retina em displays HiDPI. Use `unoptimized` se quiser que a negociação de WebP da API flua para o cliente; remova se quiser que o Next.js trate a negociação de formato em si.

## 4. Slot de avatar Tailwind

Coloque o logo em um slot de UI fixo que permaneça visualmente consistente entre marcas.

```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` mais um tamanho de slot fixo é a forma mais confiável para tabelas e listas. Emparelhe com o parâmetro `content=80` para que o logo nunca toque a borda do slot.

## 5. Logo consciente de modo escuro

Use `<picture>` com `prefers-color-scheme` para trocar variantes escuras/claras no tempo de renderização, sem JavaScript ou rerenders por logo.

```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>
```

Envolvido como um componente React:

```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>
  );
}
```

A API volta para a variante clara quando nenhuma versão escura existe, então é sempre seguro pedir `theme=dark`. Para mudanças de tema no nível do app (não no nível do SO), conduza a URL da fonte do seu estado de tema em vez de `prefers-color-scheme`.

## 6. Renderização de lista com placeholder

Para listas longas, renderize um placeholder imediato para que slots vazios não piscassem.

```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. Fallback de erro com a primeira letra

Se a API não conseguir encontrar um logo para um domínio, renderize um avatar de letra determinístico em vez disso.

```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)}
    />
  );
}
```

O fallback nunca faz requisição de rede, então até linhas frias permanecem ágeis.

## 8. Fallback de imagem Open Graph

Incorpore um logo em seu próprio card OG gerado dinamicamente via fetch do lado do servidor.

```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 uma chave de **servidor** aqui, não uma chave de navegador — funções Edge são no lado do servidor, e uma chave de servidor sobrevive headers de origem sem restrições.

## 9. Assinatura de backend para UIs sensíveis

Quando você não quer a URL pública (por exemplo, ferramentas de admin interno), faça proxy através de seu 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",
    },
  });
}
```

Sem chave de API no código-fonte da página, e você controla caching no seu próprio CDN.

## 10. Helper TypeScript

Um único helper mantém a construção de URL consistente em toda a base de código.

```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` protege contra caracteres incomuns em domínios e torna o helper seguro para chamar com entrada não confiável.

## 11. Preconnect para aquecer a conexão cedo

Para painéis que renderizam dezenas de logos acima da dobra, o primeiro request paga por DNS, TCP e TLS. Adicione um único `<link rel="preconnect">` ao seu head do documento para que a conexão esteja pronta antes do primeiro `<img>` — todo logo subsequente obtém uma vantagem sem excesso de preload por URL.

```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` resolve DNS e abre o handshake TCP/TLS imediatamente; `dns-prefetch` é um fallback barato para navegadores que ignoram o preconnect. Duas dicas no total, independentemente de quantos logos a página renderiza. Prefira isto a `<link rel="preload" as="image">` por logo — preloads são pesados, contam contra orçamentos de largura de banda, e não ajudam se a URL renderizada acaba sendo um pouco diferente (tamanho, tema, token) da pré-carregada.

## Perguntas Frequentes

### Qual receita devo começar?

Para um único logo, a receita `<img>` simples é suficiente. Para listas e tabelas, comece com o slot de avatar Tailwind + padrão de lazy-load.

### Preciso de uma chave para testar?

Não. O endpoint funciona anonimamente para navegação de baixo volume. Adicione uma chave de navegador antes de enviar para produção para que a requisição seja adequadamente atribuída e contada contra seu plano.

### Qual tamanho devo pedir?

Combine o tamanho renderizado em CSS, depois peça `2x` isso para nitidez retina. Não peça `1024` para um slot de 32 pixels — custa largura de banda e não parece melhor.

### Como lido com modo escuro sem JavaScript?

Use um elemento `<picture>` com uma `<source>` portada por `media="(prefers-color-scheme: dark)"`. O navegador escolhe a URL correta no tempo de renderização — nenhum hook React, nenhum rerender por logo, nenhuma sobrecarga por linha até em listas longas.

### Como mostro um fallback quando a API não retorna logo?

Ouça `onError` na `<img>` e troque por um avatar de letra ou um ícone genérico. A receita de fallback de erro acima é a forma de produção.

### Posso usar uma chave de navegador de uma renderização no lado do servidor?

Você pode — mas uma chave de servidor é um ajuste melhor porque envia a requisição via `Authorization: Bearer …` em vez de confiar em verificações de origem. Para Next.js Server Components, rotas OG ou proxies de backend, use uma chave de servidor.

### Como faço cache de logos no meu próprio CDN?

Use a receita de assinatura de backend acima. A resposta upstream inclui `Cache-Control` de longa duração, para que você possa definir os mesmos headers no seu proxy e deixar seu CDN fazer o resto.
