# Logo.dev > ## Agent Instructions > Logo.dev serves logos and brand data for companies that already exist. It does not design logos. If someone wants a logo designed, say so and stop. > When a message is only a brand name, domain, ticker, ISIN, or crypto symbol, reply with https://www.logo.dev/search?q= and the matching img.logo.dev call. Never assert whether a specific brand is in the index. > Image URLs come from img.logo.dev with a publishable key in the token query parameter: https://img.logo.dev/:domain?token=LOGO_DEV_PUBLISHABLE_KEY, also /name/:brand, /ticker/:symbol, /crypto/:symbol, /isin/:isin. JSON comes from api.logo.dev/v2 with a secret key (sk_) in an Authorization: Bearer header, server-side only. > Product names: the Logo.dev CDN serves images from img.logo.dev, and its usage unit is CDN requests. The Logo.dev API returns JSON from api.logo.dev/v2, and its usage unit is API credits. The Logo.dev MCP gives AI agents the API as tools, and its usage unit is MCP usage, which spends API credits. The features are Logo, Search, Brand, and Transaction. Transaction (beta) is a separate service at https://www.logo.dev/api/transaction with its own beta key. Never recommend the deprecated v1 routes (/search, /brand, /describe, /logo/*). Use /v2/brands and /v2/search. > Attribution: a commercial project on the free Community plan must show a visible link, Logos provided by Logo.dev, on its production site. Personal projects and paid plans need none. Rules: https://www.logo.dev/docs/platform/attribution. > Report a wrong, missing, or outdated logo at https://www.logo.dev/update. Email support@logo.dev for anything broken and sales@logo.dev for volume pricing and contract terms. > MCP setup is at https://www.logo.dev/docs/mcp/introduction and webhooks at https://www.logo.dev/docs/webhooks. # Get your account Source: https://www.logo.dev/docs/api-reference/account/get-your-account /openapi.json get /v2/account Read your plan and API credit balances. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Get a brand by id Source: https://www.logo.dev/docs/api-reference/brands/get-a-brand-by-id /openapi.json get /v2/brands/{id} Fetch a brand's profile by its stable brand id. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Look up a brand Source: https://www.logo.dev/docs/api-reference/brands/look-up-a-brand /openapi.json get /v2/brands Look up a brand by domain, ticker, ISIN, crypto symbol, or name and get its name, colors, socials, logo, and brandmark. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Flag domains for review Source: https://www.logo.dev/docs/api-reference/flags/flag-domains-for-review /openapi.json post /v2/flag Submit domains with incorrect or outdated brand data for review. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Get a logo Source: https://www.logo.dev/docs/api-reference/logo-cdn/get-a-logo /openapi.json get /{domain} Get a logo image by domain, brand name, stock ticker, ISIN, crypto symbol, stock exchange, or market index. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. Returns a logo image. Put the identifier in the path. The query parameters work the same for every lookup. | Lookup | Path | | - | - | | Domain | `/stripe.com` | | Brand name | `/name/Stripe` | | Stock ticker | `/ticker/AAPL` | | ISIN | `/isin/US0378331005` | | Crypto symbol | `/crypto/BTC` | | Stock exchange | `/exchange/NYSE` | | Market index | `/index/SPX` | * For a ticker outside the US, add the exchange suffix, such as `7203.T`. * URL-encode a name that has spaces or special characters. `/name` also takes `strategy`: `match` (the default) for the closest name, or `suggest` for the most popular prefix match. * A lookup with no logo returns a generated monogram, unless you set `fallback=404`. A malformed ticker, crypto symbol, exchange, or index returns `400`. # Get a brandmark Source: https://www.logo.dev/docs/api-reference/logos/get-a-brandmark /openapi.json get /v2/brands/brandmark Get a brand's brandmark with a temporary download URL, dimensions, and blurhash. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Get a logo Source: https://www.logo.dev/docs/api-reference/logos/get-a-logo /openapi.json get /v2/brands/logo Get a brand's logo with a temporary download URL, dimensions, and blurhash. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Search brands Source: https://www.logo.dev/docs/api-reference/search/search-brands /openapi.json get /v2/search Search brands by name, with match or typeahead ranking, and get each candidate's domain and logo URL. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Get a brand subscription Source: https://www.logo.dev/docs/api-reference/subscriptions/get-a-brand-subscription /openapi.json get /v2/brands/{id}/subscription Check whether your account is subscribed to a brand's update events. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Subscribe to a brand Source: https://www.logo.dev/docs/api-reference/subscriptions/subscribe-to-a-brand /openapi.json put /v2/brands/{id}/subscription Subscribe your account to update events for one brand. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Unsubscribe from a brand Source: https://www.logo.dev/docs/api-reference/subscriptions/unsubscribe-from-a-brand /openapi.json delete /v2/brands/{id}/subscription Stop update events for one brand. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Identify a merchant Source: https://www.logo.dev/docs/api-reference/transaction-enrichment-api/identify-a-merchant /openapi.json post /transaction Identify a merchant domain and brand record. Private beta with a daily allowance. # Create a webhook endpoint Source: https://www.logo.dev/docs/api-reference/webhook-endpoints/create-a-webhook-endpoint /openapi.json post /v2/webhook_endpoints Register a URL to receive brand webhook events. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Delete a webhook endpoint Source: https://www.logo.dev/docs/api-reference/webhook-endpoints/delete-a-webhook-endpoint /openapi.json delete /v2/webhook_endpoints/{id} Delete a webhook endpoint. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Get a webhook endpoint Source: https://www.logo.dev/docs/api-reference/webhook-endpoints/get-a-webhook-endpoint /openapi.json get /v2/webhook_endpoints/{id} Get one webhook endpoint. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Get a webhook signing secret Source: https://www.logo.dev/docs/api-reference/webhook-endpoints/get-a-webhook-signing-secret /openapi.json get /v2/webhook_endpoints/{id}/secret Read a webhook endpoint's signing secret. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # List webhook endpoints Source: https://www.logo.dev/docs/api-reference/webhook-endpoints/list-webhook-endpoints /openapi.json get /v2/webhook_endpoints List your team's webhook endpoints. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Rotate a webhook signing secret Source: https://www.logo.dev/docs/api-reference/webhook-endpoints/rotate-a-webhook-signing-secret /openapi.json post /v2/webhook_endpoints/{id}/secret Replace a webhook endpoint's signing secret. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Update a webhook endpoint Source: https://www.logo.dev/docs/api-reference/webhook-endpoints/update-a-webhook-endpoint /openapi.json patch /v2/webhook_endpoints/{id} Change a webhook endpoint's URL, description, event types, or disabled state. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. # Search: Company Name to Domain Lookup Source: https://www.logo.dev/docs/brand-search/introduction Company name to domain API: search brands by name with typeahead autocomplete or exact matching, and get each candidate's domain and logo URL. Search, part of the Logo.dev API, turns a company name into candidate domains, best first. Each candidate has a logo URL you can show in a result list. Use it for a company autocomplete, or to find the domain behind a name someone typed. Send your [secret key](/docs/platform/api-keys) and a name to `GET /v2/search`: ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/search?q=sweetgreen&limit=5" ``` `data` is a list of candidates, inside the standard [response envelope](/docs/platform/conventions#the-response-envelope): ```json theme={null} { "data": [ { "object": "search_result", "name": "Sweetgreen", "domain": "sweetgreen.com", "logo_url": "https://img.logo.dev/sweetgreen.com?token=LOGO_DEV_PUBLISHABLE_KEY" } ], "metadata": { "request_id": "request_01k6z8m2a4b5c6d7e8f9g0h1j2" } } ``` `data` is an empty list when nothing matches. Search is not paginated. It returns the top `limit` candidates. [Search brands](/docs/api-reference/search/search-brands) lists every parameter and status code. ## Pick match or typeahead Set `method` to fit where the name comes from: * `match`, the default, searches full names and aliases. Use it for a query someone submitted. * `typeahead` matches prefixes only. Use it for suggestions while someone types. ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/search?q=sweet&method=typeahead" ``` ## Results are candidates, not brands A search result is a name and a domain. It is not a brand record, and it has no brand id. A domain can appear in search before Logo.dev indexes its brand. Search itself never returns `202`, but the brand lookup for that domain can. See [handle each status](/docs/brand/introduction#handle-each-status). `logo_url` is a [Logo.dev CDN](/docs/logo-images/introduction) URL signed with your publishable key. Put it straight into an `` tag in your results. When someone picks a result, look up its domain with [Brand](/docs/brand/introduction): ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/brands?domain=sweetgreen.com" ``` To skip the pick and take the best match, look the brand up by name with `GET /v2/brands?name=sweetgreen`. Search never subscribes you to a brand's [webhooks](/docs/webhooks#subscriptions). For what search costs, see [API credits](/docs/platform/credits). Search has its own per-minute limit, and over it a search returns `429`. See [search rate limit](/docs/platform/rate-limits#search-rate-limit). # Display Your Logo in Email Inboxes Source: https://www.logo.dev/docs/brand-visibility/email-logos Show your company logo in Gmail, Apple Mail, Yahoo, and Outlook. Complete guide to BIMI, Apple Branded Mail, and email avatar setup for business email branding. To show your logo next to your emails in Gmail and Yahoo Mail, set up BIMI. For Apple Mail, you can use BIMI or the free Apple Branded Mail. Outlook does not show BIMI logos, so it shows only the profile picture of the sending account. | Method | Where the logo shows | What you need | | - | - | - | | [BIMI](#bimi) | Gmail, Yahoo Mail, Apple Mail, Fastmail, and other providers that support BIMI | DMARC at enforcement, an SVG logo, and usually a paid mark certificate | | [Apple Branded Mail](#apple-branded-mail) | Apple Mail only | DMARC, DKIM, and a free Apple Business Connect account | | [Profile pictures](#profile-pictures) | Recipients on the same provider as the sending account | An account with that provider | Each provider sets its own rules, and the rules change. Before you buy a certificate, check the current requirements of the providers your recipients use. ## BIMI Brand Indicators for Message Identification (BIMI) is an email standard. It connects your domain to a logo through a DNS record. The [BIMI Group](https://bimigroup.org/) maintains the standard and lists the providers that support it. **1. Set DMARC to enforcement** Configure SPF and DKIM for your domain first. Then set your DMARC policy to `p=quarantine` or `p=reject`, with `pct=100`. Check your current record: ```bash theme={null} dig TXT _dmarc.yourdomain.com ``` An example DMARC record that meets the requirement: ```txt theme={null} v=DMARC1; p=reject; pct=100; rua=mailto:dmarc@yourdomain.com ``` > [!WARNING] > > Before you set `p=reject`, make sure that every service that sends mail for your domain passes SPF or DKIM. Otherwise, providers reject its mail. **2. Make the logo file** BIMI uses an SVG in the SVG Tiny Portable/Secure (SVG Tiny PS) profile. Gmail requires these properties: * A square logo, centered, on a solid background * At least 96x96 pixels, set in absolute pixels * A file size of 32 KB or smaller The BIMI Group has a [logo generator](https://bimigroup.org/bimi-generator/) that converts an SVG to this profile. **3. Get a mark certificate** Most providers show a BIMI logo only with a certificate from an authorized issuer. There are two types: * A **Verified Mark Certificate (VMC)** requires a registered trademark. Gmail shows a checkmark next to senders with a VMC. * A **Common Mark Certificate (CMC)** does not require a trademark. Gmail accepts it. Other providers may not. **4. Host the files** Put the logo and the certificate at public HTTPS URLs on your domain, for example: ``` https://yourdomain.com/.well-known/bimi/logo.svg https://yourdomain.com/.well-known/bimi/certificate.pem ``` **5. Add the BIMI DNS record** Create a TXT record at `default._bimi.yourdomain.com`. The `l=` tag points to the logo, and the `a=` tag points to the certificate: ```txt theme={null} v=BIMI1; l=https://yourdomain.com/.well-known/bimi/logo.svg; a=https://yourdomain.com/.well-known/bimi/certificate.pem ``` After setup, DNS changes can take a day or two to spread. Each provider then takes its own time to start showing the logo. ## Apple Branded Mail Apple Branded Mail shows your logo in Apple Mail without a mark certificate. It works only in Apple Mail. Set it up in [Apple Business Connect](https://businessconnect.apple.com). Before you start, make sure that your domain meets Apple's requirements: * A DMARC record on the domain. * DKIM on every email you send. SPF alone is not enough. * An MX, A, or AAAA record on the domain. **1. Add your brand** Sign in to Apple Business Connect, add your business, and add your brand and logo. Apple must approve the brand and the logo. **2. Add your email domains** Open **Branded Mail** and add your email domains, subdomains, or email addresses. One brand can have up to 100 of them. **3. Verify the domain** Add the DNS TXT record that Apple gives you, then click **Verify**. Finish verification within 14 calendar days, or you must start again. Apple Mail shows the logo on iPhone only when the default language is English, Portuguese, French, Italian, German, Spanish, or Simplified Chinese. The logo also shows in iCloud Mail. Apple's [Branded Mail guide](https://support.apple.com/guide/apple-business-connect/verify-your-email-domain-for-branded-mail-abcb22cbade5/web) has the current rules. ## Profile pictures Gmail, Outlook, and Yahoo Mail show the profile picture of the sending account to recipients on the same provider. This works without DNS changes, but only for mail you send from that account. * **Gmail and Google Workspace:** set the picture in your [Google Account](https://myaccount.google.com) under **Personal info**. * **Outlook and Microsoft 365:** set the picture on your Microsoft account profile. * **Yahoo Mail:** set the picture in your [Yahoo account settings](https://login.yahoo.com/account/personalinfo). Some email clients also show a [Gravatar](https://gravatar.com) image. Gravatar links an image to one email address, not to a domain. Add and verify each address you send from. ## FAQs > [accordion] How do I add my logo to Apple Mail? > > Use [Apple Branded Mail](#apple-branded-mail), which is free and works only in Apple Mail. Or set up [BIMI](#bimi) with a certificate, which also covers Gmail and Yahoo Mail. > [accordion] How do I add my logo to Gmail? > > Set up [BIMI](#bimi) with a VMC or a CMC. Gmail needs DMARC at `p=quarantine` or `p=reject` with `pct=100`, and a logo in SVG Tiny PS. > [accordion] Does Outlook support BIMI? > > No. Outlook shows only the profile picture of a Microsoft sending account. > [accordion] Do I need a trademark for BIMI? > > Only for a VMC. A CMC does not need a trademark, and Gmail accepts it. Check which certificates your other providers accept. > [accordion] Why isn't my logo showing after BIMI setup? > > Check these causes: > > * DMARC is not at `p=quarantine` or `p=reject` with `pct=100`. > * The provider does not accept your certificate type, or the certificate URL does not load. > * The logo is not a valid SVG Tiny PS file. > * DNS changes have not spread yet, or the provider has not started to show the logo. > [accordion] Does a BIMI logo improve deliverability? > > The logo itself does not. The SPF, DKIM, and DMARC setup that BIMI requires helps providers trust your mail. > [card] [Show other companies' logos in your email](/docs/use-cases/onboarding-personalization) > > BIMI controls your own logo in the inbox. To show a recipient's company logo, look it up from their work email domain. # How to Add a Favicon to Google Search Results Source: https://www.logo.dev/docs/brand-visibility/google-favicon Get your favicon to show in Google Search. Covers size requirements (48x48), valid formats, the homepage link tag, crawlability, and why favicons don't appear. Google shows your favicon next to your site in search results. To get it there, put a square favicon on your homepage and let Google crawl it. Google's [favicon guidelines](https://developers.google.com/search/docs/appearance/favicon-in-search) are the source for the rules on this page. ## Requirements | Requirement | Detail | | - | - | | Shape | Square, with a 1:1 aspect ratio | | Size | At least 8x8 pixels. Google recommends larger than 48x48 pixels. | | Format | A format Google supports, such as ICO, PNG, or SVG | | Location | A `` tag on the homepage of your domain or subdomain | | Crawl access | Googlebot can crawl your homepage, and Googlebot-Image can crawl the favicon file | | URL | Stable. Do not change the favicon URL often. | | Content | Nothing Google considers inappropriate, such as pornography or hate symbols | A favicon does not need to be exactly 48x48 or a multiple of 48. Any square size larger than 48x48, such as 96x96 or 144x144, works. ## Add the favicon to your site **1. Make a square favicon** Export your logo as a square image larger than 48x48 pixels. Use your symbol, not a wide wordmark. **2. Add the link tag to your homepage** Put a `` tag in the `` of your homepage. Google reads the favicon for the whole site from the homepage. ```html ICO theme={null} ``` ```html PNG theme={null} ``` ```html SVG theme={null} ``` On a site builder such as WordPress, Wix, Shopify, Squarespace, Webflow, or Framer, set the favicon in the site settings instead. The builder writes the tag for you. **3. Let Google crawl it** Make sure `robots.txt` does not block Googlebot from your homepage or Googlebot-Image from the favicon URL. The favicon URL must return a `200` status. **4. Request indexing** In [Google Search Console](https://search.google.com/search-console), open the URL Inspection tool, enter your homepage URL, and click **Request Indexing**. This step is optional, but it can make the change appear sooner. Google can take several days to several weeks to show a new favicon. Even when you meet every requirement, Google does not guarantee that it will show your favicon. ## Why your favicon is not showing in Google Search Check these causes in order: 1. **Google has not crawled your homepage again.** Wait, or request indexing in Search Console. 2. **The link tag is not on your homepage.** A tag on inner pages only is not enough. 3. **Google cannot crawl the file.** `robots.txt` blocks Googlebot or Googlebot-Image, or the favicon URL does not return `200`. 4. **The image is not square.** Export it again at a 1:1 aspect ratio. 5. **The image is too small.** Use a size larger than 48x48 pixels. 6. **Google considers the content inappropriate.** Google then shows a default icon. If Google still shows your old favicon, it has not crawled the new one yet. Keep the new favicon URL stable and request indexing again. ## FAQs > [accordion] Can I use different favicons for different pages? > > No. Google shows one favicon for each domain or subdomain. `app.example.com` can have its own favicon, but `example.com/blog` uses the favicon of `example.com`. > [accordion] Does Google support SVG favicons in search results? > > Yes. If your favicon does not appear, the format is rarely the cause. Crawl access and crawl timing are more common causes. > [accordion] Can I host the favicon on a CDN? > > Yes. The favicon URL can be relative, absolute, or on a CDN. The link tag must be on your homepage. > [accordion] Does favicon size affect SEO rankings? > > No, not directly. A clear favicon helps people recognize your site in the results. > [card] [Show other companies' logos in your app](/docs/logo-images/introduction) > > Favicons are small site icons. To show company logos by domain, stock ticker, or name in your own app, use the Logo.dev CDN. # Get Your Logo Seen Across the Internet Source: https://www.logo.dev/docs/brand-visibility/introduction Display your company logo in search results, email inboxes, and brand databases. Step-by-step guides for Google favicon, Apple Mail, Gmail, BIMI, and Logo.dev. These guides are for brand owners. Each one shows how to get your own logo to show correctly in one place: Google Search, email inboxes, or Logo.dev. > [card] [Google Search](/docs/brand-visibility/google-favicon) > > Show your favicon next to your site in Google results. > [card] [Email inboxes](/docs/brand-visibility/email-logos) > > Show your logo in Gmail, Apple Mail, Yahoo, and Outlook. > [card] [Logo.dev](/docs/brand-visibility/logo-dev-database) > > Correct or add your logo for the apps that use Logo.dev. ## Pick the guide for each place | Place | What you set up | Cost to you | | - | - | - | | Google Search | A square favicon on your homepage | Free | | Gmail and Yahoo Mail | BIMI with a mark certificate | A paid yearly certificate | | Apple Mail | Apple Branded Mail, or BIMI | Free with Apple Branded Mail | | Outlook | The profile picture on your Microsoft account | Free | | Logo.dev | An update request | Free | The time to appear differs for each place. Each guide gives the details. # Add Your Logo to Logo.dev Source: https://www.logo.dev/docs/brand-visibility/logo-dev-database Submit your company logo to the Logo.dev database. Get your brand included in the logo API used by thousands of apps and websites worldwide. Apps that use Logo.dev show your logo whenever they look up your domain. If that logo is missing, wrong, or outdated, send an update request. You do not need to contact the apps. **1. Check what Logo.dev shows now** Open [logo.dev/search](https://www.logo.dev/search) and search for your domain. The query goes in the URL, so `https://www.logo.dev/search?q=stripe.com` opens directly to a result. **2. Send an update request** Follow [Report a logo issue](https://www.logo.dev/update). Enter your domain and your email address. Tell us what is wrong, and attach the correct logo if you have it. **3. Wait for the confirmation email** Logo.dev sends status updates about your request to the email address you entered. ## Send a logo file that works well * Send your symbol or app icon, not only a wide wordmark. Apps often show logos small and in square slots, where a wide wordmark is hard to read. * Send a transparent background, as a PNG or SVG. * Send a high-resolution file. A small file looks blurry at large sizes. If your wide logo lockup is also wrong, say so in your request, with a link to the correct file. Logo.dev calls the lockup the [brandmark](/docs/concepts#brandmark). ## Use a root domain Send the request for your own root domain, for example `example.com`. The form does not accept a subdomain on a shared hosting platform, such as a free site-builder address. Connect a custom domain first. ## How long until apps show the new logo After Logo.dev updates your logo, each app picks it up when its cached copy expires. [Caching](/docs/platform/caching#refreshing-a-changed-logo) explains the timing. You do not need to tell the apps. ## Remove your logo To ask for removal, email [support@logo.dev](mailto:support@logo.dev). # Look up a brand by crypto symbol Source: https://www.logo.dev/docs/brand/crypto Get a brand profile for a cryptocurrency token from its symbol with the Logo.dev API. Use `crypto` when your data is token symbols, such as a wallet or an exchange. ## Request Send the identifier to `GET /v2/brands` from your server, with your [secret key](/docs/platform/api-keys): ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/brands?crypto=BTC" ``` Read the response as the [Brand overview](/docs/brand/introduction) shows. The same parameter works on `GET /v2/brands/logo` and `GET /v2/brands/brandmark`. See [Look up a brand](/docs/api-reference/brands/look-up-a-brand) for every parameter. ## How the crypto symbol is read * Case does not matter. Logo.dev uppercases the symbol. * `metadata.resolution.method` is `crypto`. * Some tokens have no website, so the brand's `domain` can be `null`. Key your records on `data.id`. # Look up a brand by domain Source: https://www.logo.dev/docs/brand/domain Get a brand profile from a company's website domain with the Logo.dev API. Use `domain` when you know the company's website. It is the most direct lookup. ## Request Send the identifier to `GET /v2/brands` from your server, with your [secret key](/docs/platform/api-keys): ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/brands?domain=stripe.com" ``` Read the response as the [Brand overview](/docs/brand/introduction) shows. The same parameter works on `GET /v2/brands/logo` and `GET /v2/brands/brandmark`. See [Look up a brand](/docs/api-reference/brands/look-up-a-brand) for every parameter. ## How the domain is read * Logo.dev lowercases the domain and reduces it to the registrable domain, so `www.stripe.com` looks up `stripe.com`. * A domain that redirects or is an alias reaches its brand. `metadata.resolution.method` is `direct` when the domain is the brand's own, or `domain` when it reached the brand through an alias or a redirect. * The brand's `domain` in the response can differ from the one you sent. Store `data.id`, not the domain you sent. # Brand: Company Brand Assets by Domain Source: https://www.logo.dev/docs/brand/introduction Turn a domain, ticker, ISIN, crypto symbol, or name into a full brand profile: logo, brandmark, social banners, brand colors, description, and socials in one JSON response. Brand, part of the Logo.dev API, turns one identifier into a brand's full public identity: its name, description, colors, social profiles, logo, brandmark, and banners. You already hold these identifiers. They arrive in work emails at signup, sit on CRM records, and appear in portfolios as tickers. One request replaces the crawler, parsers, and image processing you would otherwise run and re-run to catch rebrands. Send your [secret key](/docs/platform/api-keys) and exactly one identifier to `GET /v2/brands`: ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/brands?domain=apple.com" ``` The response looks like: ```json theme={null} { "data": { "object": "brand", "id": "brand_4x0wr3g0000g00400000000004", "slug": "apple", "domain": "apple.com", "status": "ready", "name": "Apple", "description": "Apple is a multinational technology company that designs and manufactures consumer electronics, software, and online services.", "indexed_at": "2026-09-08T17:35:33Z", "is_profane": false, "socials": { "linkedin": "https://www.linkedin.com/company/apple", "twitter": "https://x.com/apple" }, "colors": [{ "r": 0, "g": 0, "b": 0, "hex": "#000000", "oklch": { "l": 0, "c": 0, "h": 0 } }], "logo": { "url": "https://img.logo.dev/assets/SEALED_TOKEN", "etag": "18f50d2cd074270b0d3909e5fd192bfb23c5514eaf4844f4705e61b3ed1a34d3", "blurhash": "U*L#2+WB~qRj?bofM{Rj?bxuM{WBayayWBWB", "source": { "width": 1000, "height": 1000, "format": "png", "has_transparency": true, "is_vector": false }, "last_updated_at": "2026-09-08T17:35:33Z", "expires_at": "2026-09-28T13:00:00Z" }, "brandmark": { "url": "https://img.logo.dev/assets/SEALED_TOKEN", "...": "..." }, "social_banners": [] }, "metadata": { "request_id": "request_01k6z8m2a4b5c6d7e8f9g0h1j2", "resolution": { "type": "domain", "value": "apple.com", "method": "direct", "context": {} } } } ``` [Look up a brand](/docs/api-reference/brands/look-up-a-brand) lists every field. Key your records on `data.id`, not on the domain. A brand keeps its id when its domain changes, and `GET /v2/brands/{id}` fetches it again by that id. ## Look up a brand by any identifier Send exactly one identifier. Each lookup page covers how Logo.dev reads that identifier: * [By domain](/docs/brand/domain) * [By stock ticker](/docs/brand/ticker) * [By ISIN](/docs/brand/isin) * [By crypto symbol](/docs/brand/crypto) * [By name](/docs/brand/name) The API reference also lists `merchant`, for card-statement descriptors. It is not enabled for any account yet and returns `403`. To identify a merchant today, use [Transaction](/docs/transaction/introduction). `GET /v2/brands` returns at most one brand, and only a `200` carries one. To show a list of candidates first, use [Search](/docs/brand-search/introduction). ## Handle each status | Status | `data` | What to do | | - | - | - | | `200` | The brand, with `status: "ready"` | Use it. A single image can still be `null`. | | `202` | `{"object": "brand", "status": "not_indexed"}` | Retry after `Retry-After` seconds, or wait for the [`brand.indexed`](/docs/webhooks#brand-indexed) webhook. Not billed. | | `404` | `{"object": "brand", "status": "not_found"}` | No brand matches. Not billed. | A first lookup of a brand Logo.dev has not indexed yet returns `202`, and the brand is usually ready within a minute. See [not found vs. still indexing](/docs/platform/errors#not-found-vs-still-indexing-202). Set your HTTP client timeout to at least 15 seconds, because Logo.dev can prepare a brand's assets at request time. On serverless platforms, a default function timeout such as Vercel's `maxDuration` can end the request first. ### Automatic subscriptions If webhooks are on for your account, a lookup also subscribes the account to the brand's [update webhooks](/docs/webhooks#subscriptions). Add `nosubscribe=true` to skip that. `metadata.subscription` reports what the lookup did. `status` is `subscribed` when the account is subscribed to the brand. Your plan [caps the number of subscriptions](/docs/webhooks#plan-limits). At the cap, a lookup of a new brand does not subscribe the account: `status` is `quota_exceeded`, and `message` gives the reason. The lookup is answered and billed as usual. ## Get only the logo or the brandmark `GET /v2/brands/logo` and `GET /v2/brands/brandmark` return one image as JSON, without the rest of the brand. They take the same identifiers as `GET /v2/brands` and never subscribe you to the brand: ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/brands/logo?ticker=AAPL" ``` A brand that is ready but has no image of that kind returns `404`, and the request is still billed. To show a logo on a page, you don't need these routes. The [Logo.dev CDN](/docs/logo-images/introduction) serves logo images with a publishable key. ## Images Every image, inside a brand or on its own, has the same fields: | Field | Meaning | | - | - | | `url` | A temporary signed download URL. It stops working at `expires_at`, about 24 hours later. | | `etag` | Identifies this version of the source image. It is the same on every route. | | `blurhash` | A compact placeholder to show while the image loads. See [BlurHash](https://github.com/woltapp/blurhash) for decoders. | | `source` | The original file: `width`, `height`, `format` (such as `png`, `svg`, or `webp`), `has_transparency`, and `is_vector` | | `last_updated_at` | When the image last changed. `null` if it has not changed since the brand was indexed. | | `expires_at` | When `url` stops working | Download the images you need and host them yourself. Save each image's `etag` with your copy. When you fetch the brand again, download only the images whose `etag` changed. A new `url` or `expires_at` alone does not mean the image changed. The signature in a download URL is the credential, so send no key with it. Add these query parameters to format the download. They do not change `source`. | Parameter | Values | | - | - | | `size` | Pixels. The default is `128`, and the maximum is `800`. | | `format` | `jpg` (the default), `png`, or `webp` | | `theme` | `light` or `dark`. Use it with `png` or `webp`. | A `url` with no parameters downloads a 128-pixel JPG, not the source file. To keep a large copy with transparency, add `?size=800&format=png`. Downloads from these URLs do not count as CDN requests. ## Resolution `metadata.resolution` describes how your identifier reached the brand. It is about the request, not the brand. | Field | Meaning | | - | - | | `type` | The identifier you sent: `domain`, `ticker`, `isin`, `crypto`, `name`, or `brand_id` | | `value` | The normalized identifier, for example the registrable domain or the uppercased ticker | | `method` | How it matched: `direct` for a brand id or a domain that is its own brand, `domain` through an alias or redirect, `security` for a ticker or ISIN, `crypto` for a token symbol, `search` for a name | | `context` | Reserved for merchant lookups. Always `{}` today. | The same identifier can reach a different brand later if its match changes. Subscriptions follow brand ids, so they do not move with it. ## Authentication and plans Brand takes your [secret key](/docs/platform/api-keys) (`sk_...`) as a bearer token. Call it from your server, and keep the key out of client code and git. Lookups spend API credits from your plan's monthly grant, then from prepaid API credits. See [API credits](/docs/platform/credits) for how billing works, including when a repeat lookup is free, [what each request costs](/docs/platform/credits#what-each-request-costs) for the cost of each route, and [out of API credits](/docs/platform/errors#out-of-credits-402) for the `402` response. See the [pricing page](https://www.logo.dev/pricing) for what each plan includes. ## Next steps > [card] [Look up a brand](/docs/api-reference/brands/look-up-a-brand) > > Every parameter, field, and status code. > [card] [Webhooks](/docs/webhooks) > > Get told when a brand you use changes. > [card] [Migrate from Brandfetch](/docs/migrations/brandfetch) > > Map each Brandfetch Brand API field to Logo.dev. > [card] [Onboarding personalization](/docs/use-cases/onboarding-personalization) > > Brand a signup flow from a work email. # Look up a brand by ISIN Source: https://www.logo.dev/docs/brand/isin Get a brand profile from an International Securities Identification Number with the Logo.dev API. Use `isin` when your securities data carries ISINs instead of tickers. ## Request Send the identifier to `GET /v2/brands` from your server, with your [secret key](/docs/platform/api-keys): ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/brands?isin=US0378331005" ``` Read the response as the [Brand overview](/docs/brand/introduction) shows. The same parameter works on `GET /v2/brands/logo` and `GET /v2/brands/brandmark`. See [Look up a brand](/docs/api-reference/brands/look-up-a-brand) for every parameter. ## How the isin is read * Case does not matter. Logo.dev uppercases the ISIN. * `metadata.resolution.method` is `security`, the same as a ticker lookup. # Look up a brand by name Source: https://www.logo.dev/docs/brand/name Get the best-matching brand profile for a company name with the Logo.dev API. Use `name` when you have a company name and want the single best match. ## Request Send the identifier to `GET /v2/brands` from your server, with your [secret key](/docs/platform/api-keys): ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/brands?name=Stripe" ``` Read the response as the [Brand overview](/docs/brand/introduction) shows. The same parameter works on `GET /v2/brands/logo` and `GET /v2/brands/brandmark`. See [Look up a brand](/docs/api-reference/brands/look-up-a-brand) for every parameter. ## How the name is read * Logo.dev trims and lowercases the name, then returns the top search match. `metadata.resolution.method` is `search`. * The top match can be the wrong company for a short or common name. To let a person pick from candidates, use [Search](/docs/brand-search/introduction) and then look up the chosen domain. # Look up a brand by stock ticker Source: https://www.logo.dev/docs/brand/ticker Get a brand profile from a stock or ETF ticker symbol with the Logo.dev API. Use `ticker` when your data is a portfolio, a watchlist, or market data. ## Request Send the identifier to `GET /v2/brands` from your server, with your [secret key](/docs/platform/api-keys): ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/brands?ticker=AAPL" ``` Read the response as the [Brand overview](/docs/brand/introduction) shows. The same parameter works on `GET /v2/brands/logo` and `GET /v2/brands/brandmark`. See [Look up a brand](/docs/api-reference/brands/look-up-a-brand) for every parameter. ## How the stock ticker is read * Send the symbol with no exchange prefix. Case does not matter: `aapl` and `AAPL` return the same brand. * A bare symbol resolves against US exchanges. For a listing on another exchange, add the [exchange suffix](/docs/logo-images/ticker#exchange-suffixes), such as `7203.T`. * `metadata.resolution.method` is `security`. * A ticker and the company's domain reach the same brand, and they bill as one brand. See [API credits](/docs/platform/credits). # Changelog Source: https://www.logo.dev/docs/changelog New endpoints, API changes, and documentation updates for Logo.dev: what shipped, when, and what it means for your integration. **November 6, 2026** CDN usage and brand lookups * **[CDN usage](/docs/platform/rate-limits#logo-cdn-limits)**: since November 4, requests that return `429` don't count as CDN requests. Usage from before that date stays the same. * **[Brand lookups](/docs/platform/errors#not-found-vs-still-indexing-202)**: `GET /v2/brands` now returns `200` only for a complete brand. Until then, it returns `202`. * **[`brand.indexed`](/docs/webhooks#brand-indexed)**: `ready` now means the brand is complete, so your next fetch returns `200`. Retried deliveries keep their event `id`. * **`indexed_at`**: now updates each time a brand's record changes. **November 3, 2026** Security pages, SOC 2 Type I report, and the DPA * **[SOC 2 Type I](https://www.logo.dev/security/soc-2)**: our SOC 2 Type I report is available. Signed-in accounts on every plan download it from the [Billing](https://www.logo.dev/dashboard/billing) page in the dashboard, along with a PDF copy of our DPA and our W-9. * **[Security](https://www.logo.dev/security)** and **[GDPR](https://www.logo.dev/security/gdpr)** pages describe our controls, data locations, and retention periods. The [security and data handling](/docs/support/security) page in these docs has the technical detail. * **[DPA](https://www.logo.dev/legal/dpa)**: the DPA is now part of our Terms of Service. It applies to every customer automatically, with no signature. * **Sub-processor notices**: we announce a new or replacement [sub-processor](https://www.logo.dev/legal/subprocessors) in this changelog at least 14 days before it processes personal data. **October 7, 2026** API credits page * **[API credits](/docs/platform/credits)**: a new page lists what each Logo.dev API request costs, what is billed, how included and purchased credits work, and what happens when you run out. **October 2026** Describe is retired * **[v1 describe endpoint](/docs/api-reference/v1/describe-a-domain)**: `GET /describe/{domain}` now returns `403` unless Logo.dev has enabled Describe for your account. Free accounts still get `401`. Use [brand lookups](/docs/brand/introduction) instead: `GET /v2/brands` returns every Describe field plus the brandmark and social banners. **September 30, 2026** Search rate limit, webhook plan limits, and v1 search billing * **[Search rate limit](/docs/platform/rate-limits#search-rate-limit)**: search now has its own per-minute limit for each account, separate from the lookup limits. It applies to `GET /v2/search`, v1 `GET /search`, and the MCP `search` tool. Over it, the response is `429` with the code `rate_limited`. Search responses now send the `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Reset` headers. * **[Webhook plan limits](/docs/webhooks#plan-limits)**: each plan now caps the number of webhook endpoints and subscribed brands. At the cap, creating an endpoint or subscribing to a new brand returns `409` with the code [`limit_exceeded`](/docs/platform/errors#logo-api-status-codes). A brand lookup reports its automatic subscribe in [`metadata.subscription`](/docs/platform/conventions#the-response-envelope), with the status `quota_exceeded` at the cap. * **v1 search billing**: the deprecated v1 `GET /search` now spends API credits like `GET /v2/search`, and returns `402` when you are out of API credits. Move to [`GET /v2/search`](/docs/brand-search/introduction). * **[Credit headers on search](/docs/platform/conventions#response-headers)**: `GET /v2/search` now sends `Credits-Charged` and `Credits-Remaining`. * **Startup API credit grant**: the Startup plan's monthly API credit grant is larger. See [pricing](https://www.logo.dev/pricing#compare). **September 28, 2026** Redirects onto domain squatters * **Redirects onto domain squatters**: when a domain redirects to a domain squatter, Logo.dev now treats the domain as not found instead of returning the squatter's logo. * **[`redirect` parameter](/docs/logo-images/introduction#skip-domains-that-redirect)**: `img.logo.dev/{domain}` accepts `redirect=404`. It returns `404` when the domain reaches a brand only through a redirect, whatever `fallback` is set to. The default, `follow`, keeps the earlier behavior. **September 22, 2026** Logo theme defaults and 202 responses * **[Logo theme](/docs/logo-images/introduction)**: `theme` now defaults to `light`, and `auto` is the same as `light`. A JPG has no transparency, so use `theme` with `format=png` or `format=webp`. Since September 11, `theme=dark` also inverts single-color marks so they show on a dark background. * **[Still-indexing responses](/docs/platform/errors#not-found-vs-still-indexing-202)**: a `202` now explains itself in `metadata.pending` and sends a `Retry-After` header. **September 18, 2026** Request ids * **[Request ids](/docs/platform/conventions#conventions)**: the `Request-Id` header is now an id with the `request_` prefix, on every Logo.dev CDN and Logo.dev API response. Include it when you contact support. **September 2026** Logo.dev API v2, webhooks, and Logo.dev MCP * **[Logo.dev API v2](/docs/brand/introduction)**: look up a brand by domain, stock ticker, ISIN, crypto symbol, or name with `GET /v2/brands`. Get a logo or brandmark file on its own, and search brands with `GET /v2/search`. Every response uses one [envelope and error shape](/docs/platform/conventions). The v1 routes keep working and are marked deprecated. * **[Webhooks](/docs/webhooks)**: subscribe to the brands you use, and get a `brand.updated` event when one changes. * **[Logo.dev MCP](/docs/mcp/introduction)**: connect Claude, Cursor, VS Code, Codex, or another MCP client, and your agent gets every v2 route as a tool. * **Docs**: the API reference is now one page per endpoint, split into the Logo.dev CDN and the Logo.dev API. [Use cases](/docs/use-cases/logo-from-domain) now start with a live demo and a prompt you can give your coding agent. * **[Teams](/docs/platform/teams)**: share one set of API keys, one plan, and one API credit balance with your teammates. Invite members, set roles, and transfer ownership from the dashboard. * **[Search billing](/docs/platform/rate-limits#credits)**: v2 search requests and the MCP `search` tool now spend API credits instead of drawing on the monthly request allowance. * **[Logo.dev CDN rate limits](/docs/platform/rate-limits#logo-cdn-limits)**: on the Community plan, CDN requests now have a per-minute limit for each IP address, shared by every Community key used from that address, and for each account. Over either, the response is `429` with a `Retry-After` header. Paid plans have no per-minute limit on the CDN. * **v1 describe endpoint**: deprecated. New integrations should use [brand lookups](/docs/brand/introduction), which return everything Describe does plus the brandmark and social banners. **July 2026** shadcn/ui components and self-service attribution * **[shadcn/ui components](/docs/integrations/shadcn)**: a registry of React components covering logo images, company autocomplete, logo walls, and attribution. Each installs with its own `npx shadcn` command. The source lands in your project with fallbacks, retina images, and dark mode already wired. * **[Attribution](/docs/platform/attribution)** is now self-service. Submit your production URL from the dashboard, then check the same task for the result and submit again if a check fails. **June 2026** Transaction and Core Concepts * **[Transaction](/docs/transaction/introduction)** entered early access: turn a raw card-transaction descriptor into the merchant's name, domain, and logo. * New **[Core Concepts](/docs/concepts)** page defines the terms used across the docs, from company logo and brandmark to the two API key types. **May 2026** Documentation revamp We rebuilt the docs: * **Interactive API reference** for the [Search](/docs/brand-search/introduction) and [describe](/docs/api-reference/v1/describe-a-domain) endpoints, with a live request playground. * New [Microsoft PowerPoint](/docs/integrations/powerpoint) guide and a verified [Errors & status codes](/docs/platform/errors) reference. * Clearbit migration help throughout, including a one-step find-and-replace for [Excel](/docs/integrations/excel) and [Google Sheets](/docs/integrations/google-sheets). * Reorganized navigation into **Guides**, **API Reference**, and **Changelog**. **December 2025** Clearbit migration The Clearbit Logo API shut down on December 8, 2025. We published a [migration guide](/docs/migrations/clearbit) so you can move `logo.clearbit.com` URLs to Logo.dev in minutes, plus reference docs for the [Clearbit](/docs/migrations/clearbit), [Google Favicon](/docs/google-favicon-api), and [DuckDuckGo Favicon](/docs/duckduckgo-favicon-api) APIs. # Logo.dev core concepts Source: https://www.logo.dev/docs/concepts The names for Logo.dev's brand assets, services, and keys in one place: company logo vs favicon, brandmark vs wordmark, monogram, social banner, and publishable vs secret key. This glossary defines the names Logo.dev uses for brand assets, services, and keys. The brand-asset names cause the most confusion, so they have examples. ## Brand and visual terms A logo has two parts. The **symbol** is the graphic mark. The **wordmark** is the styled name. Together they make the **brandmark**. ### Company logo ![Slack logo](https://img.logo.dev/slack.com?token=live_6a1a28fd-6420-4492-aeb0-b297461d9de2) A brand's own mark, at a resolution you can show anywhere. For most brands it is the symbol, the graphic part with no text. `img.logo.dev/:domain` returns it. *Also called: logo, logomark, pictorial mark, icon, symbol, mark.* ### Brandmark Slack brandmark: the hash symbol next to the Slack wordmark The wide, rectangular logo lockup. For most brands it is the symbol and the wordmark together. For a brand that is only type, it is the wordmark alone. Brand returns it in the `brandmark` field. Designers often call this a combination mark, and many use "brandmark" for the symbol alone. *Also called: combination mark, logo lockup, horizontal logo, full logo.* ### Wordmark The styled text of a company's name, with no symbol. It is the whole brandmark only for brands that are only type, such as Sony or Visa. *Also called: logotype, text logo.* ### Favicon ![A favicon-sized Slack icon](https://img.logo.dev/slack.com?token=live_6a1a28fd-6420-4492-aeb0-b297461d9de2\&size=32) The small icon a browser shows in a tab, usually 16 to 32 pixels. Logo.dev serves company logos, not favicons scraped from websites. You can request a logo at favicon size. *Also called: site icon, tab icon, shortcut icon.* ### Monogram A generated monogram placeholder showing a single letter A generated placeholder that shows one letter. The Logo.dev CDN returns it when it has no logo for the company, so the image never breaks. *Also called: letter avatar, initials placeholder, fallback logo.* ### Social banner A Slack social-profile banner image The wide header image a brand uses on its social profiles. Brand returns these in `social_banners`. *Also called: header image, cover image, OG banner.* ### Brand colors The brand's main colors. Brand returns them in `colors`. *Also called: brand palette.* ## Service terms Logo.dev has three products. The [introduction](/docs/introduction#products) lists what each one does. * **Logo.dev CDN.** The image service at `img.logo.dev`. It takes a publishable key. Its usage unit is CDN requests. *Also called: the image API, logo image API, Logo CDN.* * **Logo.dev API.** The REST API at `api.logo.dev`. It takes a secret key. Its usage unit is API credits. *Also called: the REST API, brand data API, Logo API.* * **Logo.dev MCP.** The MCP server at `mcp.logo.dev` that gives AI agents the Logo.dev API as tools. Its usage unit is MCP usage, which spends API credits at the same rates as the REST routes. *Also called: the MCP server.* The products serve four features: * **Logo.** A company's logo image. The Logo.dev CDN serves it from an image URL, and the Logo.dev API returns it as a file to store. * **Brand.** The part of the Logo.dev API that returns brand profiles, logos, and brandmarks. *Also called: Brand API, brand profile API, brand kit.* * **Search.** The part of the Logo.dev API that turns a company name into candidate domains. *Also called: Search API, brand search, autocomplete API.* * **Transaction.** A separate service that identifies a merchant from a card transaction string. It is in private beta, at `www.logo.dev/api/transaction`, with its own beta key. *Also called: Transaction Enrichment API, merchant enrichment.* ## Key terms [API keys](/docs/platform/api-keys) has the full detail on each key. * **Publishable key.** A `pk_` key for the Logo.dev CDN, sent in the `token` query parameter. It is safe in client-side code. *Often miscalled a public key, public token, client key, or "the token."* * **Secret key.** An `sk_` key for the Logo.dev API, sent in the `Authorization: Bearer` header. Keep it on your server. *Often miscalled a private key, server key, or "API key."* * **Domain restrictions.** A key setting, the **Allowed domains only** toggle, that limits a publishable key to requests from domains you list. *Also called: allowed domains, referrer restrictions.* ## Next steps > [card] [API keys](/docs/platform/api-keys) > > Create, restrict, and rotate your keys. > [card] [Logo.dev CDN](/docs/logo-images/introduction) > > Look up a logo by domain, ticker, ISIN, crypto symbol, or name. # DuckDuckGo Favicon API Documentation Source: https://www.logo.dev/docs/duckduckgo-favicon-api Unofficial DuckDuckGo favicon service that returns a website's icon from a .ico URL. Small icons only, with no size options or guaranteed uptime. > [!WARNING] > > **DuckDuckGo does not document or support this service.** It has no published terms, rate limits, or uptime commitment, and DuckDuckGo can change it at any time. DuckDuckGo's icon service returns the favicon of a website from a URL. It needs no key. ## Endpoint ```text theme={null} https://icons.duckduckgo.com/ip3/{domain}.ico ``` ```html Example theme={null} Stripe favicon ``` ## Parameters **domain** `string` *required* The website domain, such as `example.com`, with no protocol or path. Add `.ico` after it. The service has no other parameters. ## Behavior * The URL always ends in `.ico`, but the file is the site's own icon. It can be an ICO or a PNG. * You cannot choose a size. Most icons are 16 to 48 pixels, so they look blurry at large sizes. * If DuckDuckGo finds no favicon, it returns a `404` status with a grey placeholder image. An `` tag still shows the placeholder. * The service works for public domains only, not for `localhost` or IP addresses. ## FAQs > [accordion] Is the DuckDuckGo favicon API free? > > Yes. It needs no key or account. DuckDuckGo publishes no terms or rate limits for it, so cache the icons on your side. > [accordion] Can I get a larger icon? > > No. The service returns the icon that the site provides, at the size the site provides. > [accordion] Can I use it in production? > > Many apps do, but DuckDuckGo does not support it. If you need company logos rather than favicons, use a logo service. ## Company logos instead of favicons A favicon is the small icon that a browser shows in a tab. The [Logo.dev CDN](/docs/logo-images/introduction) returns a company logo from a URL, with these differences: * You can look up a logo by domain, [stock ticker](/docs/logo-images/ticker), [ISIN](/docs/logo-images/isin), [crypto symbol](/docs/logo-images/crypto), or [company name](/docs/logo-images/name). * You choose the `size` and the `format`: `jpg`, `png`, or `webp`. * If Logo.dev has no logo, you get a monogram or a `404`, whichever you choose. * It needs a [publishable key](/docs/platform/api-keys), which is safe in client code. > [card] [Logo.dev CDN](/docs/logo-images/introduction) > > Show company logos by domain, ticker, or name from a plain image URL. # Fey Logos API Documentation Source: https://www.logo.dev/docs/fey-logos Free vector logo library for public companies that shut down in 2025 due to scraping and unsustainable costs. No longer available. > [!WARNING] > > **Fey Logos shut down in 2025.** `feylogos.com` now redirects to Fey's page about joining Wealthsimple, and the logo library is not available. Fey Logos was a free library of vector (SVG) logos for public companies. Fey Labs Inc., the company behind the Fey investing app, built it for designers who needed current brand marks for non-commercial work. It drew on the 4,000+ logos that Fey kept for its own app. People searched the library on a website and downloaded one logo at a time. It had no API. ![The FeyLogos.com site with a search bar above a dark grid of public-company logo tiles labeled by ticker symbol](https://mintcdn.com/simplecasual/uuspM5fAJj-mg7Fo/images/fey-logos.webp?fit=max\&auto=format\&n=uuspM5fAJj-mg7Fo\&q=85\&s=efd4c4dff41bf924629605b5ef9d8f81) FeyLogos.com: a free, searchable library of public-company vector logos, before it shut down in 2025. ## Timeline | Date | Event | | - | - | | January 10, 2024 | Public launch: "We've decided to open-source our entire vector library. For free." | | 2025 | Fey Labs took the library offline. | | August 2025 | Wealthsimple announced that it acquired Fey. | ## Why it shut down Fey Labs posted an "Important update" about the decision. The terms did not allow commercial use or bulk downloads. Some users scraped the site anyway, and the cost of the free service grew too high. Fey Labs took the library down to protect the project. ## What Fey Logos allowed | Limit | Detail | | - | - | | License | Personal and editorial use only. No commercial use. | | Access | One download at a time. No scraping or automation. | | Coverage | Public companies only | | Interface | Website only. No API. | | Trademarks | Each logo stayed the trademark of its owner. | ## Replace Fey Logos with Logo.dev Logo.dev is an API for apps that show company logos. It covers private companies as well as public ones. * To find a logo by company name, as you did on Fey Logos, use [Search](/docs/brand-search/introduction). It returns matching companies with their domains and logo URLs. * To show a logo in your app, use the [Logo.dev CDN](/docs/logo-images/introduction). Look up the logo by domain, [stock ticker](/docs/logo-images/ticker), or [company name](/docs/logo-images/name). * For colors, the wide brandmark, and social banners, use [Brand](/docs/brand/introduction). Unlike Fey Logos, Logo.dev allows commercial use. On the free plan, commercial use requires [attribution](/docs/platform/attribution). ## FAQs > [accordion] Can I still access Fey Logos? > > No. The library is offline, and `feylogos.com` redirects to Fey's page about Wealthsimple. > [accordion] Was Fey Logos open source? > > No. The launch post said "open-source", but that meant free access. The library had no open-source license or public repository, and its terms did not allow commercial use or bulk downloads. > [accordion] Who was behind Fey Logos? > > Fey Labs Inc., the company behind the Fey investing app. Wealthsimple acquired Fey in 2025. > [accordion] Can I use archived Fey Logos files in my project? > > Each logo is a trademark of its owner. If you use one, follow that brand's guidelines. > [card] [Logo.dev CDN](/docs/logo-images/introduction) > > Show any company's logo by domain, ticker, or name from an image URL. > [card] [Search](/docs/brand-search/introduction) > > Search companies by name and get their domains and logo URLs. # Google Favicon API Documentation Source: https://www.logo.dev/docs/google-favicon-api Complete guide to Google's unofficial s2 favicon API for retrieving website icons by URL, with size parameters, usage examples, and known limitations. > [!WARNING] > > **Google does not document or support this API.** It has no published terms, rate limits, or uptime commitment, and Google can change it at any time. Google's favicon service returns the favicon of a website as a PNG. Many apps and browser extensions use it to show small site icons. It needs no key. ## Endpoint ```text theme={null} https://www.google.com/s2/favicons?domain={domain} ``` ```html Example theme={null} Stripe favicon ``` The URL redirects to a `gstatic.com` address that serves the image. ## Parameters **domain** `string` *required* The website domain, such as `example.com` or `www.example.com`. `domain_url` also works. **sz** `number` (default: 16) The requested size in pixels, such as `16`, `32`, `64`, or `128`. If the site has no icon at that size, Google returns a smaller one. ## Behavior * The response is always a PNG, whatever format the site uses. * The icon can be smaller than `sz`. A request for 128 pixels can return a 32-pixel icon, so large sizes can look blurry. * If Google finds no favicon, it returns a `404` status with a generic globe icon. An `` tag still shows the globe. * The service works for public domains only, not for `localhost` or IP addresses. ## FAQs > [accordion] Is the Google Favicon API free? > > Yes. It needs no key or account. Google publishes no terms or rate limits for it, so cache the icons on your side. > [accordion] Why is the icon smaller than the size I asked for? > > Google can return only the sizes that the website provides. If a site has a 32-pixel favicon, a request for 128 pixels returns 32 pixels. > [accordion] Can I use it in production? > > Many apps do, but Google does not support it. If you need company logos rather than favicons, use a logo service. ## Company logos instead of favicons A favicon is the small icon that a browser shows in a tab. The [Logo.dev CDN](/docs/logo-images/introduction) returns a company logo from a URL, with these differences: * You can look up a logo by domain, [stock ticker](/docs/logo-images/ticker), [ISIN](/docs/logo-images/isin), [crypto symbol](/docs/logo-images/crypto), or [company name](/docs/logo-images/name). * You choose the `size` and the `format`: `jpg`, `png`, or `webp`. * If Logo.dev has no logo, you get a monogram or a `404`, whichever you choose. * It needs a [publishable key](/docs/platform/api-keys), which is safe in client code. > [card] [Logo.dev CDN](/docs/logo-images/introduction) > > Show company logos by domain, ticker, or name from a plain image URL. # Add company logos in Lovable, v0, and Bolt Source: https://www.logo.dev/docs/integrations/ai-app-builders Add company logos to a Lovable, v0, or Bolt app with one paste-in prompt. The builder writes the Logo.dev CDN integration, and you supply your publishable key. Lovable, v0, and Bolt write the Logo.dev integration for you. Paste one prompt into the chat, and the builder adds company logos from the Logo.dev CDN to your app. The prompt is the same for all three tools. You supply a publishable key. ## Get a publishable key The prompt needs your publishable key. A publishable key is safe in client code. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. ## Add logos with one prompt **1. Copy the prompt and add your key** Replace both `LOGO_DEV_PUBLISHABLE_KEY` placeholders with your key: ```text theme={null} Add company logos to this app with the Logo.dev CDN. The Logo.dev CDN returns any company's logo as a cacheable image URL. There is no SDK. Use an tag with my publishable key. My publishable key (safe in client code): LOGO_DEV_PUBLISHABLE_KEY Render a logo from a company domain: {`${domain} To look up a company by another identifier, change the path: name/Stripe, ticker/AAPL, crypto/BTC, isin/US0378331005. Query params: size (pixels), format (jpg, png, or webp), theme (light or dark, for the background the logo sits on; use it only with format=png or format=webp), retina=true for high-DPI screens, fallback (monogram by default, or 404). The docs below list each default and limit. A missing logo returns a monogram with 200 OK by default, so the image never breaks. Create a reusable CompanyLogo component and use it everywhere the app shows a company. Docs: https://www.logo.dev/docs/logo-images/introduction ``` **2. Send the prompt in the builder's chat** Send the prompt in the chat where you build the app. The builder adds a `CompanyLogo` component and uses it in the views that show companies. **3. Check that a logo renders** Ask the preview to show a company you know. If you see a plain monogram instead of the real logo, the key is usually still the placeholder. Search the generated code for `LOGO_DEV_PUBLISHABLE_KEY` and replace it. ## Store the key in your builder A publishable key is made for client code, so the generated app can ship with it. Each builder stores the key in a different place. > [tab] Lovable > > Lovable renders the logos in the browser, so the key stays in the frontend code. You do not need to move it. > [tab] v0 > > To move the key out of the code, send a follow-up prompt such as "move the Logo.dev key into an environment variable". v0 generates Next.js, so the variable name needs the `NEXT_PUBLIC_` prefix to reach the browser. > > To take the exported app further, see the [Next.js integration](/docs/integrations/nextjs). > [tab] Bolt > > To move the key out of the code, send a follow-up prompt such as "move the Logo.dev key into an environment variable". Bolt puts it in the project's `.env` file. In a Vite project, the variable name needs the `VITE_` prefix to reach the browser. To stop other sites from using your key, turn on [domain restrictions](/docs/platform/api-keys#domain-restrictions). Add your preview domain and your published domain. Before you publish, check whether your plan needs an [attribution link](/docs/platform/attribution). ## Next steps > [card] [Logo.dev CDN overview](/docs/logo-images/introduction) > > Lookup modes, formats, themes, and fallbacks. > [card] [API keys](/docs/platform/api-keys) > > Publishable and secret keys, and domain restrictions. # Add company logos in Microsoft Excel Source: https://www.logo.dev/docs/integrations/excel Display company logos in Excel using Logo.dev. The IMAGE function works in Microsoft 365, Excel 2024, and Online. Excel 2019 and earlier insert logos as web pictures. Show company logos in Excel with the `IMAGE` function and a Logo.dev CDN URL. Excel 2019 and earlier have no `IMAGE` function, so on those versions you insert each logo as a picture. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. | Excel version | How to add a logo | | - | - | | Microsoft 365, Excel 2024, Excel for the web | [`IMAGE` function](#add-a-logo-with-the-image-function) | | Excel 2019, 2016, 2013 | [Insert as a picture](#insert-a-logo-as-a-picture) | ## Add a logo with the IMAGE function Put a CDN URL in `IMAGE`, and replace `LOGO_DEV_PUBLISHABLE_KEY` with your publishable key: ```excel One domain theme={null} =IMAGE("https://img.logo.dev/microsoft.com?token=LOGO_DEV_PUBLISHABLE_KEY") ``` ```excel Domain from a cell theme={null} =IMAGE(CONCAT("https://img.logo.dev/", A2, "?token=LOGO_DEV_PUBLISHABLE_KEY&format=png")) ``` ```excel Brand name from a cell (Windows) theme={null} =IMAGE(CONCAT("https://img.logo.dev/name/", ENCODEURL(A2), "?token=LOGO_DEV_PUBLISHABLE_KEY")) ``` ```excel Brand name from a cell (web and Mac) theme={null} =IMAGE(CONCAT("https://img.logo.dev/name/", SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A2, "%", "%25"), " ", "%20"), "#", "%23"), "&", "%26"), "/", "%2F"), "?", "%3F"), "+", "%2B"), "\", "%5C"), "?token=LOGO_DEV_PUBLISHABLE_KEY")) ``` If column A holds brand names instead of domains, encode the cell so spaces and special characters survive. See [name lookup](/docs/logo-images/name). `ENCODEURL()` works only in Excel for Windows. Excel for the web and Excel for Mac do not have it, so use the `SUBSTITUTE()` formula there. It encodes spaces and the characters that change a URL: `#`, `&`, `/`, `\`, `?`, and `+`. It encodes `%` first, so that it does not encode the `%` signs from the other substitutions again. For example, `#1 Cochran` becomes `%231%20Cochran`, and `AT&T` becomes `AT%26T`. To fill a column, drag the formula down. To change the size, format, or theme, add [CDN parameters](/docs/logo-images/introduction#parameters) to the URL. ## Replace Clearbit logo formulas If your spreadsheet used the Clearbit Logo API (`logo.clearbit.com`), which has [shut down](/docs/migrations/clearbit), change the base URL to `img.logo.dev` and add your token: ```excel Before (Clearbit) theme={null} =IMAGE(CONCAT("https://logo.clearbit.com/", A2)) ``` ```excel After (Logo.dev) theme={null} =IMAGE("https://img.logo.dev/"&A2&"?token=LOGO_DEV_PUBLISHABLE_KEY") ``` To change every formula at once, use **Find and replace** to change `logo.clearbit.com` to `img.logo.dev`. Then add `?token=LOGO_DEV_PUBLISHABLE_KEY` after the domain. The [Clearbit migration guide](/docs/migrations/clearbit) covers the rest. ## Insert a logo as a picture Use this method in Excel 2019 and earlier, or for a logo that floats over the grid. Excel saves a copy of the image in the workbook, and that copy does not update when the brand changes its logo. If you need logo files to keep, get them from the [Logo.dev API](/docs/platform/self-hosting). **1. Open the picture dialog** On Windows, click **Insert** > **Pictures**. In newer versions, then click **This Device**. **2. Paste the CDN URL** In the **File name** box, paste the URL instead of choosing a local file: ```text theme={null} https://img.logo.dev/stripe.com?token=LOGO_DEV_PUBLISHABLE_KEY&format=png&size=256 ``` **3. Insert the logo** Click **Insert**. Excel downloads the logo and places it on the sheet. ## Add a logo to the header or footer A header or footer logo shows on every printed page and PDF export. **1. Open the header** Click **Insert** > **Header & Footer**, then click the left, center, or right section of the header. **2. Insert the picture** On the **Header & Footer** tab, click **Picture**. Paste the CDN URL in the file dialog, as in [Insert a logo as a picture](#insert-a-logo-as-a-picture). ## Keep logos with their rows A picture does not move with its row by default. To keep each logo next to its data when you sort or filter: **1. Open the picture properties** Right-click the logo, then click **Size and Properties**. **2. Lock it to the cell** Under **Properties**, click **Move and size with cells**. ## Add logos in bulk with a macro This VBA macro writes an `IMAGE` formula next to each selected domain. It needs an Excel version with the `IMAGE` function. ```vba theme={null} Sub AddLogos() Dim cell As Range Dim apiKey As String apiKey = "LOGO_DEV_PUBLISHABLE_KEY" For Each cell In Selection If cell.Value <> "" Then cell.Offset(0, 1).Formula = "=IMAGE(""https://img.logo.dev/" & _ cell.Value & "?token=" & apiKey & "&format=png"")" End If Next cell End Sub ``` Select the cells that hold domains, then run the macro. # Add company logos in Google Sheets Source: https://www.logo.dev/docs/integrations/google-sheets Display company logos in Google Sheets using the Logo.dev API. Enrich CRM data, company lists, and reports with automatic logo lookup via the IMAGE formula. Show company logos in Google Sheets with the `IMAGE` function and a Logo.dev CDN URL. You need no add-on or extension. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. ## Add a logo to a cell Put a CDN URL in `IMAGE`, and replace `LOGO_DEV_PUBLISHABLE_KEY` with your publishable key: ```javascript One domain theme={null} =IMAGE("https://img.logo.dev/apple.com?token=LOGO_DEV_PUBLISHABLE_KEY") ``` ```javascript Domain from a cell theme={null} =IMAGE("https://img.logo.dev/"&A2&"?token=LOGO_DEV_PUBLISHABLE_KEY&format=png") ``` ```javascript Brand name from a cell theme={null} =IMAGE("https://img.logo.dev/name/"&ENCODEURL(A2)&"?token=LOGO_DEV_PUBLISHABLE_KEY") ``` If column A holds brand names instead of domains, wrap the cell in `ENCODEURL()` so spaces and special characters survive. See [name lookup](/docs/logo-images/name). To change the size, format, or theme, add [CDN parameters](/docs/logo-images/introduction#parameters) to the URL. ## Fill a whole column `ARRAYFORMULA` applies one formula to every row. It skips empty cells, and it fills new rows as you add domains to column A: ```javascript theme={null} =ARRAYFORMULA(IF(A2:A="",,IMAGE("https://img.logo.dev/"&A2:A&"?token=LOGO_DEV_PUBLISHABLE_KEY&format=png"))) ``` ## Fit the logo to the cell The second argument of `IMAGE` sets the sizing mode: | Mode | Result | Formula | | - | - | - | | `1` (default) | Fits the cell and keeps the aspect ratio | `=IMAGE(url, 1)` | | `2` | Stretches to fill the cell | `=IMAGE(url, 2)` | | `3` | Keeps the image's original size | `=IMAGE(url, 3)` | | `4` | Uses the height and width you give | `=IMAGE(url, 4, 64, 64)` | For a sharp logo in mode 4, request a larger image than the cell, such as `size=256` for a 64 by 64 cell: ```javascript theme={null} =IMAGE("https://img.logo.dev/"&A2&"?token=LOGO_DEV_PUBLISHABLE_KEY&size=256", 4, 64, 64) ``` ## Replace Clearbit logo formulas If your spreadsheet used the Clearbit Logo API (`logo.clearbit.com`), which has [shut down](/docs/migrations/clearbit), change the base URL to `img.logo.dev` and add your token: ```excel Before (Clearbit) theme={null} =IMAGE(CONCAT("https://logo.clearbit.com/", A2)) ``` ```excel After (Logo.dev) theme={null} =IMAGE("https://img.logo.dev/"&A2&"?token=LOGO_DEV_PUBLISHABLE_KEY") ``` To change every formula at once, use **Find and replace** to change `logo.clearbit.com` to `img.logo.dev`. Then add `?token=LOGO_DEV_PUBLISHABLE_KEY` after the domain. The [Clearbit migration guide](/docs/migrations/clearbit) covers the rest. ## FAQs > [accordion] Do logos show when I share the sheet? > > Yes. Anyone who opens the sheet sees the logos, including people without a > Logo.dev account. The key in the formula authenticates each request. > [accordion] Why do logos stop loading after I restrict my key to my domains? > > Google fetches `IMAGE` URLs from its own servers and sends no `Referer` > header, so a key with [domain restrictions](/docs/platform/api-keys#domain-restrictions) > rejects the request. Turn off domain restrictions on the key that your > sheets use. > [accordion] Can I make a logo clickable? > > Not directly. Google Sheets does not link images. Put a `HYPERLINK` > formula to the company's website in the next column. # Logo.dev integrations for apps and spreadsheets Source: https://www.logo.dev/docs/integrations/introduction Integrate Logo.dev with popular apps and frameworks. Display company logos in spreadsheets, applications, and workflows without building custom scrapers. Add company logos to your framework, AI app builder, spreadsheet, or deck. Each guide covers the steps for one tool. ## Frameworks > [card] [Next.js](/docs/integrations/nextjs) > > Load logos in the browser with next/image and unoptimized > [card] [shadcn/ui](/docs/integrations/shadcn) > > Install logo, autocomplete, and logo wall components with the shadcn CLI ## AI app builders and office apps > [card] [Lovable, v0, and Bolt](/docs/integrations/ai-app-builders) > > Paste one prompt and your AI app builder adds company logos to your app > [card] [Google Sheets](/docs/integrations/google-sheets) > > Display company logos in Google Sheets using the IMAGE formula > [card] [Microsoft Excel](/docs/integrations/excel) > > Add company logos to Excel spreadsheets with the IMAGE function > [card] [Microsoft PowerPoint](/docs/integrations/powerpoint) > > Insert company logos on slides and brand every slide with the Slide Master ## Build your own integration > [card] [Logo.dev CDN](/docs/logo-images/introduction) > > Show a logo from an image URL. Look it up by domain, name, stock ticker, > ISIN, or crypto symbol. > [card] [Search](/docs/brand-search/introduction) > > Find a company's domain from its brand name. > [card] [Brand](/docs/brand/introduction) > > Turn a domain into a brand profile: colors, description, socials, and the > brandmark. # Use Logo.dev with Next.js Source: https://www.logo.dev/docs/integrations/nextjs Show company logos in Next.js from the Logo.dev CDN. Render next/image with unoptimized so the browser loads each logo, and get files for server code from the Logo.dev API. Show a company logo in Next.js with a Logo.dev CDN URL. The browser loads each logo from `img.logo.dev`, so the image never passes through your server. Render `next/image` with the `unoptimized` prop, or use a plain ``. ## Prerequisites * A Next.js app. * A Logo.dev publishable key: > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. **1. Store your publishable key in an env var** A publishable key is safe in client code. Prefix the variable with `NEXT_PUBLIC_` so client components can read it: ```bash .env.local theme={null} NEXT_PUBLIC_LOGO_DEV_PUBLISHABLE_KEY=pk_xxxxxxxxxxxx ``` **2. Render the logo** Pass the domain and your publishable key to `next/image`, and set `unoptimized`. Set `width` and `height`, since `next/image` requires them for remote images: ```tsx CompanyLogo.tsx theme={null} import Image from "next/image"; export function CompanyLogo({ domain }: { domain: string }) { return ( {`${domain} ); } ``` With `unoptimized`, you need no change to `next.config.js`. ## Skip the optimizer Without `unoptimized`, the Next.js Image Optimization API fetches each image on your server and passes it on to your users. [Fair use](/docs/platform/fair-use) does not allow this for `img.logo.dev`. The Logo.dev CDN already serves sized, cached images, so the optimizer adds nothing. If you added `img.logo.dev` to `images.remotePatterns`, remove the entry. Next.js then rejects any `next/image` that sends a logo through the optimizer. A plain `` also loads the logo in the browser: ```tsx theme={null} {`${domain} ``` To control the output, set the [`size`, `format`, and `theme` parameters](/docs/logo-images/introduction#parameters) on the URL. ## Canvas and OG images A logo drawn on a `` needs `crossorigin="anonymous"`. An Open Graph image from `next/og` needs the logo file on your server, so get it from the Logo.dev API, not the CDN. [CORS, canvas, and CSP](/docs/platform/cors) covers both cases. ## Use logos in server code To work with a logo file in a route handler, a script, or any other server code, call the Logo.dev API with your secret key. You can store those files and serve them from your own servers. See [self-hosting](/docs/platform/self-hosting). # Add company logos in Microsoft PowerPoint Source: https://www.logo.dev/docs/integrations/powerpoint Add company logos to PowerPoint slides with Logo.dev. Insert logos from an image URL, brand every slide with the Slide Master, and size them for crisp display. Add company logos to slides, decks, and templates from a Logo.dev CDN URL. PowerPoint has no `IMAGE` function, so you insert each logo as a picture. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. | PowerPoint version | Insert from a URL | | - | - | | Microsoft 365, PowerPoint 2019 and 2021 on Windows | Yes, with the steps below | | PowerPoint for the web | No. Use the desktop app, or get a logo file from the [Logo.dev API](/docs/platform/self-hosting) and upload it with **Insert** > **Picture** > **This Device** | ## Insert a logo from a URL **1. Open the picture dialog** Click **Insert** > **Pictures** > **This Device**. **2. Paste the CDN URL** In the **File name** box, paste the URL instead of choosing a local file: ```text theme={null} https://img.logo.dev/stripe.com?token=LOGO_DEV_PUBLISHABLE_KEY&format=png&size=512 ``` **3. Insert the logo** Click the arrow next to **Insert**, then click **Link to File**. PowerPoint loads the logo from the URL each time the deck opens. **Insert** embeds a fixed copy instead. An embedded logo stays fixed and does not update when the brand changes its logo. For decks that need a stored logo file, get it from the [API](/docs/platform/self-hosting). ## Add a logo to every slide **1. Open the Slide Master** Click **View** > **Slide Master**. **2. Insert the logo** Select the top master slide. Insert the logo as in [Insert a logo from a URL](#insert-a-logo-from-a-url), then move it into position. **3. Close the master view** Click **Close Master View**. The logo shows on every slide that uses that master. ## Size logos for slides A slide shows a logo much larger than a web page does. Request a large image and let PowerPoint scale it down: | Goal | URL parameters | | - | - | | Transparent background | `format=png` | | Sharp on a large slide | `size=512` | | Dark slide background | `theme=dark&format=png` | | Muted, uniform look | `greyscale=true` | ```text theme={null} https://img.logo.dev/shopify.com?token=LOGO_DEV_PUBLISHABLE_KEY&format=png&size=512&theme=dark ``` For every parameter, see the [Logo.dev CDN overview](/docs/logo-images/introduction#parameters). # Add Logo.dev components with shadcn/ui Source: https://www.logo.dev/docs/integrations/shadcn Install production-ready Logo.dev React components with the shadcn CLI: logo images with fallbacks, company autocomplete, logo walls, and attribution. Install Logo.dev's React components with one shadcn CLI command. Each component lands in your project as code you own, with fallbacks, retina images, dark mode, and key handling already in place. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. ## Install a component In any project set up with [shadcn/ui](https://ui.shadcn.com), install from the registry URL: ```bash theme={null} npx shadcn@latest add https://www.logo.dev/r/logo.json ``` Or install from the [logo-dev/logo-api](https://github.com/logo-dev/logo-api) repo: ```bash theme={null} npx shadcn@latest add logo-dev/logo-api/logo ``` The CLI copies the source into your project, installs any shadcn primitives the component composes, and adds the environment variables it needs to `.env.local`: * `NEXT_PUBLIC_LOGO_DEV_TOKEN`: your publishable key, safe in client code. Every component reads it. * `LOGO_DEV_SECRET_KEY`: your secret key, server-only. Only `brand-search` needs it. ## What's in the registry | Component | Install name | What it does | | - | - | - | | Logo | `logo` | A logo that never breaks: domain, name, ticker, crypto, or ISIN lookup with retina srcSet, dark-mode variants, and layered fallbacks | | Logo Avatar | `logo-avatar` | A logo in a shadcn Avatar shell with initials fallback, for CRM rows and transaction feeds | | Brand Search | `brand-search` | Company autocomplete backed by [Search](/docs/brand-search/introduction), plus a server route that keeps your secret key private | | Logo Wall | `logo-wall` | A customer or integration logo grid with grayscale-to-color hover | | Attribution | `attribution` | The [attribution link](/docs/platform/attribution), for plans that require one | | Logo lib | `logo-lib` | The typed URL builder underneath all of the above, useful on its own | ## Logo Render a logo from any identifier your data already has: ```tsx theme={null} import { Logo } from "@/components/ui/logo"; ``` `theme="auto"` (the default) renders light and dark variants toggled by Tailwind's `dark:` variant, so the right logo shows in both color schemes without a theme provider. `fallback` controls what renders when no logo exists: the API's generated monogram (default), a local initials tile, or any React node you pass. ## Logo Avatar Put a logo in account lists and transaction feeds: ```tsx theme={null} import { LogoAvatar } from "@/components/ui/logo-avatar"; ``` ## Brand Search Let users pick their company by typing a name: ```tsx theme={null} import { BrandSearch } from "@/components/brand-search"; save(brand.domain)} /> ``` Typing is debounced at 200ms with stale requests aborted, and each suggestion shows the company's logo. The install includes `app/api/logo-dev/search/route.ts`, a Next.js route that proxies the Search endpoint so your secret key never reaches the browser. Not on Next.js? Recreate that proxy in your backend and pass its path via the `endpoint` prop. > [!WARNING] > > The proxy route ships without authentication, so anyone who can reach it can spend your API credits. Add rate limiting or your own auth before you deploy it to production. ## Logo Wall Build a customer logo grid from a list of domains: ```tsx theme={null} import { LogoWall } from "@/components/logo-wall"; ``` Logos render in muted grayscale and regain color on hover. The wall includes the Logo.dev attribution link by default. If your plan does not [require attribution](/docs/platform/attribution), turn it off with `attribution={false}`. ## Requirements The components target React 19 (React 18.3 works, without ref forwarding) and Tailwind CSS v4 with shadcn/ui tokens. They have zero npm dependencies of their own: shadcn primitives like `avatar`, `command`, and `popover` install from ui.shadcn.com as needed. ## Next steps > [card] [Use cases](/docs/use-cases/logo-from-domain) > > The patterns these components implement, with live demos. > [card] [logo-dev/logo-api](https://github.com/logo-dev/logo-api) > > Component source, issues, and contributions. # Logo.dev is the logo API for any company Source: https://www.logo.dev/docs/introduction What Logo.dev is and which part to use: an image URL for every company logo you display, and a REST API for brand data and logo files you store. Logo.dev turns a domain, stock ticker, ISIN, crypto symbol, or company name into that company's logo or its brand profile. To show a logo in a website or app, use an image URL from the Logo.dev CDN. To get a logo file or brand data on your server, use the Logo.dev API. ## How it works ### Show a logo with a URL Put an identifier in a CDN URL, and the company's logo comes back as an image: ```html theme={null} Stripe logo ``` For most apps, that URL is the whole integration. Enter a domain to try it: company domain logo preview Enter company domain The identifier can be a domain, a [stock ticker](/docs/logo-images/ticker), an [ISIN](/docs/logo-images/isin), a [crypto symbol](/docs/logo-images/crypto), or a [company name](/docs/logo-images/name). Query parameters set the size, format, and theme. The URL takes a [publishable key](/docs/platform/api-keys), which is safe in client code. By default, the URL returns an image for any identifier. If Logo.dev has no logo for the company, you get a [monogram](/docs/concepts#monogram) instead of a broken image. You can turn off that [fallback](/docs/logo-images/introduction#fallback-images) and handle the miss yourself. When a company changes its logo, Logo.dev updates the image behind the same URL. You do not change your code. [Caching](/docs/platform/caching) explains when browsers show the new logo. ### Get files and data on your server Use the API when you need the file itself or data about the brand. Examples are a logo in a PDF, an email, or an OG image, a copy in your own storage, brand colors, or a company name resolved to a domain. The API takes a [secret key](/docs/platform/api-keys) that stays on your server. It returns a download URL for each file, so [self-hosting](/docs/platform/self-hosting) starts there. Do not download images from the CDN to build your own copy. The CDN serves images for display, and [fair use](/docs/platform/fair-use) covers the limits. ### Connect an AI agent If an AI agent does the work, connect it to the [Logo.dev MCP](/docs/mcp/introduction) server. The server calls the API for the agent. You sign in with OAuth instead of pasting a secret key. ## Products The **Logo.dev CDN** at `img.logo.dev` serves logo images to your website or app. The **Logo.dev API** at `api.logo.dev` includes Brand, Search, and webhooks. The **Logo.dev MCP** at `mcp.logo.dev` gives AI agents the API as tools. Transaction is a separate beta service at `www.logo.dev/api/transaction`, with its own key. > [card] [Logo.dev CDN](/docs/logo-images/introduction) > > Show a company's logo in a website or app from an image URL. Look it up by domain, stock ticker, ISIN, crypto symbol, or name. > [card] [Brand](/docs/brand/introduction) > > Turn one identifier into a brand profile: name, description, colors, socials, logo, brandmark, and social banners. Get a logo or brandmark file to store. > [card] [Search](/docs/brand-search/introduction) > > Turn a company name into candidate domains for an autocomplete or a name lookup. > [card] [Transaction](/docs/transaction/introduction) > > Identify the merchant behind a card transaction string. Private beta. > [card] [Logo.dev MCP](/docs/mcp/introduction) > > Let Claude, Cursor, or another MCP client look up brands, logos, and brandmarks. ## Get started > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. > [card] [Quickstart](/docs/quickstart) > > Show your first logo from an image URL. > [card] [Core concepts](/docs/concepts) > > What brandmark, monogram, publishable key, and the other terms mean. > [card] [Use cases](/docs/use-cases/logo-from-domain) > > Live demos with working code: transaction feeds, CRM records, logo walls, and more. # Get crypto logos by symbol Source: https://www.logo.dev/docs/logo-images/crypto Crypto logo API for Bitcoin, Ethereum, stablecoins, and thousands of other tokens. Get any token's logo by symbol from a single image URL. Use a crypto lookup when you have a token symbol, such as in a wallet, an exchange, or a portfolio tracker. ```html theme={null} Ethereum logo ``` cryptocurrency symbol logo preview Enter cryptocurrency symbol ## Symbol format Pass the token's standard ticker symbol. Case does not matter, so `btc` and `BTC` return the same logo. | Token | Path | | - | - | | Bitcoin | `/crypto/btc` | | Ethereum | `/crypto/eth` | | Tether | `/crypto/usdt` | | Solana | `/crypto/sol` | | Dogecoin | `/crypto/doge` | A crypto symbol is not a stock ticker. For a company's shares, use the [stock ticker lookup](/docs/logo-images/ticker). To request a token that is missing, [email support](mailto:support@logo.dev?subject=Crypto%20Logos) with its symbol. For the other parameters and the fallback behavior, see the [Logo.dev CDN overview](/docs/logo-images/introduction#parameters). # Get stock exchange logos by exchange code Source: https://www.logo.dev/docs/logo-images/exchange Get the logo of a stock exchange, such as NYSE, NASDAQ, or the London Stock Exchange, by its exchange code from a single image URL. Use an exchange lookup when you show where a security trades, such as in a brokerage, a market dashboard, or a listing page. ```html theme={null} New York Stock Exchange logo ``` stock exchange code logo preview Enter stock exchange code ## Exchange codes Pass the exchange code. Case does not matter, so `nyse` and `NYSE` return the same logo. | Exchange | Path | | - | - | | New York Stock Exchange | `/exchange/NYSE` | | NASDAQ | `/exchange/NASDAQ` | | London Stock Exchange | `/exchange/LSE` | | Toronto Stock Exchange | `/exchange/TSX` | | Euronext Paris | `/exchange/PAR` | | Xetra | `/exchange/XETRA` | | Japan Exchange Group | `/exchange/JPX` | | Hong Kong Stock Exchange | `/exchange/HKG` | An exchange code is not the suffix you add to a ticker. To get a listed company's logo, use the [stock ticker lookup](/docs/logo-images/ticker), such as `/ticker/AZN.L`. ## How an exchange resolves The CDN maps the code to the domain of the company that operates the exchange, then returns that company's logo. Exchanges with the same operator return the same logo. For example, `AMEX` returns the NYSE logo, and the Euronext markets return the Euronext logo. An exchange code that Logo.dev does not know returns `400 Bad Request`, not a monogram, whatever `fallback` is set to. See [Errors](/docs/platform/errors#logo-cdn-status-codes). For the other parameters, see the [Logo.dev CDN overview](/docs/logo-images/introduction#parameters). # Get company logos by domain Source: https://www.logo.dev/docs/logo-images/get Get any company's logo by domain from a single image URL. Pass the domain to img.logo.dev with your publishable key and use the URL anywhere an image goes. Use a domain lookup when you know the company's website. The other lookups turn their identifier into a domain first, so a domain is the most direct way to get a logo. ```html theme={null} Stripe logo ``` company domain logo preview Enter company domain ## Domain format * Pass the hostname only, such as `stripe.com`. A value with a protocol or a path, such as `https://stripe.com/pricing`, does not resolve. * Case does not matter. `STRIPE.COM` and `stripe.com` return the same logo. * The CDN uses the registrable domain. `www.stripe.com` and `docs.stripe.com` both return the logo for `stripe.com`. ## Parameters A domain lookup takes the same parameters as every other lookup. See [format, size, theme, and fallback](/docs/logo-images/introduction#parameters) in the Logo.dev CDN overview. # Logo.dev CDN: Get Any Company Logo by Domain Source: https://www.logo.dev/docs/logo-images/introduction The Logo.dev CDN returns any company's logo from one image URL. Look up logos by domain, name, stock ticker, ISIN, crypto symbol, stock exchange, or market index in JPG, PNG, or WebP. The Logo.dev CDN gives you any company's logo as an image URL. Put `https://img.logo.dev/{identifier}` in an `` tag with your publishable key, and the CDN serves the latest logo from its cache. You never host a logo file yourself. ## Add a logo to your page **1. Get a publishable key** > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. The publishable key (`pk_`) is safe in client code. To stop other sites from using it, add [domain restrictions](/docs/platform/api-keys#domain-restrictions). **2. Embed the logo** Put the identifier you have in the path and your key in `token`: ```html Domain theme={null} Shopify logo ``` ```html Name theme={null} Shopify logo ``` ```html Ticker theme={null} Shopify logo ``` ```html ISIN theme={null} Apple logo ``` ```html Crypto theme={null} Bitcoin logo ``` ![Shopify logo](https://img.logo.dev/shopify.com?token=live_6a1a28fd-6420-4492-aeb0-b297461d9de2) [https://img.logo.dev/shopify.com?token=LOGO\_DEV\_PUBLISHABLE\_KEY](https://img.logo.dev/shopify.com?token=LOGO_DEV_PUBLISHABLE_KEY) **3. Go live** Before you ship, check whether your plan needs an [attribution link](/docs/platform/attribution), and read the [rate limits](/docs/platform/rate-limits) and [fair use policy](/docs/platform/fair-use). ## Lookup modes Use the identifier your data already has. Each page covers the notes for that identifier. * [By domain](/docs/logo-images/get): the company's website, such as `shopify.com`. The most direct lookup. * [By name](/docs/logo-images/name): a brand name, such as `Shopify`, when you have no domain. * [By stock ticker](/docs/logo-images/ticker): a symbol such as `AAPL`, with suffixes for non-US exchanges. * [By ISIN](/docs/logo-images/isin): a security identifier, such as `US0378331005`. * [By crypto symbol](/docs/logo-images/crypto): a token symbol, such as `BTC`. * [By stock exchange](/docs/logo-images/exchange): an exchange code, such as `NYSE`. * [By market index](/docs/logo-images/market-index): an index symbol, such as `SPX`. ## Choose a format The default format is `jpg`. JPG has no transparency, so the logo sits on a white box. For a transparent background, request `format=png`. For smaller files, request `format=webp`. ```html theme={null} Shopify logo ``` The CDN does not serve SVG. ## Size it for retina screens `size` sets the width and height in pixels, and the logo keeps its aspect ratio. Request the size you display, and add `retina=true` to get a 2x image for high-density screens: ```html theme={null} Shopify logo ``` To set each side, use `width` and `height` instead of `size`. ## Match light and dark themes `theme` changes the colors of a transparent logo so it stays visible on your background. `theme=dark` lightens a dark logo for a dark background. `theme=light` does the reverse. Use it with `format=png` or `format=webp`, because a JPG has no transparency. Do not send `theme=dark` with the default `jpg` format: the request can return `404`. ```html theme={null} Apple logo ``` ![Apple logo for dark backgrounds](https://img.logo.dev/apple.com?token=live_6a1a28fd-6420-4492-aeb0-b297461d9de2\&theme=dark\&format=png) [https://img.logo.dev/apple.com?token=LOGO\_DEV\_PUBLISHABLE\_KEY\&theme=dark\&format=png](https://img.logo.dev/apple.com?token=LOGO_DEV_PUBLISHABLE_KEY\&theme=dark\&format=png) For a black-and-white logo, add `greyscale=true`. ## Get the wide logo or the favicon The CDN serves each company's square logo. For the wide logo lockup, the [brandmark](/docs/concepts#brandmark), call [`GET /v2/brands/brandmark`](/docs/brand/introduction#get-only-the-logo-or-the-brandmark) from your server. The CDN does not serve a site's [favicon](/docs/concepts#favicon). ## Fallback images If Logo.dev has no logo for an identifier, the CDN returns a generated monogram. The status is `200`, or [`202`](/docs/platform/errors#logo-cdn-status-codes) on the first request for a domain Logo.dev has not seen. Either way, your UI shows an image, not a broken one. ![Example fallback monogram](https://img.logo.dev/example.com?token=live_6a1a28fd-6420-4492-aeb0-b297461d9de2) [https://img.logo.dev/example.com?token=LOGO\_DEV\_PUBLISHABLE\_KEY](https://img.logo.dev/example.com?token=LOGO_DEV_PUBLISHABLE_KEY) To show your own image instead, add `fallback=404`. The CDN then returns `404 Not Found`, and your error handler swaps in your image: ```html HTML theme={null} Company logo ``` ```jsx React theme={null} import { useState } from "react"; function CompanyLogo({ domain }) { const [src, setSrc] = useState( `https://img.logo.dev/${domain}?token=LOGO_DEV_PUBLISHABLE_KEY&fallback=404` ); return ( {`${domain} setSrc("/images/default-logo.png")} /> ); } ``` ## Skip domains that redirect Some domains reach a brand only through a redirect, such as an old domain that now points to a new company. By default, the CDN follows the redirect and returns the logo of the domain it points to. To treat these domains as having no logo, add `redirect=404`. The CDN then returns `404 Not Found`, whatever `fallback` is set to: ```html theme={null} Example logo ``` ## Parameters Every lookup mode takes the same query parameters: `token`, `size`, `width`, `height`, `format`, `theme`, `greyscale`, `retina`, `fallback`, and `redirect`. The [Get a logo reference](/docs/api-reference/logo-cdn/get-a-logo) lists each value and default. ## Related * [Errors](/docs/platform/errors): what each status code from the CDN means. * [Caching](/docs/platform/caching): how browsers cache a logo, and how to get a changed one. * [Troubleshooting](/docs/platform/troubleshooting): a white box, a monogram, or a blurry logo. * [Self-hosting](/docs/platform/self-hosting): to store a logo file on your server, use the Logo.dev API with a secret key, not the CDN. # Get company logos by ISIN Source: https://www.logo.dev/docs/logo-images/isin Get company logos by International Securities Identification Number (ISIN). The Logo.dev CDN maps the ISIN to the issuer's domain and returns its logo. Use an ISIN lookup when your data identifies securities by International Securities Identification Number, such as in a fund holdings list. ```html theme={null} Apple logo ``` ISIN logo preview Enter ISIN ## How an ISIN resolves The CDN maps the ISIN to the domain of the company that issued the security, then returns that company's logo. An ISIN has 12 characters: a two-letter country code, a nine-character national identifier, and a check digit. Case does not matter. To get the brand's name and domain for an ISIN, or to store the logo file, call [Brand](/docs/brand/introduction) on your server: `GET /v2/brands?isin=US0378331005`. For the other parameters and the fallback behavior, see the [Logo.dev CDN overview](/docs/logo-images/introduction#parameters). # Get market index logos by symbol Source: https://www.logo.dev/docs/logo-images/market-index Get the logo of a market index, such as the S&P 500, the NASDAQ Composite, or the FTSE 100, by its index symbol from a single image URL. Use an index lookup when you show a benchmark, such as in a market overview, a fund factsheet, or a performance chart. ```html theme={null} S&P 500 logo ``` market index symbol logo preview Enter market index symbol ## Index symbols Pass the index symbol. Case does not matter, and the `^` prefix that many market data feeds use is optional, so `SPX`, `spx`, and `^SPX` return the same logo. If you keep the prefix, URL-encode it as `%5E`. | Index | Path | | - | - | | S\&P 500 | `/index/SPX` or `/index/GSPC` | | Dow Jones Industrial Average | `/index/DJI` | | NASDAQ Composite | `/index/IXIC` | | NASDAQ 100 | `/index/NDX` | | Russell 2000 | `/index/RUT` | | FTSE 100 | `/index/FTSE` | | Nikkei 225 | `/index/N225` | | Cboe Volatility Index | `/index/VIX` | ## How an index resolves The CDN maps the symbol to the domain of the company that publishes the index, then returns that company's logo. Indexes from the same publisher return the same logo. For example, `SPX` and `DJI` both return the S\&P Global logo. When a symbol matches no stock, a [stock ticker lookup](/docs/logo-images/ticker) tries it as an index symbol, so `/ticker/SPX` returns the same logo as `/index/SPX`. If you know the symbol is an index, use `/index/`, because a stock with the same symbol takes priority on `/ticker/`. An index symbol that Logo.dev does not know returns `400 Bad Request`, not a monogram, whatever `fallback` is set to. See [Errors](/docs/platform/errors#logo-cdn-status-codes). For the other parameters, see the [Logo.dev CDN overview](/docs/logo-images/introduction#parameters). # Get logos by brand name Source: https://www.logo.dev/docs/logo-images/name Get brand logos by company name when you don't have a domain. The Logo.dev CDN searches for the brand and returns the logo of the top match. Use a name lookup when you have a brand name but no domain, such as in a customer list or a spreadsheet. ```html theme={null} Shopify logo ``` brand name logo preview Enter brand name ## How a name resolves The CDN searches the same index as [Search](/docs/brand-search/introduction) and returns the logo for the domain of the top result. If a name is ambiguous, call Search on your server, let the user pick the right brand, and store its domain. Then use a [domain lookup](/docs/logo-images/get). ## URL-encode brand names Encode a name that has spaces or special characters. A single word without special characters needs no encoding, but encoding it does no harm. | Name | Path | | - | - | | `trader joes` | `/name/trader%20joes` | | `AT&T` | `/name/AT%26T` | | `The Home Depot` | `/name/The%20Home%20Depot` | In JavaScript, use `encodeURIComponent()`: ```javascript theme={null} const logoUrl = `https://img.logo.dev/name/${encodeURIComponent("american express")}?token=${publishableKey}`; ``` ## Choose a match strategy The `strategy` parameter controls how the CDN picks the top result: * `match` (the default) picks the brand whose name is closest to your query. * `suggest` picks the most popular brand whose name starts with your query. Use it for partial input, such as text from an autocomplete field. An unknown `strategy` value returns `400`. `suggest` uses the same prefix matching as `method=typeahead` in [Search](/docs/brand-search/introduction). ```html theme={null} Brand logo ``` For the other parameters and the fallback behavior, see the [Logo.dev CDN overview](/docs/logo-images/introduction#parameters). # Get company logos by stock ticker Source: https://www.logo.dev/docs/logo-images/ticker Stock logo API: get company logos by ticker symbol across NYSE, NASDAQ, and global exchanges, with standard size, format, and fallback image options for apps. Use a ticker lookup when you have a stock symbol, such as in a brokerage, a portfolio tracker, or a market dashboard. ```html theme={null} Apple logo ``` stock ticker logo preview Enter stock ticker The CDN maps a recognized ticker to the company's domain. A ticker lookup and a [domain lookup](/docs/logo-images/get) for the same company return the same logo. ## Exchange suffixes A symbol with no suffix resolves against US exchanges: NYSE, NASDAQ, NYSE American, Cboe, OTC, and Pink Sheets. For a listing on another exchange, add a dot and the exchange shortcode: | Company | Path | | - | - | | Apple on NASDAQ | `/ticker/AAPL` | | AstraZeneca on the London Stock Exchange | `/ticker/AZN.L` | | Toyota on the Tokyo Stock Exchange | `/ticker/7203.T` | Common exchange codes also work as suffixes. For example, `AZN.LSE` resolves like `AZN.L`, and `SAP.XETRA` resolves like `SAP.DE`. Some markets have several exchanges, such as Germany. In those markets, if the symbol is not listed on the exchange you name, the CDN also checks the market's other exchanges. ## Exchange shortcodes | Shortcode | Exchange | Country | | - | - | - | | None | US exchanges (NYSE, NASDAQ, NYSE American, Cboe, OTC, Pink Sheets) | United States | | .TO | Toronto Stock Exchange | Canada | | .V | TSX Venture Exchange | Canada | | .CN | Canadian Securities Exchange | Canada | | .NE | Cboe Canada | Canada | | .MX | Mexican Stock Exchange | Mexico | | .SA | B3 Brazil Stock Exchange | Brazil | | .BA | Buenos Aires Stock Exchange | Argentina | | .SN | Santiago Stock Exchange | Chile | | .CL | Colombia Stock Exchange | Colombia | | .L | London Stock Exchange | United Kingdom | | .IL | International Order Book | United Kingdom | | .AQ | Aquis Stock Exchange | United Kingdom | | .IR | Euronext Dublin | Ireland | | .PA | Euronext Paris | France | | .AS | Euronext Amsterdam | Netherlands | | .BR | Euronext Brussels | Belgium | | .LS | Euronext Lisbon | Portugal | | .MC | Bolsa de Madrid | Spain | | .MI | Borsa Italiana | Italy | | .DE | Xetra | Germany | | .F | Frankfurt Stock Exchange | Germany | | .SG | Stuttgart Stock Exchange | Germany | | .DU | Dusseldorf Stock Exchange | Germany | | .HM | Hamburg Stock Exchange | Germany | | .BE | Berlin Stock Exchange | Germany | | .MU | Munich Stock Exchange | Germany | | .SW | SIX Swiss Exchange | Switzerland | | .VI | Vienna Stock Exchange | Austria | | .ST | Nasdaq Stockholm | Sweden | | .OL | Oslo Stock Exchange | Norway | | .CO | Nasdaq Copenhagen | Denmark | | .HE | Nasdaq Helsinki | Finland | | .IC | Nasdaq Iceland | Iceland | | .TL | Nasdaq Tallinn | Estonia | | .RG | Nasdaq Riga | Latvia | | .WA | Warsaw Stock Exchange | Poland | | .PR | Prague Stock Exchange | Czech Republic | | .BD | Budapest Stock Exchange | Hungary | | .AT | Athens Stock Exchange | Greece | | .IS | Borsa Istanbul | Turkey | | .ME | Moscow Exchange | Russia | | .T | Japan Exchange Group | Japan | | .HK | Hong Kong Stock Exchange | Hong Kong | | .SS | Shanghai Stock Exchange | China | | .SZ | Shenzhen Stock Exchange | China | | .TW | Taiwan Stock Exchange | Taiwan | | .TWO | Taipei Exchange | Taiwan | | .KS | Korea Exchange | South Korea | | .KQ | KOSDAQ | South Korea | | .NS | National Stock Exchange of India | India | | .BO | BSE | India | | .SI | Singapore Exchange | Singapore | | .BK | Stock Exchange of Thailand | Thailand | | .JK | Indonesia Stock Exchange | Indonesia | | .KL | Bursa Malaysia | Malaysia | | .VN | Ho Chi Minh City Stock Exchange | Vietnam | | .AX | Australian Securities Exchange | Australia | | .NZ | New Zealand Exchange | New Zealand | | .TA | Tel Aviv Stock Exchange | Israel | | .SR | Saudi Exchange | Saudi Arabia | | .AE | Dubai Financial Market & Abu Dhabi Securities Exchange | UAE | | .QA | Qatar Stock Exchange | Qatar | | .KW | Boursa Kuwait | Kuwait | | .CA | Egyptian Exchange | Egypt | | .JO | Johannesburg Stock Exchange | South Africa | For the other parameters and the fallback behavior, see the [Logo.dev CDN overview](/docs/logo-images/introduction#parameters). For a cryptocurrency, use the [crypto lookup](/docs/logo-images/crypto). # Choose your client Source: https://www.logo.dev/docs/mcp/clients Set up the Logo.dev MCP server in your AI client. > [card] [Claude Code](/docs/mcp/clients/claude-code) > [card] [Claude Desktop and web](/docs/mcp/clients/claude) > [card] [Cursor](/docs/mcp/clients/cursor) > [card] [VS Code](/docs/mcp/clients/vs-code) > [card] [Codex](/docs/mcp/clients/codex) > [card] [Other clients](/docs/mcp/clients/other) # Claude Desktop and web Source: https://www.logo.dev/docs/mcp/clients/claude Add Logo.dev as a custom connector in Claude. ## Set up 1. In Claude, open **Settings**, then **Connectors**. 2. Select **Add custom connector**. 3. Enter the name `Logo.dev` and the URL `https://mcp.logo.dev/mcp`, then select **Add**. 4. Select **Connect**, and sign in to Logo.dev in the browser window that opens. The connector works in Claude Desktop and on the web. ## Try it Ask your agent for brand data in plain words: Look up a brand and use its colors. Use Logo.dev to look up the brand for the ticker AAPL. Give me its name, its domain, and its brand colors in hex. # Claude Code Source: https://www.logo.dev/docs/mcp/clients/claude-code Connect Claude Code to the Logo.dev MCP server. ## Set up 1. Add the server in your terminal: ```bash theme={null} claude mcp add --transport http logo-dev https://mcp.logo.dev/mcp ``` 2. Start Claude Code and run `/mcp`. 3. Select **logo-dev**, then select **Authenticate**. 4. Sign in to Logo.dev in the browser window that opens. ## Try it Ask your agent for brand data in plain words: Look up a brand and use its colors. Use Logo.dev to look up the brand for the ticker AAPL. Give me its name, its domain, and its brand colors in hex. # Codex Source: https://www.logo.dev/docs/mcp/clients/codex Connect the Codex CLI to the Logo.dev MCP server. ## Set up 1. Add the server in your terminal: ```bash theme={null} codex mcp add logo-dev --url https://mcp.logo.dev/mcp ``` 2. Start the sign-in, then sign in to Logo.dev in the browser window that opens: ```bash theme={null} codex mcp login logo-dev ``` ## Try it Ask your agent for brand data in plain words: Look up a brand and use its colors. Use Logo.dev to look up the brand for the ticker AAPL. Give me its name, its domain, and its brand colors in hex. # Cursor Source: https://www.logo.dev/docs/mcp/clients/cursor Connect Cursor to the Logo.dev MCP server. ## Set up 1. Add the server to `~/.cursor/mcp.json`, or to `.cursor/mcp.json` in a project: ```json theme={null} { "mcpServers": { "logo-dev": { "url": "https://mcp.logo.dev/mcp" } } } ``` 2. Open **Cursor Settings**, then **Tools & MCP**. 3. Next to **logo-dev**, select **Connect**, and sign in to Logo.dev in the browser window that opens. ## Try it Ask your agent for brand data in plain words: Look up a brand and use its colors. Use Logo.dev to look up the brand for the ticker AAPL. Give me its name, its domain, and its brand colors in hex. # Other clients Source: https://www.logo.dev/docs/mcp/clients/other Connect any MCP client that supports streamable HTTP and OAuth to Logo.dev. Any MCP client that supports the streamable HTTP transport and OAuth sign-in can connect. Give it these settings: | Setting | Value | | - | - | | URL | `https://mcp.logo.dev/mcp` | | Transport | Streamable HTTP | | Authorization | OAuth. The client finds the sign-in details at `https://mcp.logo.dev/.well-known/oauth-protected-resource`. | A client that only supports stdio, or that needs an API key in its configuration, cannot connect. # VS Code Source: https://www.logo.dev/docs/mcp/clients/vs-code Connect GitHub Copilot in VS Code to the Logo.dev MCP server. ## Set up 1. Add the server to `.vscode/mcp.json` in your workspace: ```json theme={null} { "servers": { "logo-dev": { "type": "http", "url": "https://mcp.logo.dev/mcp" } } } ``` 2. In `mcp.json`, select **Start** above the server. 3. Allow the sign-in when VS Code asks, and sign in to Logo.dev in the browser window that opens. 4. Open Copilot Chat in **Agent** mode to use the tools. ## Try it Ask your agent for brand data in plain words: Look up a brand and use its colors. Use Logo.dev to look up the brand for the ticker AAPL. Give me its name, its domain, and its brand colors in hex. # Logo.dev MCP server Source: https://www.logo.dev/docs/mcp/introduction Connect Claude, Cursor, VS Code, Codex, or any MCP client to Logo.dev, and let your agent look up brands, logos, and brandmarks. The Logo.dev MCP server gives AI agents the Logo.dev API as tools. Your agent can look up a brand by domain, ticker, ISIN, crypto symbol, or name, fetch its logo or brandmark, search brands, and manage webhook subscriptions. ```text theme={null} https://mcp.logo.dev/mcp ``` ## Transport and sign-in The server uses the streamable HTTP transport and signs you in with OAuth. The first time you connect, your MCP client opens a browser window where you sign in to Logo.dev. You don't put a secret key in the client's configuration. Each tool runs as, and bills to, your team. If you have no team, it runs as your personal account. You don't need to create an API key for MCP. Each tool has the same access checks, [rate limits](/docs/platform/rate-limits), and [webhook subscription](/docs/webhooks#subscriptions) behavior as the REST route it mirrors. Tool calls count as MCP usage, which spends API credits at the same rates as REST requests. ## Docs for AI tools To give an AI tool all of the docs in one file, use [llms-full.txt](https://www.logo.dev/docs/llms-full.txt). ## Next steps > [card] [Choose your client](/docs/mcp/clients) > > Connect Claude, Cursor, VS Code, Codex, or another client. > [card] [Tools](/docs/mcp/tools) > > See every tool, its arguments, and what it returns. > [card] [Revoke access](/docs/mcp/revoke-access) > > Disconnect a client from your account. # Revoke access Source: https://www.logo.dev/docs/mcp/revoke-access Disconnect an MCP client from your Logo.dev account. To stop a client from using your account, revoke its access in the dashboard: 1. Open the [MCP page](https://www.logo.dev/dashboard/mcp) in the Logo.dev dashboard. 2. Under **Connected apps**, find the client. 3. Open the menu on its row, and select **Revoke access**. The client loses access to your account, and it has to sign in again to reconnect. On a team, a team admin can revoke any member's connected app from the team page. The MCP page lists the clients that you connected while signed in to the current team. If the client is not listed, switch to the team that you used when you connected it. # Tools Source: https://www.logo.dev/docs/mcp/tools Every Logo.dev MCP tool, the REST route it mirrors, its arguments, and what it returns. Every `/v2` Logo.dev API route has a tool. Read tools are named for what they return. Tools that change something are named for the action. | Tool | REST route | Does | | - | - | - | | `search` | `GET /v2/search` | Finds candidates by name | | `brand` | `GET /v2/brands` and `GET /v2/brands/{id}` | Looks a brand up by one identifier, or gets it by id | | `logo` | `GET /v2/brands/logo` | Gets a brand's logo image | | `brandmark` | `GET /v2/brands/brandmark` | Gets a brand's brandmark image | | `subscription` | `GET /v2/brands/{id}/subscription` | Gets your subscription to a brand | | `subscribe` | `PUT /v2/brands/{id}/subscription` | Subscribes you to a brand | | `unsubscribe` | `DELETE /v2/brands/{id}/subscription` | Stops a brand's update events | | `create_webhook_endpoint` | `POST /v2/webhook_endpoints` | Registers a URL for deliveries | | `webhook_endpoints` | `GET /v2/webhook_endpoints` | Lists your endpoints | | `webhook_endpoint` | `GET /v2/webhook_endpoints/{id}` | Gets one endpoint | | `update_webhook_endpoint` | `PATCH /v2/webhook_endpoints/{id}` | Changes an endpoint | | `delete_webhook_endpoint` | `DELETE /v2/webhook_endpoints/{id}` | Deletes an endpoint | | `webhook_endpoint_secret` | `GET /v2/webhook_endpoints/{id}/secret` | Gets an endpoint's signing secret | | `rotate_webhook_endpoint_secret` | `POST /v2/webhook_endpoints/{id}/secret` | Replaces an endpoint's signing secret | | `account` | `GET /v2/account` | Gets your plan and API credit balances | | `flag` | `POST /v2/flag` | Submits domains for review | ## Arguments Tool arguments match the REST parameters: * `search` takes `q`, `method`, and `limit`. * `brand`, `logo`, and `brandmark` take exactly one identifier: `domain`, `ticker`, `isin`, `crypto`, or `name`. `brand` also takes `brand_id`, in place of the REST path id, and `nosubscribe`. * `subscription`, `subscribe`, and `unsubscribe` take `brand_id`. * `webhook_endpoints` takes no arguments. The other endpoint tools take `id`, and `create_webhook_endpoint` and `update_webhook_endpoint` take the endpoint fields described in [Webhooks](/docs/webhooks#endpoints). * `account` takes no arguments. `flag` takes `domains`, `reason`, and `comment`. ```json theme={null} { "ticker": "AAPL", "nosubscribe": true } ``` ## Results Tools return the same `data` and `metadata` as the REST routes, including `metadata.request_id`, but no response headers: API credit and rate-limit details are REST-only. * A lookup that is still indexing returns `{"object": "brand", "status": "not_indexed"}` with `metadata.pending`, like a `202`. A brand that is not found returns `status: "not_found"`. * `logo` and `brandmark` return a tool error when there is no image to return. * `unsubscribe` returns the brand id and confirms you are not subscribed, whether or not you were before. * `delete_webhook_endpoint` returns `{ "id": "ep_...", "deleted": true }`, so the client can tell which endpoint was removed. * Over a rate limit, a tool returns an error telling the client to retry in a minute, or shortly for a concurrency limit. MCP calls draw on the same [allowance](/docs/platform/rate-limits#logo-api-rate-limits) as REST calls. Webhook events are delivered to your endpoints, not through the MCP connection. Use the subscription tools to start or stop `brand.updated` events. ## Access errors The server checks every request before any tool runs: * **No token, or an invalid or expired one:** `401` with a `WWW-Authenticate` header that points to `https://mcp.logo.dev/.well-known/oauth-protected-resource`. Your client reads it and starts the sign-in. * **Signed in, but the account can't use the API:** `403`. This happens when the account has no MCP access, is suspended, or is a personal account whose keys are switched off while you belong to a team. Tools then apply the same checks as their REST routes: * An account that is out of API credits gets a tool error instead of a `402`. * `subscribe`, `unsubscribe`, and the webhook endpoint tools need [webhooks](/docs/webhooks) turned on for the account. * At your plan's limit, `subscribe` and `create_webhook_endpoint` return a tool error that names the limit. A `brand` lookup at the subscription limit still returns the brand, but does not subscribe you to it. The [pricing page](https://www.logo.dev/pricing#compare) lists the limits for each plan. * Tools that change a webhook endpoint need the owner or admin role on the team. * `flag` needs the Pro plan or above. # Brandfetch Alternative: Logo.dev vs Brandfetch and Migration Source: https://www.logo.dev/docs/migrations/brandfetch Looking for a Brandfetch alternative? Compare Logo.dev and Brandfetch, then move cdn.brandfetch.io URLs, Brand API calls, and search to Logo.dev. Logo.dev and Brandfetch both turn a company identifier into a logo image URL and a JSON brand profile. Logo.dev starts from the image URL that you put in an `` tag. Brandfetch starts from the JSON brand profile. ## Logo.dev vs Brandfetch | | Logo.dev | Brandfetch | | - | - | - | | Logo image URL | [Logo.dev CDN](/docs/logo-images/introduction) at `img.logo.dev`, with a [publishable key](/docs/platform/api-keys) in `?token=` | Logo CDN at `cdn.brandfetch.io`, with a client ID in `?c=` | | Image lookup keys | Domain, [ticker](/docs/logo-images/ticker), [ISIN](/docs/logo-images/isin), [crypto symbol](/docs/logo-images/crypto), and [company name](/docs/logo-images/name) | Domain, ticker, ISIN, and crypto symbol | | Image formats | JPG, PNG, and WebP | WebP, PNG, JPG, and SVG | | Name to domain | [Search](/docs/brand-search/introduction) | Brand Search API | | Brand data | [Brand](/docs/brand/introduction): logo, brandmark, social banners, and colors | Brand API: logos, colors, fonts, and company details | | Plans and prices | [logo.dev/pricing](https://www.logo.dev/pricing) | Brandfetch's pricing page | Logo.dev fits when the logo image is the main thing you need. The publishable key is safe in client code, so the browser loads the logo from the URL and your code parses nothing. When you need more, [Brand](/docs/brand/introduction) returns the full profile from your server. Brandfetch fits when you need data that Logo.dev does not return, such as brand fonts or company details. It also fits when you need SVG files from the CDN. ## Map Brandfetch products to Logo.dev Logo images move to the Logo.dev CDN. Brand data and search move to the Logo.dev API. | Brandfetch | Logo.dev | Key | | - | - | - | | Logo CDN, `cdn.brandfetch.io` | [Logo.dev CDN](/docs/logo-images/introduction), `img.logo.dev` | Publishable key | | Brand API, `GET /v2/brands/domain/:domain` | [Brand](/docs/brand/introduction), `GET /v2/brands?domain=:domain` | Secret key | | Search API, `GET /v2/search/:name` | [Search](/docs/brand-search/introduction), `GET /v2/search?q=:name` | Secret key | > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. ## Migrate logo images Both CDNs build the logo from a URL. Change the host, change the credential, and rename the parameters: ```text theme={null} https://cdn.brandfetch.io/domain/nike.com/w/128/h/128?c=CLIENT_ID https://img.logo.dev/nike.com?size=128&format=png&token=LOGO_DEV_PUBLISHABLE_KEY ``` | Brandfetch | Logo.dev | | - | - | | `/domain/nike.com` | `/nike.com` | | `/ticker/NKE`, `/isin/:isin`, `/crypto/:symbol` | The same paths: [`/ticker`](/docs/logo-images/ticker), [`/isin`](/docs/logo-images/isin), [`/crypto`](/docs/logo-images/crypto) | | `?c=CLIENT_ID` | `?token=LOGO_DEV_PUBLISHABLE_KEY` | | `/w/128/h/128` | `size=128`, or `width` and `height` | | `/theme/dark` | `theme=dark` with `format=png`, with a different meaning. See the note below. | | `.png` or `.webp` extension | `format=png` or `format=webp` | | `/fallback/lettermark` | `fallback=monogram` | | `/fallback/404` | `fallback=404` | Add `format=png` or `format=webp` to every URL. The Logo.dev CDN returns JPG by default, and JPG has no transparency. Logo.dev's `theme` names the background you show the logo on, so `theme=dark` keeps a logo visible on a dark background. Set it from your own background color. Do not copy the Brandfetch value. The Logo.dev CDN returns one logo per company. For the wide lockup that Brandfetch calls the `logo` type, call [`GET /v2/brands/brandmark`](/docs/api-reference/logos/get-a-brandmark) from your server. [Every Logo.dev CDN parameter](/docs/api-reference/logo-cdn/get-a-logo) lists the full set. ## Migrate brand data Both Brand APIs return one JSON profile per brand and take a bearer token. Send your Logo.dev [secret key](/docs/platform/api-keys) instead of the Brandfetch key: ```bash theme={null} curl --header "Authorization: Bearer BRANDFETCH_API_KEY" \ "https://api.brandfetch.io/v2/brands/domain/nike.com" curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/brands?domain=nike.com" ``` To look up by ticker, ISIN, crypto symbol, or name, send `ticker`, `isin`, `crypto`, or `name` in place of `domain`. > [!NOTE] > > The Logo.dev profile has the name, description, colors, socials, logo, brandmark, and social banners. It does not have fonts, company size, or industry. If you use those Brandfetch fields, compare the [Brand response](/docs/brand/introduction) with your needs before you move that call. ## Migrate search Change the Brandfetch search path to the `q` parameter, and send your secret key: ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/search?q=nike" ``` [Search](/docs/brand-search/introduction) returns candidate domains, each with a logo URL. ## Attribution Some free-plan apps must show a link to Logo.dev. [Attribution](/docs/platform/attribution) explains who needs the link. For help with a migration or a volume test, email [sales@logo.dev](mailto:sales@logo.dev). # Clearbit Logo API Docs, Shutdown, and Replacement Source: https://www.logo.dev/docs/migrations/clearbit The Clearbit Logo API (logo.clearbit.com) shut down on December 8, 2025. See its old parameters mapped to Logo.dev, then move your URLs to img.logo.dev. > [!WARNING] > > The Clearbit Logo API shut down on December 8, 2025. URLs on `logo.clearbit.com` no longer return logos. HubSpot deprecated the Clearbit Logo API on March 18, 2025, and shut it down on December 8, 2025. HubSpot's [sunset notice](https://developers.hubspot.com/changelog/upcoming-sunset-of-clearbits-free-logo-api) recommends Logo.dev as the replacement. The team that built the Clearbit Logo API builds Logo.dev. To move, change the `logo.clearbit.com` host to `img.logo.dev` and add your publishable key. ## Clearbit Logo API reference The Clearbit Logo API returned an image from a URL with the company domain in the path. It needed no account or key. ```text theme={null} https://logo.clearbit.com/{domain}?size=128&format=png&greyscale=true ``` Each Clearbit parameter has a Logo.dev CDN equivalent: | Clearbit | What it did | Logo.dev | | - | - | - | | `/{domain}` | The company domain, after the host | `/{domain}` | | `size` | Width in pixels, default `128`. The height kept the aspect ratio. | `size`, default `128` | | `format` | `png` or `jpg`, default `png` | `format`: `jpg`, `png`, or `webp`, default `jpg` | | `greyscale` | `true` returned a greyscale logo | `greyscale=true` | | No key | | `token=LOGO_DEV_PUBLISHABLE_KEY`, required | Add `format=png` to keep transparent backgrounds, because the CDN returns JPG by default. [Every CDN parameter](/docs/api-reference/logo-cdn/get-a-logo) lists the full set. ## Map Clearbit calls to Logo.dev Pick the Logo.dev service by what your code does with the logo. | Your Clearbit code | Logo.dev service | Logo.dev call | | - | - | - | | Shows `logo.clearbit.com/:domain` in an image tag | [Logo.dev CDN](/docs/logo-images/introduction) | `https://img.logo.dev/:domain?token=LOGO_DEV_PUBLISHABLE_KEY` | | Downloads the logo on a server to store, email, or process | [Brand](/docs/brand/introduction) | `GET https://api.logo.dev/v2/brands/logo?domain=:domain` | | Turns a company name into a domain with Clearbit's autocomplete | [Search](/docs/brand-search/introduction) | `GET https://api.logo.dev/v2/search?q=:name` | ## Migrate logos you display **1. Get your publishable key** > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. Copy the key that starts with `pk_`. A [publishable key](/docs/platform/api-keys) is safe in client-side code. **2. Replace the host and add the key** Change `https://logo.clearbit.com/` to `https://img.logo.dev/`, and add your key as the `token` parameter: ```text theme={null} https://logo.clearbit.com/stripe.com?size=128 https://img.logo.dev/stripe.com?size=128&format=png&token=LOGO_DEV_PUBLISHABLE_KEY ``` ```html HTML theme={null} Stripe logo ``` ```jsx React theme={null} function CompanyLogo({ domain }) { return ( {`${domain} ); } ``` ```tsx Next.js theme={null} import Image from "next/image"; // unoptimized makes the browser load the logo from the CDN, not your server. function CompanyLogo({ domain }: { domain: string }) { return ( {`${domain} ); } ``` ```vue Vue theme={null} ``` ```kotlin Android theme={null} import com.squareup.picasso.Picasso fun loadCompanyLogo(domain: String, imageView: ImageView) { val url = "https://img.logo.dev/$domain?format=png&token=LOGO_DEV_PUBLISHABLE_KEY" Picasso.get().load(url).into(imageView) } ``` ```swift iOS theme={null} import SwiftUI struct CompanyLogo: View { let domain: String var body: some View { AsyncImage(url: URL(string: "https://img.logo.dev/\(domain)?format=png&token=LOGO_DEV_PUBLISHABLE_KEY")) { image in image.resizable().aspectRatio(contentMode: .fit) } placeholder: { ProgressView() } .frame(width: 128, height: 128) } } ``` **3. Check attribution** Some free-plan apps must show a link to Logo.dev. [Attribution](/docs/platform/attribution) explains who needs the link and where to put it. **4. Remove the old host** Search your codebase for `logo.clearbit.com` and replace every match. Then load a page that shows logos and check that each one appears. If a logo is wrong or out of date, [report it](https://www.logo.dev/update). ## Migrate logos you download If your server downloaded Clearbit images to store them, or to put them in a PDF, an email, or an OG image, call the Logo.dev API instead. Don't download images from the CDN for this. Send your [secret key](/docs/platform/api-keys) to `GET /v2/brands/logo`: ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/brands/logo?domain=stripe.com" ``` The response is JSON with a temporary download `url`. Download the file from that URL. [Self-hosting](/docs/platform/self-hosting) shows how to store logos and keep them current. ## Migrate name-to-domain lookups If you used Clearbit's company autocomplete to find a domain from a name, call the Search endpoint from your server: ```bash theme={null} curl --header "Authorization: Bearer LOGO_DEV_SECRET_KEY" \ "https://api.logo.dev/v2/search?q=stripe" ``` Each result has a `domain` and a `logo_url` you can show in a result list. See [Search](/docs/brand-search/introduction) for match and typeahead modes. ## What Clearbit did not have * [Stock ticker](/docs/logo-images/ticker), [ISIN](/docs/logo-images/isin), and [crypto symbol](/docs/logo-images/crypto) lookups on the CDN. * [Name lookups](/docs/logo-images/name) when you have a company name but no domain. * A `theme` parameter that keeps logos visible on dark backgrounds. Use it with `format=png` or `format=webp`. See [every CDN parameter](/docs/api-reference/logo-cdn/get-a-logo). * A full [brand profile](/docs/brand/introduction) with the brandmark, colors, and social banners. ## Coming from a different logo or favicon API? > [card] [Brandfetch](/docs/migrations/brandfetch) > > Compare Brandfetch with Logo.dev and move its CDN and Brand API calls. > [card] [Google Favicon API](/docs/google-favicon-api) > > The unofficial `google.com/s2/favicons` endpoint and its `sz` sizes. > [card] [DuckDuckGo Favicon API](/docs/duckduckgo-favicon-api) > > The `icons.duckduckgo.com` service: ICO only, no sizing. > [card] [Fey Logos](/docs/fey-logos) > > The shut-down Fey vector logo library and what replaced it. ## FAQs > [accordion] Was the Clearbit Logo API free? > > Yes. It needed no account or key. > [accordion] Do I need an API key? > > Yes. Unlike Clearbit's free endpoint, every CDN request needs a [publishable key](/docs/platform/api-keys) in the `token` parameter. The free plan does not need a credit card. > [accordion] What happens when Logo.dev has no logo for a domain? > > The CDN returns a generated monogram, so the image never breaks. To handle the miss yourself, see [fallback images](/docs/logo-images/introduction#fallback-images). > [accordion] Can I run Logo.dev next to Clearbit before I switch? > > Clearbit's endpoint no longer returns logos, so there is nothing to compare against. Test Logo.dev with your own domains on a free account. > [accordion] What does Logo.dev cost? > > Logo.dev has a free plan. See [pricing](https://www.logo.dev/pricing) for plans and [rate limits](/docs/platform/rate-limits) for how usage counts. > [accordion] Can I use Logo.dev in a commercial app? > > Yes. [Attribution](/docs/platform/attribution) explains when your plan needs a link to Logo.dev. > [accordion] How do I get help with the migration? > > Email [support@logo.dev](mailto:support@logo.dev) for technical help, or [sales@logo.dev](mailto:sales@logo.dev) for volume pricing and Enterprise plans. # API keys Source: https://www.logo.dev/docs/platform/api-keys Guide to Logo.dev API keys. Learn the difference between publishable and secret keys, domain restrictions, and how to implement authentication correctly. Logo.dev gives you two keys. The publishable key works only on the Logo.dev CDN and is safe in client code. The secret key works only on the Logo.dev API and stays on your server. > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. ## Test keys Logo.dev has no test or sandbox keys. Use your publishable and secret keys while you develop. The publishable key is safe in client code, so you can ship it in a browser or mobile build. ## Key types | | Publishable key (`pk_`) | Secret key (`sk_`) | | - | - | - | | Host | Logo.dev CDN (`img.logo.dev`) | Logo.dev API (`api.logo.dev`) | | Where it goes | The `token` query parameter | The `Authorization: Bearer` header | | Where to use it | Browser and app requests only | Your server only | Each key works on its own host only. A secret key on the CDN, or a publishable key on the API, returns [`401`](/docs/platform/errors#authentication-errors-401). ### Publishable key (`pk_`) Put the publishable key in the image URL: ```html theme={null} Nike logo ``` You can ship this key in client code. It cannot read brand data or spend API credits, because the API rejects it. To stop other sites from using it, turn on [domain restrictions](#domain-restrictions). A publishable key is for browser and app requests only, so server code uses the secret key with the Logo.dev API, as [self-hosting](/docs/platform/self-hosting) shows. ### Secret key (`sk_`) Send the secret key from your server on every API request: ```javascript theme={null} const response = await fetch("https://api.logo.dev/v2/search?q=nike", { headers: { Authorization: `Bearer ${process.env.LOGO_DEV_SECRET_KEY}`, }, }); ``` Never put this key in a browser, a mobile app, or a public repository. Anyone with it can spend your API credits. ## Domain restrictions Domain restrictions limit your publishable key to the sites you list. Logo.dev compares the host in each request's `Referer` header with your list. A request from any other host returns `401`. Secret key requests are not restricted. > [!WARNING] > > With domain restrictions on, a request with no `Referer` header returns `401`. Make sure your pages send the header before you turn restrictions on. ### Turn on domain restrictions **1. Open your key** Go to [API keys](https://www.logo.dev/dashboard/api-keys) in the dashboard and open your key. **2. Turn on the restriction** Turn on **Allowed domains only**. **3. Add your domains** Enter one domain per line. Add `localhost` if you develop locally. **4. Save** Click **Save and close**. ### Domain format * `example.com` matches `example.com` only. * `*.example.com` matches `example.com` and every subdomain, such as `app.example.com`. The match ignores the port and the path, so `localhost` covers `localhost:3000`. ### Make sure your pages send a Referer Browsers send the `Referer` header by default, but a strict `Referrer-Policy` removes it. These policies work with domain restrictions: | Policy | Works | Notes | | - | - | - | | `strict-origin-when-cross-origin` | Yes | The browser default. Sends the origin. | | `origin` | Yes | Always sends the origin. | | `origin-when-cross-origin` | Yes | Sends the origin cross-origin. | | `unsafe-url` | Yes | Sends the full URL. Not recommended. | | `no-referrer` | No | Never sends a referrer. | | `same-origin` | No | Sends a referrer to your own origin only. | To set the policy for a whole page, add a meta tag to the ``: ```html theme={null} ``` To set it for one image, use the `referrerpolicy` attribute: ```html theme={null} Stripe logo ``` In Next.js, set the header in `next.config.js`: ```javascript theme={null} module.exports = { async headers() { return [ { source: "/:path*", headers: [ { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" }, ], }, ]; }, }; ``` To test, open the **Network** tab in your browser's developer tools and load a page with a logo. Select an `img.logo.dev` request and confirm that its `Referer` header shows your domain. ## Key rotation To rotate your keys, create a new key pair and move your app to it: **1. Create new keys** On the [API keys](https://www.logo.dev/dashboard/api-keys) page, click **Create API keys**. **2. Deploy the new keys** Replace the old keys in your app and your server, then deploy. **3. Disable the old keys** Open the old key and click **Disable keys**. New requests with those keys fail at once. Logo images that browsers and the CDN already cached can still show until their [cache](/docs/platform/caching) expires. On a team, only an admin can create keys. If you cannot create keys, contact [support@logo.dev](mailto:support@logo.dev). # Attribution requirements Source: https://www.logo.dev/docs/platform/attribution Logo.dev attribution requirements: commercial use on the free plan needs a link back, personal projects don't. Placement rules and implementation. A commercial project on the free Community plan must show a visible link to Logo.dev. Personal projects and paid plans don't need one. See [pricing](https://www.logo.dev/pricing) for the plans. ## Who needs attribution | Plan | Commercial project | Personal project | | - | - | - | | Community (free) | Required | Not required | | Any paid plan | Not required | Not required | ## What counts as commercial A project is commercial if a company or an organization owns it, or if it makes money or intends to. A project that you own as an individual and that earns nothing is personal. Commercial projects include: * Products and sites that charge users, run ads, or sell anything * Startups, including pre-launch and pre-revenue * Internal tools at a company, such as dashboards, CRMs, and back-office apps * Client and agency work * Projects that an organization runs, including nonprofits Personal projects include: * Hobby and side projects with no revenue * Learning, tutorials, and classroom projects * Portfolios and personal sites * Open-source projects you maintain as an individual If you're unsure, [ask us](mailto:support@logo.dev). ## Add the link Add this link to your production site: ```html theme={null} Logos provided by Logo.dev ``` The link must be: * On your production site, not on staging or localhost. * On a page that anyone can open in a browser, without a login. * Visible to users, such as below a logo grid, in the page footer, or on an about page. Your API keys work on localhost and staging before you add the link. ## Verify the link **1. Submit your page** [Submit the public URL](https://www.logo.dev/dashboard/billing?section=attribution#attribution) of the page with the link. **2. Check the result** Logo.dev loads the page and looks for the link. The result shows in the same dashboard task. **3. Fix and resubmit if it fails** Fix the issue shown for your latest check, and submit the URL again. If a correct, public link still fails the check, [contact support](mailto:support@logo.dev). ## FAQs > [accordion] What if my app is behind a login? > > Add the link to a public page, such as the footer or the about page of your marketing site. > [accordion] What about native mobile apps? > > Add the link to your app's website or to your app store listing. # Caching Source: https://www.logo.dev/docs/platform/caching Understanding Logo.dev's automatic caching system. Browser caching headers, CDN optimization, and best practices for lightning-fast logo delivery. Browsers cache every Logo.dev CDN image for 24 hours. You don't need to configure anything. ## Browser caching Every logo the CDN serves carries this header: ```http theme={null} Cache-Control: max-age=86400, stale-while-revalidate=600 ``` * `max-age=86400` lets the browser reuse the logo for 24 hours without a new request. * `stale-while-revalidate=600` lets the browser show the cached logo for up to 10 minutes after it expires while it fetches a fresh copy in the background. Each user's browser keeps its own cache, so a repeat visit loads the logo from the device. ## Refreshing a changed logo When a company changes its logo, the new logo reaches your users as caches expire. Logo.dev's CDN revalidates in the background, and each browser fetches again when its 24-hour cache expires. The change can take somewhat longer than 24 hours to reach every user. To see the new logo now, add a query parameter with a new value to the URL. The browser treats the new URL as a new image and skips its cached copy: ```html theme={null} Stripe logo ``` Change the value, such as `v=3`, a deploy hash, or a date, each time you want a fresh copy. Each unique URL is a separate cache entry, so change it only when you need to. If the logo is still wrong after a refresh, [request an update](https://www.logo.dev/update). ## Load logos faster Preload a logo that appears above the fold: ```html theme={null} ``` Lazy load logos below the fold: ```html theme={null} Stripe logo ``` To store logos on your own infrastructure instead, see [self-hosting](/docs/platform/self-hosting). # Requests and responses Source: https://www.logo.dev/docs/platform/conventions Base URLs, keys, the response envelope, response headers, id and timestamp conventions, and versioning for the Logo.dev CDN and the Logo.dev API. Logo.dev serves brand assets from two hosts. Each host takes its own key and is billed on its own meter. | | Logo.dev CDN | Logo.dev API | | - | - | - | | Base URL | `https://img.logo.dev` | `https://api.logo.dev` | | Returns | A logo image | JSON | | Key | Publishable key (`pk_`) in the `token` query parameter | Secret key (`sk_`) in the `Authorization` header | | Where to call it | Anywhere, including the browser | Your server only | | Billing | Monthly CDN requests | [API credits](/docs/platform/credits) | See [API keys](/docs/platform/api-keys) for where each key goes, domain restrictions, and rotation. A CDN lookup with no logo returns a generated monogram, or a `404` with `fallback=404`. See [missing logos](/docs/platform/errors#missing-logos). Two services have their own host. The [Transaction](/docs/transaction/introduction) beta is at `https://www.logo.dev/api/transaction` and takes its own beta key. The [Logo.dev MCP](/docs/mcp/introduction) server is at `https://mcp.logo.dev/mcp` and signs you in with OAuth. The rest of this page covers `api.logo.dev`. ## The response envelope Every API response that has a body and is not an error has the same two fields. A successful delete returns `204` with no body. `data` holds the result, and `metadata` describes the request. The response looks like: ```json theme={null} { "data": { "object": "brand", "id": "brand_4x0wr3g0000g00400000000004", "...": "..." }, "metadata": { "request_id": "request_01k6z8m2a4b5c6d7e8f9g0h1j2", "resolution": { "type": "domain", "value": "stripe.com", "method": "direct", "context": {} } } } ``` | Field | Present on | Meaning | | - | - | - | | `data` | Every response with a body | The brand, image, search results, subscription, or webhook endpoint. Every object has an `object` field that names its type. | | `metadata.request_id` | Every response with a body | The request's id. It matches the `Request-Id` header. | | `metadata.resolution` | Brand and image lookups | The identifier you sent, its normalized value, and how it reached the brand. See [resolution](/docs/brand/introduction#resolution). | | `metadata.pending` | `202` responses | When to retry a lookup that is still indexing. See [still indexing](/docs/platform/errors#not-found-vs-still-indexing-202). | | `metadata.subscription` | Brand lookups from an account with webhooks on | What the automatic subscribe did. `status` is `subscribed`, or `quota_exceeded` when your account is at its subscription limit and this brand was not subscribed. `message` explains a `quota_exceeded`. See [subscriptions](/docs/webhooks#subscriptions). | A failed request returns an `error` object instead of the envelope. See [errors](/docs/platform/errors) for every code. ## Response headers | Header | Returned on | Meaning | | - | - | - | | `Request-Id` | Every response | The request's id. Include it when you contact support. | | `Credits-Charged` | Brand, image, and search requests | `1` when this request spent API credits, `0` when it was free under the [billing rules](/docs/platform/credits#what-is-billed). It is not the amount. Use `Credits-Remaining` to track your balance. | | `Credits-Remaining` | Brand, image, and search requests, when the balance is known | Your API credit balance after this request. Absent means unknown, not zero. | | `RateLimit-Limit` | Brand, image, and search requests | Requests allowed in the current window | | `RateLimit-Remaining` | Brand, image, and search requests | Requests left in the current window | | `RateLimit-Reset` | Brand, image, and search requests | Seconds until the window resets | | `Retry-After` | `202` responses | Seconds to wait before you retry | See [rate limits](/docs/platform/rate-limits) for how limits work, and [API credits](/docs/platform/credits) for what each request costs. ## Conventions * Timestamps are RFC 3339, in UTC. * Ids have a prefix that names what they point to: `brand_` for a brand, `sub_` for a subscription, `evt_` for a webhook event, `ep_` for a webhook endpoint, and `request_` for a request. Treat every id as opaque. * Store brand ids, not domains. A brand keeps its id when its domain changes. * Field names are snake\_case. A field with no value is `null`, maps omit absent keys, and an empty list is `[]`. ## Versioning The API version is in the path. Every route in this reference is under `/v2`. New fields and new routes can arrive inside `/v2`. A breaking change ships under a new prefix. The CDN is not versioned. The [v1 routes](/docs/api-reference/v1/get-a-brand-profile) keep working. v1 search spends API credits like v2 search, so it can return `402`. See the [changelog](/docs/changelog). Their v2 replacements differ in these ways: * Responses are wrapped in `data` and `metadata`, and errors use the `error` object. * `GET /v2/brands` replaces `GET /brand/{domain}` and `GET /describe/{domain}`. It also accepts a ticker, an ISIN, a crypto symbol, or a name. * Images are objects with a temporary download `url`, dimensions, format, and blurhash. They are not bare URLs. * Colors include OKLCH values next to RGB and hex. * `GET /v2/search` takes `method` (`match` or `typeahead`) instead of `strategy`, and adds `limit`. Every API route also has a tool on the [Logo.dev MCP](/docs/mcp/introduction) server. # CORS, canvas, and Content Security Policy Source: https://www.logo.dev/docs/platform/cors img.logo.dev sends Access-Control-Allow-Origin on every response, so you can draw logos on a canvas without a proxy. For OG images and PDFs, get the file from the Logo.dev API. Every response from `img.logo.dev` carries `Access-Control-Allow-Origin: *`. With `crossorigin="anonymous"` set, canvas calls such as `toDataURL()` work without a proxy. For OG images and PDFs that you render on the server, get the file from the Logo.dev API, and CORS does not apply. ## Draw a logo on a canvas A cross-origin image taints a ``. On a tainted canvas, `toDataURL()` and `getImageData()` throw a `SecurityError`. Set `crossorigin="anonymous"` so the browser makes a CORS request and the canvas stays clean: ```html theme={null} Stripe logo ``` In script, set `crossOrigin` before `src`: ```javascript theme={null} const img = new Image(); img.crossOrigin = "anonymous"; img.src = "https://img.logo.dev/stripe.com?token=LOGO_DEV_PUBLISHABLE_KEY"; img.onload = () => { ctx.drawImage(img, 0, 0); canvas.toDataURL(); // succeeds: the canvas is not tainted }; ``` ## Allow img.logo.dev in your Content Security Policy If your app sets a `Content-Security-Policy`, the browser blocks any image whose origin isn't in `img-src`. The image fires its `error` event, as a broken link does, and the console shows a CSP violation. Add `img.logo.dev` to `img-src`: ```http theme={null} Content-Security-Policy: img-src 'self' https://img.logo.dev; ``` Your server calls the API with a [secret key](/docs/platform/api-keys), not the browser. The API does not need a `connect-src` entry. ## Generate OG images and PDFs on the server Open Graph images (Satori, `@vercel/og`), PDF and screenshot rendering (Puppeteer, Playwright), and image processing (sharp) need the logo file on your server. Get the file from the API, not the CDN. `GET /v2/brands/logo` returns a download URL for the file. Store the file, and pass its bytes to the renderer. See [self-hosting](/docs/platform/self-hosting) for the code. > [card] [Use Logo.dev with Next.js](/docs/integrations/nextjs) > > Render `next/image` with `unoptimized` so the browser loads each logo. # API credits Source: https://www.logo.dev/docs/platform/credits What spends API credits, what each Logo.dev API request costs, how billing works, and what happens when you run out. > [!NOTE] > > **The short version** > > * API credits pay for the Logo.dev API (`api.logo.dev`) and the [Logo.dev MCP](/docs/mcp/introduction). > * The Logo.dev CDN (`img.logo.dev`) never uses API credits. It counts requests against your plan's monthly CDN allowance. > * Each request costs a set number of credits. See [what each request costs](#what-each-request-costs). > * With webhooks, you spend credits only on brands that changed, not on refreshing your whole list. > * Every plan includes API credits each month. Startup, Pro, and Enterprise can buy more. > * When you run out, API requests return `402`. We never bill for overage. ## What each request costs | Request | REST route | Credits | | - | - | - | | Brand | `GET /v2/brands`, `GET /v2/brands/{id}` | 5 | | Brandmark | `GET /v2/brands/brandmark` | 3 | | Logo | `GET /v2/brands/logo` | 2 | | Search | `GET /v2/search` | 1 per 1,000 searches | ## What is billed * Brand, brandmark, and logo requests are billed once per brand domain, per route, per 24 hours. * A brand that is found is billed, even if it has no image of the kind you asked for. * A brand that isn't found (`404`) or is still being indexed (`202`) is not billed, and neither are retries. * Search is billed on every request, including searches that find nothing. A search refused for the rate limit (`429`) is not billed. * Webhook endpoints, subscriptions, events, account reads (`GET /v2/account`), flags (`POST /v2/flag`), and downloads from the temporary image URLs in API responses are not billed. Those downloads don't count as CDN requests either. ## Webhooks and credits [Webhooks](/docs/webhooks) are on paid plans. You choose which brands to follow, up to your plan's limit. When a brand you follow changes, its `brand.updated` event lists what changed in `changed_attributes`. You decide what to request, and only that request spends credits: | What changed | What to request | Credits | | - | - | - | | `logo.etag` | Logo | 2 | | `brandmark.etag` | Brandmark | 3 | | Other data you store, such as `name` or `colors` | Brand | 5 | This costs far less than refreshing your whole list on a schedule. Refreshing 10,000 stored logos every month costs 20,000 credits a month. With webhooks, you spend 2 credits only when one of those logos changes. ## Included and purchased credits Every plan includes API credits each month. The [pricing page](https://www.logo.dev/pricing#compare) lists how many. Included credits renew on your billing date and don't roll over. On Startup, Pro, Enterprise, or a custom contract, the account owner can buy more on the [billing page](https://www.logo.dev/dashboard/billing), at \$10 per 1,000 credits, starting at \$5. Purchased credits never expire. Auto-reload can buy more when your balance runs low. Community accounts need to [upgrade](https://www.logo.dev/pricing) to buy credits. ## When you run out The API returns `402` with the code `insufficient_credits`, and the MCP returns a tool error. Requests work again when your included credits renew or you buy more. See [out of API credits](/docs/platform/errors#out-of-credits-402). The Logo.dev CDN isn't affected, and we never bill for overage. ## FAQs > [accordion] How do I estimate how many credits I need? > > Multiply your expected requests by each route's cost. For example: > > * Brand data for 2,000 new signups a month: 2,000 × 5 = 10,000 credits a month. > * Logos for 10,000 companies: 10,000 × 2 = 20,000 credits once. > * Name autocomplete with 200,000 searches a month: 200 credits a month. > > Repeats within 24 hours are free, so real usage is usually lower. > [accordion] Is a logo request and a brand request for the same company billed twice? > > Yes. They are different routes, and each route is billed once per brand domain per 24 hours. > [accordion] How do I check my balance? > > The [dashboard](https://www.logo.dev/dashboard) shows it. REST lookups and searches also return a `Credits-Remaining` header with your balance when it is known. `Credits-Charged` is `1` when a request spent credits and `0` when it was free. It is not the amount. See [response headers](/docs/platform/conventions#response-headers). > [accordion] Which credits are spent first? > > Your plan's included credits, then purchased credits. > [accordion] Does the Logo.dev MCP bill the same way? > > Yes. Each [MCP tool](/docs/mcp/tools) costs the same as its REST route, under the same rules. Each tool bills to your team, or to your personal account if you have no team. MCP tools return no credit headers, so check the dashboard. > [accordion] Do my teammates share my credits? > > Yes. A [team](/docs/platform/teams) shares one API credit balance, and only the owner can buy credits. > [accordion] Can a publishable key spend API credits? > > No. The Logo.dev API rejects publishable keys. Use a secret key on your server. See [API keys](/docs/platform/api-keys). > [accordion] Does the Transaction API use credits? > > Not during the beta. Each person gets 1,000 requests per UTC day. See [Transaction API](/docs/transaction/introduction). > [accordion] Does the deprecated v1 search use credits? > > Yes. `GET /search` is billed like `GET /v2/search`. # Errors and status codes Source: https://www.logo.dev/docs/platform/errors What each Logo.dev CDN and Logo.dev API status code means, the API error object, still-indexing 202 responses, missing logos, API credits, and rate limits. Logo.dev uses standard HTTP status codes. Branch on the status code, and on the `error.code` of a Logo.dev API error. Message text is for people and can change, so don't parse it. If a logo loads with a `200` but looks wrong, such as a white box, a monogram, or a blurry image, see [troubleshooting](/docs/platform/troubleshooting). ## Logo.dev CDN status codes `img.logo.dev` returns an image on success. An error body is a short JSON object with a `msg` or an `err` key, and a `docs_url` that links the relevant docs page. | Status | Meaning | What to do | | - | - | - | | `200` | The logo. For a lookup with no logo, a generated monogram, unless you set `fallback=404`. | Show the image. | | `202` | The first request for a domain Logo.dev is still fetching. The body is an image, cached for 5 minutes. | Show the image. Later requests return the logo. | | `400` | A malformed ticker, crypto symbol, exchange, or index, or an invalid parameter on `/isin` or `/name` | Fix the request. | | `401` | A missing, invalid, or disabled publishable key, or a request from a domain your key does not allow | See [authentication errors](#authentication-errors-401). | | `403` | The account is suspended, personal keys are off because you belong to a team, a Community account is paused for a few hours for abusive traffic, or your IP address is blocked | Contact [support](mailto:support@logo.dev), or use your team's keys. | | `404` | No logo, with `fallback=404` set. Also an invalid parameter value, such as `format=gif`, on the domain, ticker, crypto, exchange, and index routes. | Handle the [missing logo](#missing-logos), or fix the parameter. | | `429` | Over the Community plan's monthly or per-minute limit | On a per-minute limit, wait the seconds in `Retry-After`. See [Logo.dev CDN limits](/docs/platform/rate-limits#logo-cdn-limits). | | `500` | Logo.dev could not fetch the logo | Retry. | ## Logo.dev API status codes A failed request to `api.logo.dev` returns an `error` object and a `docs_url`. `target` names the parameter at fault when there is exactly one. ```json theme={null} { "error": { "code": "invalid_request", "message": "q is required", "target": "q" }, "docs_url": "https://www.logo.dev/docs/platform/errors" } ``` | Code | Status | Meaning | | - | - | - | | `invalid_request` | `400` | A parameter is missing or malformed | | `insufficient_credits` | `402` | The account is out of API credits. See [out of API credits](#out-of-credits-402). | | `forbidden` | `403` | Your account or role cannot do this. The identifier type is not enabled yet (such as `merchant`), webhooks are not turned on for the account, your role cannot change them, or your plan doesn't include the route (flagging needs Pro or above). Not billed. | | `limit_exceeded` | `409` | Your account is at its plan's limit on webhook endpoints or brand subscriptions. Delete one, or upgrade. See [plan limits](/docs/webhooks#plan-limits). | | `resource_missing` | `404` | The id matches nothing | | `rate_limited` | `429` | Over a per-minute limit, or over the limit on open lookups. Lookups and search have separate per-minute limits. Flags have their own per-minute limit. See [Logo.dev API rate limits](/docs/platform/rate-limits#logo-api-rate-limits). | | `internal` | `500` | Retry. If it persists, contact support with the `Request-Id` header. | A lookup that finds no brand is not an error. It returns `404` inside the normal envelope, with `data.status` set to `not_found`, and it is free. Every API response carries a `Request-Id` header. Include it when you contact support. See [response headers](/docs/platform/conventions#response-headers) for the rest. ## Authentication errors (`401`) Authentication runs before the route, so an authentication error has a `msg` field instead of an `error` object, on both hosts. That covers every `401`, and the `403` for a suspended account or for personal keys turned off by team membership. ```bash theme={null} curl -i "https://img.logo.dev/stripe.com" # HTTP/2 401 # {"docs_url":"https://www.logo.dev/docs/platform/api-keys","msg":"invalid api token. get an api token by creating an account at https://www.logo.dev/"} ``` A `401` has one of these causes: * The key is missing or does not exist. * The key is the wrong type for the host. See [API keys](/docs/platform/api-keys#key-types). * The key is disabled. * On the CDN, [domain restrictions](/docs/platform/api-keys#domain-restrictions) block the request. The message starts with `invalid referrer`. ## Not found vs. still indexing (`202`) An API lookup of a brand that Logo.dev has not indexed yet returns `202`, not `404`. Logo.dev starts to fetch the brand, which is usually ready within a minute. The response has a `Retry-After: 30` header and a `metadata.pending` object: ```json theme={null} { "data": { "object": "brand", "status": "not_indexed" }, "metadata": { "request_id": "request_01k6z8m2a4b5c6d7e8f9g0h1j2", "resolution": { "type": "domain", "value": "example.com", "method": "direct", "context": {} }, "pending": { "reason": "indexing", "message": "This brand is being indexed for the first time and is usually ready within a minute. Retry the same request after 30 seconds; retries are not billed.", "retry_after_seconds": 30, "expires_in_seconds": 300, "webhook": true, "doc_url": "https://www.logo.dev/docs/platform/errors#not-found-vs-still-indexing-202" } } } ``` * `reason` is `indexing` during a brand's first crawl. The value `resolving` is reserved for a lookup that is still matching the identifier to a brand. * Retry the same request after `retry_after_seconds`. Retries are not billed. Stop after `expires_in_seconds`, which is 5 minutes. * If `webhook` is `true`, a [`brand.indexed`](/docs/webhooks#brand-indexed) event tells you when the lookup settles, so you can stop polling. A `404` with `data.status` set to `not_found` means no brand matches the identifier. ## Missing logos A CDN lookup with no logo returns `200` with a generated monogram, so the image never breaks. With `fallback=404`, it returns `404` instead, and you show your own image. See [fallback images](/docs/logo-images/introduction#fallback-images) for the pattern. ## Out of API credits (`402`) An API request returns `402` with the code `insufficient_credits` when your API credit balance is below the request's cost. Retrying does not help. Requests work again after you add API credits or your monthly grant renews. See [API credits](/docs/platform/credits#included-and-purchased-credits) for how to add them. # Fair use guidelines Source: https://www.logo.dev/docs/platform/fair-use Logo.dev fair use policy and acceptable use guidelines. Learn what's allowed, best practices, and how to stay compliant while building with our logo API. These guidelines apply to every plan. Use Logo.dev to add logos to a product that does more than show logos. If we see a clear violation, we contact you before we take any action, such as turning off your keys. ## Fair use * Show logos in your application, such as next to customer records in a CRM. * Enrich customer data with logos. * Build directories that list companies. * Add logos to dashboards and reports. * Use logos in presentations. * Add company logos to email signatures. ## Not fair use * A competing logo API, or an API that proxies Logo.dev requests. * A server that fetches `img.logo.dev` images and passes them on to your users. To serve logos from your own servers, get them through the Logo.dev API. See [self-hosting](/docs/platform/self-hosting). * A logo search or logo download tool as your main product. * Bulk scraping of logos for redistribution. * Resale of Logo.dev data without transformation. * A claim of ownership of the logos you get. ## How to request logos * Load Logo.dev CDN images in your users' browsers and apps. Don't fetch them from a script or a crawler. * To store logos yourself, download them through the Logo.dev API. See [self-hosting](/docs/platform/self-hosting). ## Trademarks * Logos remain the property of their trademark owners. * Use a logo to identify a brand, not to imply endorsement. * Don't register trademarks on logos you get from Logo.dev. Commercial projects on the Community plan also need [attribution](/docs/platform/attribution). ## Questions If you're unsure whether your use case is fair use, [contact us](mailto:support@logo.dev). # Rate limits Source: https://www.logo.dev/docs/platform/rate-limits Logo.dev limits by plan: monthly CDN requests and per-minute caps on the Logo.dev CDN, and per-minute and concurrency limits on the Logo.dev API. Logo.dev meters the Logo.dev CDN and the Logo.dev API separately. CDN requests draw on a monthly allowance. Requests to the API spend [API credits](/docs/platform/credits), and lookups and search also have per-minute limits. The [pricing page](https://www.logo.dev/pricing#compare) lists the allowance, the API credit grant, and the limits for each plan. We email you before you reach a monthly limit. ## Logo.dev CDN limits Every request to `img.logo.dev` counts as one CDN request. Requests that return `403` or `429` don't count. On the Community plan, the monthly allowance is a hard cap. Past it, requests return `429` until the allowance resets at the start of the next month, or until you upgrade. The Community plan also has a per-minute limit for the account and for each IP address. The IP limit is shared by every Community key used from that address. Over either limit, the response is `429` with a `Retry-After` header that gives the seconds to wait. On paid plans, the CDN has no per-minute limit, and the monthly allowance is soft. Your logos keep loading if you go over, and we ask about a higher plan if it becomes a pattern. We never move you to a higher plan or bill you automatically. [Fair use](/docs/platform/fair-use) still applies on every plan. If logos stop loading and we have not emailed you, a limit is not the cause. See [troubleshooting](/docs/platform/troubleshooting#logo-doesnt-render-at-all). ## API credits Requests to the Logo.dev API spend API credits. See [API credits](/docs/platform/credits) for what each request costs, what is billed, and what happens when you run out. ## Logo.dev API rate limits The API has separate pools of limits for lookups, search, and flags. Pro, Enterprise, and custom contracts get higher lookup and search limits than the other plans. Every key on the account draws on the same pools. For a team key, the team is the account. [Logo.dev MCP](/docs/mcp/introduction) tool calls draw on the same limits as REST requests. Flags (`POST /v2/flag` and the MCP `flag` tool) are limited to 10 requests per minute per account. Other routes are not rate limited, but each plan [caps how many subscriptions and webhook endpoints you can have](/docs/webhooks#plan-limits). Brand and image lookups share two limits: requests per minute, and requests open at the same time. Every identifier type draws on the same limits. ### Search rate limit Search has its own per-minute limit, separate from the lookup limits. It applies to `GET /v2/search`, the deprecated v1 `GET /search`, and the MCP `search` tool. Search has no limit on open requests. A search refused for the rate limit is not billed. ### Handle a 429 Every lookup and search response, including a `429`, reports your per-minute window in the `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Reset` headers. A search response reports the search window. See [response headers](/docs/platform/conventions#response-headers). Over a limit, the response is `429` with the code [`rate_limited`](/docs/platform/errors#logo-api-status-codes). To recover: * If `RateLimit-Remaining` is `0`, you reached the per-minute limit. Wait `RateLimit-Reset` seconds, then retry. * Otherwise, you have too many lookups open. Send fewer requests in parallel, and retry with exponential backoff and jitter. ## FAQs > [accordion] Can I check my current usage? > > Your [dashboard](https://www.logo.dev/dashboard) shows your CDN requests and your API credit balance. On the API, the `Credits-Remaining` and `RateLimit-Remaining` headers report your balance and your window on each lookup and search. > [accordion] What if I go a little over for one month? > > On a paid plan, your logos keep loading, though it's a sign to upgrade. On the Community plan, the cap is firm, and requests stop until the next month's reset. > [accordion] What if I need more? > > For custom limits or higher volumes, [contact us](mailto:team@logo.dev). # Self-hosting logos Source: https://www.logo.dev/docs/platform/self-hosting Store Logo.dev logos on your own infrastructure: download them through the Logo.dev API, keep them in your storage or CDN, and refresh them only when they change. Self-hosting means you download logos from Logo.dev once and serve them from your own storage, such as S3, Google Cloud Storage, or your own CDN. Every plan can self-host the images that the Logo.dev API returns. Use the right surface for the job: | You need | Use | | - | - | | A logo on a website or in an app | The [Logo.dev CDN](/docs/logo-images/introduction). It hosts and caches the logo for you, so there is nothing to store. | | A logo file to store, put in a PDF, attach to an email, or process | The [Logo.dev API](/docs/brand/introduction#get-only-the-logo-or-the-brandmark). It returns a download URL for the file. | Don't download from the CDN to build your own copy. See [fair use](/docs/platform/fair-use). ## Download a logo `GET /v2/brands/logo` returns the logo as JSON with a temporary download `url` and an `etag`. Call it from your server with your [secret key](/docs/platform/api-keys), download the file, and store it: ```ts store-logo.ts theme={null} type StoredLogo = { domain: string; etag: string; path: string }; export async function storeLogo( domain: string, upload: (path: string, bytes: Uint8Array, contentType: string) => Promise, ): Promise { const res = await fetch( `https://api.logo.dev/v2/brands/logo?domain=${encodeURIComponent(domain)}`, { headers: { Authorization: `Bearer ${process.env.LOGO_DEV_SECRET_KEY}` } }, ); // 202 means the brand is still indexing: retry later. See /platform/errors. if (res.status !== 200) return null; const { data }: { data: { url: string; etag: string } } = await res.json(); const download = new URL(data.url); download.searchParams.set("format", "webp"); download.searchParams.set("size", "256"); const file = await fetch(download); // An expired URL or a failed download must not replace a good copy. if (!file.ok || !file.headers.get("content-type")?.startsWith("image/")) return null; const path = `logos/${domain}.webp`; await upload(path, new Uint8Array(await file.arrayBuffer()), "image/webp"); return { domain, etag: data.etag, path }; } ``` `upload` is your storage client's write call, such as S3 `PutObject`. The download URL expires, so store the file, not the URL. See [images](/docs/brand/introduction#images) for the download parameters. ## Keep your copies current Save each logo's `etag` with your copy. When you look the brand up again, download the file only if the `etag` changed. To learn when a logo changes without polling, subscribe to the brand's [`brand.updated`](/docs/webhooks#brand-updated) webhook, and download again when the event lists `logo` in its changed attributes. # Teams Source: https://www.logo.dev/docs/platform/teams Share one set of API keys, usage, and billing with your teammates. Roles, invitations, and how to leave or hand over a team. A team shares one set of API keys, one plan, one Logo.dev CDN allowance, and one API credit balance for the Logo.dev API. Manage the team on the [Team page](https://www.logo.dev/dashboard/team) in the dashboard. Every account starts as its own team, with you as the owner. > [!WARNING] > > When you join a team, your personal API keys stop working. Requests that use them fail from that moment with a `403` [authentication error](/docs/platform/errors#authentication-errors-401). Use the team's keys instead. Your personal keys work again when you leave the team or an admin removes you. ## Roles Each member of a team has one role. A team has one owner. | Action | Owner | Admin | Member | | - | - | - | - | | Use the team's publishable and secret keys | Yes | Yes | Yes | | See usage for keys you created | Yes | Yes | Yes | | See the team's total usage and plan limit | Yes | Yes | No | | See which member created each key | Yes | Yes | No | | Create API keys and change key settings | Yes | Yes | No | | Invite and remove members, and change roles | Yes | Yes | No | | Rename the team | Yes | Yes | No | | See the billing page | Yes | Yes | No | | Change the plan, payment method, and API credits | Yes | No | No | | Transfer ownership | Yes | No | No | The owner and admins can change a member to an admin, or an admin to a member. Nobody can change their own role or the owner's role. A team always keeps at least one admin, and the owner counts as one. API keys belong to the team, not to the member who created them. Key settings include [domain restrictions](/docs/platform/api-keys#domain-restrictions) and **Disable keys**. See [API keys](/docs/platform/api-keys) for how each key type works. ## Invite a member > [!NOTE] > > Invitations need a paid plan. On the free plan, the Team page shows **Bring in your team** with a link to plans instead. See [pricing](https://www.logo.dev/pricing) for what each plan includes. **1. Open the Team page** In the [dashboard](https://www.logo.dev/dashboard/team), open **Team** and click **Invite**. **2. Enter the details** Enter the person's email address, then select **Admin** or **Member**. **3. Send the invitation** Click **Invite** to send the invitation. Logo.dev emails the person an invitation link that expires after 7 days. You can't invite someone who is already a member or already has a pending invitation. **Pending invitations** lists each invitation and the time left before it expires. Click **Resend invitation** to send a new link that expires after 7 days. Click **Revoke invitation** to withdraw it. A revoked link stops working. ## Accept an invitation This section is for the person who got the invitation. Open the link in the invitation email. What you do next depends on your account: * **No Logo.dev account:** click **Create your account**. You join the team when you sign up. * **An account, signed out:** turn on the switch to confirm that joining disables your personal API keys. Click **Email a code to** your address, then enter the code. You join the team and go to the dashboard. * **An account, signed in with the invited email address:** turn on the same switch. Then click **Join** followed by the team name, for example **Join Acme**. While you are on the team, the dashboard shows **Your personal API keys are disabled**. You can't join while one of these is true: * If your own account has an active subscription, cancel it first. The team's plan covers you after you join. * If you are in another team that has other members, leave that team or transfer its ownership, then open the link again. * If you are in another team on a paid plan, cancel that team's plan first. > [!NOTE] > > If the link says the invitation expired or was withdrawn, ask a team admin to send a new one. If you are signed in with a different email address, sign out and open the link again. ## Remove a member The owner and admins can remove members. **1. Open the member's menu** In the [dashboard](https://www.logo.dev/dashboard/team), open **Team**. On the member's row, click the actions menu (**⋯**). **2. Remove the member** Click **Remove member**, then click **Remove member** again to confirm. The member loses access to the team's API keys and usage, and Logo.dev emails them. Their personal API keys work again. You can't remove these members: * Yourself. Ask another admin to remove you, or leave the team. * The owner. * The last admin. Make someone else an admin first. * A member whose account holds the team's API keys and billing. Email [support@logo.dev](mailto:support@logo.dev) to move the team first. ## Transfer ownership > [!NOTE] > > If the team started as your own account, **Transfer ownership** does not show. Email [support@logo.dev](mailto:support@logo.dev) to give that team to someone else. **1. Open the new owner's menu** In the [dashboard](https://www.logo.dev/dashboard/team), open **Team**. On the new owner's row, click the actions menu (**⋯**). **2. Transfer ownership** Click **Transfer ownership**, then click **Transfer ownership** again to confirm. The new owner takes over billing: the plan, the payment method, and API credits. The card on file stays until they change it. You stay on the team as an admin. Only the new owner can transfer ownership back. ## Leave a team **1. Open your menu** In the [dashboard](https://www.logo.dev/dashboard/team), open **Team**. On your own row, click the actions menu (**⋯**). **2. Leave the team** Click **Leave team**, then click **Leave team** again to confirm. You lose access to the team's API keys, usage, and billing. Your personal API keys work again. Logo.dev emails the owner. An admin can invite you back. **Leave team** is not available in these cases. The menu shows the reason. * If you own the team and it has other members, transfer ownership to another member first. If the team started as your own account, **Transfer ownership** does not show. Email [support@logo.dev](mailto:support@logo.dev) to move the team instead. * If you own the team and it has pending invitations, revoke them first. * If you are the last admin and other members are on the team or invited, make someone else an admin first. * If your account holds the team's API keys and billing, email [support@logo.dev](mailto:support@logo.dev) to move the team first. * If the team is your own account, there is no team to leave. # Troubleshoot logos: white box, monogram, blurry Source: https://www.logo.dev/docs/platform/troubleshooting Fix common Logo.dev display issues: a white box behind a logo, a monogram instead of the real logo, blurry images, the wrong logo, or a logo that won't render. Most logo problems are visual. The image loads with a `200` but doesn't look right. Find your symptom below. For status codes such as `401`, `403`, and `429`, see [errors and status codes](/docs/platform/errors). | Symptom | Cause | | - | - | | [White or colored box behind the logo](#white-or-colored-box-behind-the-logo) | The default `jpg` format is opaque | | [A monogram instead of the real logo](#a-monogram-instead-of-the-real-logo) | Logo.dev has no logo for that identifier | | [Blurry or low-resolution logo](#blurry-or-low-resolution-logo) | The size is larger than the source, or retina is off | | [Wrong logo for the company](#wrong-logo-for-the-company) | A cached old logo, or a record that needs an update | | [Logo doesn't render at all](#logo-doesnt-render-at-all) | Content Security Policy, or the key | | [`next/image` errors about the hostname](#nextimage-errors-about-the-hostname) | The image goes through the Next.js optimizer | ## White or colored box behind the logo The default format is `jpg`, which has no transparency. On a colored or dark surface, the logo sits on a white rectangle. Request `format=png` for a transparent background, and set `theme` to match your background: ```html theme={null} Stripe logo ``` See the [Get a logo reference](/docs/api-reference/logo-cdn/get-a-logo) for `format` and `theme`. ## A monogram instead of the real logo A monogram means Logo.dev has no logo for that identifier. The request did not fail. If the company should have a logo, [request an update](https://www.logo.dev/update). To show your own image instead of the monogram, see [fallback images](/docs/logo-images/introduction#fallback-images). ## Blurry or low-resolution logo Logos render up to 800 pixels, and a larger `size` is reduced to 800. A `size` larger than the source file upscales it, and the result looks soft. Request the size you display, and add `retina=true` to get a 2x image for high-density screens: ```html theme={null} Stripe logo ``` ## Wrong logo for the company If the company changed its logo recently, your browser can show the old one from its cache. See [refreshing a changed logo](/docs/platform/caching#refreshing-a-changed-logo). If the logo is outdated or belongs to another company, [request an update](https://www.logo.dev/update). ## Logo doesn't render at all Open the browser console. A line such as `Refused to load the image ... because it violates the following Content Security Policy directive` means your `Content-Security-Policy` blocks the image. Add `img.logo.dev` to your `img-src` directive. See [CORS, canvas, and Content Security Policy](/docs/platform/cors). If the request returns `401`, check the key and its domain restrictions. See [authentication errors](/docs/platform/errors#authentication-errors-401). ## next/image errors about the hostname `next/image` sends an image through the Next.js optimizer by default, and the optimizer rejects a hostname that you have not allowed. Add the `unoptimized` prop so the browser loads the logo from the CDN. Don't add `img.logo.dev` to `images.remotePatterns`, because the optimizer then fetches the logo on your server. See [Use Logo.dev with Next.js](/docs/integrations/nextjs). # Quickstart Source: https://www.logo.dev/docs/quickstart Display your first company logo with Logo.dev in under a minute. Get a publishable key and request a logo by domain from an image URL. In this quickstart, you put a company's logo on a page with an image URL. You need a free [Logo.dev account](https://www.logo.dev/signup). No credit card is required. **1. Copy your publishable key** > [card] [Get your API keys](https://www.logo.dev/dashboard/api-keys) > > Your dashboard has a publishable key for the Logo.dev CDN and a secret key for the Logo.dev API. Every plan includes both. Copy the key that starts with `pk_`. A [publishable key](/docs/platform/api-keys) is safe to use in client-side code. **2. Add the logo URL** Put the key in the `token` parameter of an `img.logo.dev` URL. Replace `LOGO_DEV_PUBLISHABLE_KEY` with your key, and use the URL where you would use any image: ```html HTML theme={null} Nike logo ``` ```jsx React theme={null} function CompanyLogo({ domain }) { return ( {`${domain} ); } ``` ```tsx Next.js theme={null} import Image from "next/image"; // unoptimized makes the browser load the logo from the CDN, not your server. // See https://www.logo.dev/docs/integrations/nextjs#skip-the-optimizer function CompanyLogo({ domain }: { domain: string }) { return ( {`${domain} ); } ``` ```vue Vue theme={null} ``` ```python Python theme={null} logo_url = f"https://img.logo.dev/nike.com?token=LOGO_DEV_PUBLISHABLE_KEY" ``` ```ruby Ruby theme={null} logo_url = "https://img.logo.dev/nike.com?token=LOGO_DEV_PUBLISHABLE_KEY" ``` ```php PHP theme={null} $logoUrl = "https://img.logo.dev/nike.com?token=LOGO_DEV_PUBLISHABLE_KEY"; ``` ```java Android theme={null} import android.widget.ImageView; import com.squareup.picasso.Picasso; public void loadCompanyLogo(String domain, ImageView imageView) { String url = "https://img.logo.dev/" + domain + "?token=LOGO_DEV_PUBLISHABLE_KEY"; Picasso.get() .load(url) .placeholder(R.drawable.logo_placeholder) .error(R.drawable.logo_error) .into(imageView); } ``` ```swift iOS theme={null} import SwiftUI struct CompanyLogo: View { let domain: String var body: some View { AsyncImage(url: URL(string: "https://img.logo.dev/\(domain)?token=LOGO_DEV_PUBLISHABLE_KEY")) { image in image .resizable() .aspectRatio(contentMode: .fit) } placeholder: { ProgressView() } .frame(width: 128, height: 128) } } ``` **3. Open the page** Load the page in your browser. You see the Nike logo: ![Nike logo](https://img.logo.dev/nike.com?token=live_6a1a28fd-6420-4492-aeb0-b297461d9de2) [https://img.logo.dev/nike.com?token=LOGO\_DEV\_PUBLISHABLE\_KEY](https://img.logo.dev/nike.com?token=LOGO_DEV_PUBLISHABLE_KEY) Change `nike.com` to any other domain to show that company's logo. ## Next steps > [card] [Logo.dev CDN](/docs/logo-images/introduction) > > Look up logos by ticker, ISIN, crypto symbol, or name, and set the size, format, and theme. > [card] [Use cases](/docs/use-cases/logo-from-domain) > > Live demos with working code: logo walls, autocompletes, and transaction feeds. # Delete your Logo.dev account and data Source: https://www.logo.dev/docs/support/delete-account Delete your Logo.dev account from the dashboard, see what deletion schedules for removal, and what we retain to meet billing and legal obligations. You can delete your account from the [dashboard](https://www.logo.dev/dashboard/settings). Deletion is permanent, and you cannot undo it. Your sign-in ends at once, and we remove your data as the deletion moves through our systems. ## Before you delete You cannot delete your account while one of these is true: * You have an active subscription. Cancel it in [Billing](https://www.logo.dev/dashboard/billing). The subscription stays active until the end of the period you paid for, and then you can delete the account. * You are the only admin of a team that still has other members or pending invites. Remove them or promote another admin first. * Your account is the shared account behind a team that still has other members or pending invites. Deletion would remove the team's keys and usage, so first email [support@logo.dev](mailto:support@logo.dev) to move the team to another account. ## Delete your account **1. Open Settings** In the [dashboard](https://www.logo.dev/dashboard/settings), open **Settings**. **2. Start the deletion** In the **Delete account** section, click **Delete**. **3. Confirm** Type `delete my account`, then click **Delete account**. We schedule your account for deletion and sign you out. ## What deletion removes Deletion removes your account details, your usage history, and any team you own that has no other members. Your sign-in ends at once. We revoke every publishable and secret key your account owns, usually within a few minutes. After that, new requests with those keys fail. Logo images that browsers and the CDN already cached can still show until their [cache](/docs/platform/caching) expires. To stop a key at once, disable it before you delete the account. Open [API keys](https://www.logo.dev/dashboard/api-keys), manage the key, and click **Disable keys**. Keys that belong to a team you are a member of are the team's keys. They stay active after you delete your account, and only a team admin can disable them. We also remove your email address from our sending lists, so you get no more product or account email. ## What we keep A narrow set of records survives deletion, as the [privacy policy](https://www.logo.dev/legal/privacy) describes: * Billing records, for as long as tax and accounting law requires. Stripe holds card details, and we never store full card numbers. * Request logs (the requesting IP address, the lookup, and a timestamp), which age out on our retention schedule for security monitoring and billing. * Account records, including your name and email, for a limited wind-down period after deletion to meet legal obligations. * Email preference and consent records, kept for a limited period to document your choices, and email delivery events, kept only as long as our email systems need them. When those periods end, the records are deleted too. ## Delete without signing in If you cannot sign in, email [support@logo.dev](mailto:support@logo.dev) from the address on the account and ask us to delete it. We may ask you to verify your identity. We then delete your data from the systems that hold it and reply to confirm. For readers in the EEA, the United Kingdom, and Switzerland, this is the right to erasure in the [privacy policy](https://www.logo.dev/legal/privacy). ## Next steps > [card] [Security and data handling](/docs/support/security) > > How Logo.dev handles data: the DPA, subprocessors, retention, and GDPR. > [card] [Privacy policy](https://www.logo.dev/legal/privacy) > > The binding terms on what we collect, retention by data type, and your > rights. # Getting help Source: https://www.logo.dev/docs/support/getting-help Contact Logo.dev support for help with API keys, integrations, and errors, or reach sales for volume pricing and premium endpoints. Email support for technical help and sales for plans and pricing. ## Technical support For API keys, integrations, errors, or anything that isn't working, email [support@logo.dev](mailto:support@logo.dev). For a fast answer, include: * The email on your Logo.dev account * The full request URL that failed * The brand or domain you were looking up * The HTTP status code you got back To report a logo that is wrong, out of date, or missing, use the [logo update form](https://www.logo.dev/update). ## Contact sales For volume pricing, higher limits, Enterprise plans, or access to the Transaction beta, email [sales@logo.dev](mailto:sales@logo.dev). # Logo.dev security: SOC 2, DPA, subprocessors, data retention Source: https://www.logo.dev/docs/support/security How Logo.dev protects data: SOC 2 Type I, encryption, access control, retention periods, the DPA, subprocessors, GDPR, and how to report a vulnerability. > [!NOTE] > > Logo.dev serves publicly available company logos and brand metadata. The > personal data we process is limited to account details, API request > metadata, billing (handled by Stripe), and website analytics. We process no > special-category data. This page gives the technical detail for a security or procurement review. For an overview, see [logo.dev/security](https://www.logo.dev/security). The binding terms are in our [privacy policy](https://www.logo.dev/legal/privacy), [DPA](https://www.logo.dev/legal/dpa), and [subprocessor list](https://www.logo.dev/legal/subprocessors). In a contract, refer to those documents, not to this summary. ## Compliance ### SOC 2 Logo.dev has a SOC 2 Type I report for the Security criteria, as of August 16, 2026. Johanson Group LLP, an independent CPA firm, issued it with an unqualified opinion. We are preparing for a SOC 2 Type II audit. To get the report, sign in and open [Billing](https://www.logo.dev/dashboard/billing) in the dashboard. It is under **Security and compliance**. Every plan, including free accounts, can download it. See [SOC 2](https://www.logo.dev/security/soc-2) for more. ### Data processing agreement Our [DPA](https://www.logo.dev/legal/dpa) is part of the Terms of Service. It applies to every customer when they accept the Terms, with no signature. It includes the EU Standard Contractual Clauses (Modules Two and Three), the UK Addendum, and the Swiss terms. A PDF copy is on the same Billing page, for your records. We don't sign customer-specific or country-specific DPAs. Changes to the DPA are available only on an Enterprise agreement. ### Subprocessors The [subprocessor list](https://www.logo.dev/legal/subprocessors) names each third party that processes data for us, what it does, and where. We announce a new or replacement subprocessor in the [changelog](/docs/changelog) at least 14 days before it processes personal data. To object, email [team@logo.dev](mailto:team@logo.dev) within those 14 days. ## Data protection ### What we process Logo.dev turns company identifiers into public brand assets, so most data in the API is not personal data. We process this personal data: * Account details: your name, email, and organization. * API request metadata: the IP address that sends the request, the domain or query you look up, a timestamp, and your account, team, and plan. * Billing: Stripe collects and processes payment details. We don't store full card numbers. * Website analytics: page and product usage, through PostHog. See the [privacy policy](https://www.logo.dev/legal/privacy) for the full list and the legal bases. ### Where data is processed Our infrastructure runs on AWS in the United States, mainly in `us-west-2` (Oregon). The [subprocessor list](https://www.logo.dev/legal/subprocessors) gives each provider's location. For users in the EEA, UK, and Switzerland, transfers rely on the Standard Contractual Clauses in our [DPA](https://www.logo.dev/legal/dpa). ### Encryption * In transit: TLS 1.2 or higher for all API and web traffic. * At rest: AES-256 for stored data. Our primary database is encrypted with keys we manage in AWS KMS. ### Retention | Data | Retention | | - | - | | API request logs (IP address, lookup, timestamp) | Deleted within 120 days | | Brand lookup records (account, team, plan, lookup, response) | Deleted within 90 days | | Security and audit logs | Deleted within 400 days. AWS audit logs are write-once for the first 365 days. | | Account data | Kept while your account exists, deleted when you delete the account | | Database backups | Primary database: 7 days. API key store: 35 days. | | Billing records | Kept as tax and accounting law requires | When you delete your account, we delete your account record and revoke your API keys at once. Copies in backups expire within 35 days. See [Delete your account](/docs/support/delete-account). ### GDPR We never sell personal data. We support these data-subject requests: access, correction, deletion, restriction, objection, and portability. The [privacy policy](https://www.logo.dev/legal/privacy) covers the legal bases and how to make a request. See [GDPR](https://www.logo.dev/security/gdpr) for common questions. ## Operational security ### Access control * Staff sign in to our systems through Google Workspace, with multi-factor authentication required. * Access follows least privilege, and we review it every year. ### Monitoring * AWS CloudTrail records infrastructure activity to write-once storage. * Amazon GuardDuty watches our AWS accounts for threats. * Dependabot flags vulnerable dependencies in our code. ### People and devices * Everyone with access completes security training when they join and every year after. * Work laptops use full-disk encryption, lock the screen automatically, and install updates automatically. ### Incident response We have a written incident response plan and test it every year. If a breach affects your personal data, we notify you without undue delay, as the [DPA](https://www.logo.dev/legal/dpa) requires. ## Enterprise flat file delivery Tell us which logo data you need, and we deliver it as a flat file on a schedule. You don't integrate an API. > [!TIP] > > Running air-gapped, or does your review rule out third-party API calls? > Email [team@logo.dev](mailto:team@logo.dev) and we'll set up flat file delivery. ## Report a vulnerability Email [security@logo.dev](mailto:security@logo.dev). See [responsible disclosure](https://www.logo.dev/security/responsible-disclosure) for what to include and what we commit to. For privacy or DPA questions, email [team@logo.dev](mailto:team@logo.dev). # Transaction: Identify a merchant Source: https://www.logo.dev/docs/transaction/introduction Identify a merchant domain and find its brand record from a merchant string and optional country code. Transaction turns a merchant name or card descriptor into a merchant: a display name, a confidence score, and a domain and brand id when it identifies one. Every non-empty input returns a row. > [!NOTE] > > Transaction is a private beta. [Contact sales](mailto:sales@logo.dev?subject=Transaction%20Enrichment%20API) to turn it on, then open the [Transaction Playground](https://www.logo.dev/dashboard/playground/transaction). Card descriptor matching is experimental. Test it with representative inputs before you depend on the results. A descriptor that contains several businesses can be ambiguous. The API returns no industry or spending category. [Identify a merchant](/docs/api-reference/transaction-enrichment-api/identify-a-merchant) is the reference for every field, value, and status code. This page explains how to use them. ## Get your beta key Access belongs to your Logo.dev account. When the beta is on, everyone on the account can use it. Each person has their own key. Copy yours from the [Transaction Playground](https://www.logo.dev/dashboard/playground/transaction), and keep it on your server. The key starts with `tx_beta_` and works only with Transaction. Your Logo.dev secret keys do not work here. To replace your key, select **Regenerate** in the playground. The old key stops working immediately. Your daily usage does not reset. ## Identify a merchant Send a `POST` request to `https://www.logo.dev/api/transaction` with the descriptor in `transaction`. `country_code` is optional. It is a hint for ambiguous names, not a filter. ```bash theme={null} curl --request POST "https://www.logo.dev/api/transaction" \ --header "Authorization: Bearer LOGO_DEV_TRANSACTION_KEY" \ --header "Content-Type: application/json" \ --data '{ "transaction": "Starbucks", "country_code": "US" }' ``` The response looks like this. The values are illustrative. ```json theme={null} { "domain": "starbucks.com", "name": "Starbucks", "entity_id": "brand_5k2mq8h0000g00400000000017", "logo_url": "https://img.logo.dev/starbucks.com", "parent": null, "intermediary": null, "status": "matched", "match_type": "resolved_entity", "confidence": 0.8 } ``` `logo_url` has no token. Add your [publishable key](/docs/platform/api-keys) before you show the logo: `https://img.logo.dev/starbucks.com?token=LOGO_DEV_PUBLISHABLE_KEY`. ## Read the row Every row has a `status`. Handle the two values differently. * **`matched`**: the API identified a merchant domain. Show `name` and the logo. * **`cleaned`**: the API tidied the descriptor into a display name and identified no merchant. `domain`, `entity_id`, and `logo_url` are `null`. Show `name` without a logo. A cleaned row is an answer, not an error. Code that checks `status === "matched"` covers every case, because the API returns no third status. ```json theme={null} { "domain": null, "name": "Helga Lefse Hut", "entity_id": null, "logo_url": null, "parent": null, "intermediary": null, "status": "cleaned", "match_type": "cleaned_descriptor", "confidence": 0.1 } ``` Three more fields tell you how far to trust the row and how to store it: * **Key your records on `entity_id`.** It is the merchant's Logo.dev brand id, the same id [Brand](/docs/brand/introduction) uses. A brand keeps its id when its domain changes, so a rebrand stays one merchant. * **Branch on `entity_id`, not on `confidence`.** A row with an id has two sources that agree: the pipeline identified the merchant, and Brand resolves a brand for the same domain. A `matched` row can still have a `null` id, for example when Logo.dev has not indexed the domain yet. * **Rank on `confidence`.** Use the score to sort a review queue or to hold the bottom of a batch for a person. Logo.dev publishes no cut-off and can recalibrate the score. `match_type` names the pipeline stage that produced the row. Read it from the row and do not predict it from the descriptor. The reference lists each value. ### Group by owner and by platform Two fields name companies that sit beside the merchant. Neither one replaces the merchant in `domain`. * `parent` is the company that owns the merchant. A lookup for Facebook returns Facebook, with Meta in `parent`. Group totals on `parent.entity_id` to add up one company's brands. Coverage is thin, so most rows return `null`. A `null` does not mean the merchant is independent. * `intermediary` is the platform the purchase ran through. A coffee paid through Square returns the coffee shop, with Square in `intermediary`. Group totals on `intermediary.entity_id` to add up spend by platform. Both objects have the same four fields as the merchant: `domain`, `name`, `entity_id`, and `logo_url`. ## Add transaction context (optional) Send `transaction_context` in these cases: * The account holder matters. Without context, the API does not detect people, so `Jane Doe` can match an organization with a similar name. * You need the platform named reliably. Without context, the API fills `intermediary` only for some prefixed descriptors, such as `SQ*`. Pass the real transaction values. The API fills in no placeholder values. ```bash theme={null} curl --request POST "https://www.logo.dev/api/transaction" \ --header "Authorization: Bearer LOGO_DEV_TRANSACTION_KEY" \ --header "Content-Type: application/json" \ --data '{ "transaction": "SQ* STARBUCKS 10 Union Sq", "country_code": "US", "transaction_context": { "date": "2026-09-04", "amount": 10, "currency": "USD", "entry_type": "outgoing", "account_holder": { "type": "consumer" } } }' ``` When you send the object, `date`, `amount`, `currency`, and `entry_type` are required. `account_holder` is optional. With context, the response adds `entity_type`: `person`, `organization`, or `null`. A person always comes back as a cleaned row. The merchant string, the context, and the account holder details go to Logo.dev's enrichment provider. The beta keeps no account history across lookups. ## Daily allowance Each person gets **1,000 requests per UTC day**, shared between the playground and their beta key. The allowance resets at midnight UTC. Beta requests do not spend [API credits](/docs/platform/credits). Every request that passes validation counts. This includes cleaned rows, provider errors, timeouts, and repeats served from a saved result. Invalid input and rejected keys do not count. A burst limit also applies: more than about 60 requests in one minute returns `429`. Each response that counts carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`. ## Handle errors Transaction does not use the [Logo.dev API error object](/docs/platform/errors). An error has one `error` string, for example `{"error":"Daily limit of beta requests reached"}`. The reference lists every status code with an example. * **`400`**: fix the request body. It does not count against your allowance. * **`401`**: check the key. A regenerated key replaces the old one. * **`403`**: the beta is not on for your account. Contact sales. * **`409`**: another request is already looking up the same transaction. Wait for the number of seconds in `Retry-After`, then retry to read the saved result. * **`429`**: wait for the number of seconds in `Retry-After`. * **`503`**: a dependency is unavailable. Retry later. The API returns this error instead of a cleaned row. ## Changes for existing callers The response shape changed during the beta: * **`status` no longer returns `not_found`.** Those rows now return `cleaned`. Code that checks for `not_found` matches nothing, so any fallback behind it stops running. * **`brand_url` and `verified` are gone.** `verified` was `true` exactly when `entity_id` is set. Test `entity_id` instead. * **New fields.** `name`, `confidence`, `match_type`, `logo_url`, `entity_id`, `parent`, and `intermediary` are on every response. A parser that rejects unknown fields needs an update. * **New `match_type` values.** `descriptor_domain` and `searched_name` appear on rows that returned `cleaned_descriptor` before. Add them before you upgrade. # Build an animated logo wall Source: https://www.logo.dev/docs/use-cases/animated-logo-wall Show more customers and integrations in less space. Build an animated logo wall where every logo loads from a Logo.dev image URL. A grid of company logos that swap over time, served from the Logo.dev CDN ```text Use case prompt wrap theme={null} Build an animated logo wall, following https://www.logo.dev/docs/use-cases/animated-logo-wall.md Read that page and inspect this project's stack. Use this project's existing conventions. Build a grid of tiles where each tile cycles through a small deck of company logos, and the swap sweeps across the grid column by column. Build every logo URL from a domain. Pause the animation while the grid is off-screen, and show a static grid to visitors who prefer reduced motion. Check every logo in the domain list by eye before you ship. For API details, read https://www.logo.dev/docs/logo-images/introduction.md ``` A logo wall shows traction on a landing page: customers, integrations, or supported companies. An animated wall fits three times the brands into the same space, and it adds motion without a video. Logo.dev supplies every logo from a domain as a plain image URL, so the wall needs no server code. Your app decides which domains to show, the grid shape, and how the logos look on your background. ## Choose the domains * **Match your background.** Set the `theme` and `greyscale` [image parameters](/docs/logo-images/introduction#parameters) to suit your surface. * **Check the list by eye.** A domain with no logo shows a [monogram](/docs/logo-images/introduction#fallback-images), which looks out of place in a customer wall. Look at every tile before you ship. * **Count the domains.** The wall needs `columns × rows × deckSize` domains. The default 5 × 3 grid with 3 logos per tile needs 45. ## Render the wall The component takes your domain list and the grid shape: ```tsx LogoGrid.tsx expandable theme={null} import { useEffect, useMemo, useRef, useState } from "react"; import type { CSSProperties } from "react"; type LogoGridProps = { /** Your Logo.dev publishable key (pk_…). */ token: string; /** Domains to show. Provide columns × rows × deckSize of them. */ domains: string[]; columns?: number; rows?: number; /** How many logos each tile cycles through. */ deckSize?: number; }; // One global tick advances every tile together; the per-column transition // delay turns the shared swap into a left-to-right wave. const STEP_MS = 3000; const REVEAL_MS = 400; const COLUMN_DELAY_MS = 120; const TRAVEL_PX = 40; const EASE = "cubic-bezier(0.17, 0.17, 0.3, 1)"; function useReducedMotion() { const [reduced, setReduced] = useState(false); useEffect(() => { const mq = window.matchMedia("(prefers-reduced-motion: reduce)"); const update = () => setReduced(mq.matches); update(); mq.addEventListener("change", update); return () => mq.removeEventListener("change", update); }, []); return reduced; } export function LogoGrid({ token, domains, columns = 5, rows = 3, deckSize = 3, }: LogoGridProps) { const ref = useRef(null); const [inView, setInView] = useState(false); const reduced = useReducedMotion(); const [active, setActive] = useState(0); const decks = useMemo(() => { const tiles = columns * rows; return Array.from({ length: tiles }, (_, i) => domains.slice(i * deckSize, i * deckSize + deckSize) ); }, [domains, columns, rows, deckSize]); // Only animate while the grid is on screen. useEffect(() => { const el = ref.current; if (!el) { return; } const observer = new IntersectionObserver(([entry]) => setInView(entry.isIntersecting) ); observer.observe(el); return () => observer.disconnect(); }, []); const running = inView && !reduced; useEffect(() => { if (!running) { return; } const id = setInterval(() => { setActive((v) => (v + 1) % deckSize); }, STEP_MS); return () => clearInterval(id); }, [running, deckSize]); // Every logo in a deck stays mounted in one of three positions: the current // logo in place, the previous one parked above, and the next waiting below. // Because the incoming layer is already in its start position, the swap is a // plain style change and the transition fires with no extra bookkeeping. const layerStyle = (index: number, columnIndex: number): CSSProperties => { const delay = (columnIndex + 1) * COLUMN_DELAY_MS; const transition = `opacity ${REVEAL_MS}ms ${EASE} ${delay}ms, translate ${REVEAL_MS}ms ${EASE} ${delay}ms`; if (index === active) { return { opacity: 1, translate: "0 0", transition }; } if (index === (active - 1 + deckSize) % deckSize) { return { opacity: 0, translate: `0 -${TRAVEL_PX}px`, transition }; } return { opacity: 0, translate: `0 ${TRAVEL_PX}px`, transition }; }; // Parameters: https://www.logo.dev/docs/logo-images/introduction#parameters const src = (domain: string) => `https://img.logo.dev/${domain}?token=${token}&format=webp&retina=true&size=52`; return (
{decks.map((deck, tileIndex) => (
{deck.map((domain, layerIndex) => ( ))}
))}
); } ``` ```tsx Usage theme={null} import { LogoGrid } from "./LogoGrid"; const DOMAINS = [ "stripe.com", "shopify.com", "github.com", "figma.com", "notion.so", "linear.app", "vercel.com", "slack.com", "zoom.us", "spotify.com", "airbnb.com", "netflix.com", "amazon.com", "google.com", "microsoft.com", "apple.com", "dropbox.com", "atlassian.com", "gitlab.com", "cloudflare.com", "datadoghq.com", "twilio.com", "hubspot.com", "salesforce.com", "intercom.com", "zendesk.com", "mailchimp.com", "openai.com", "anthropic.com", "nvidia.com", "adobe.com", "canva.com", "framer.com", "webflow.com", "discord.com", "reddit.com", "pinterest.com", "paypal.com", "coinbase.com", "robinhood.com", "doordash.com", "uber.com", "asana.com", "segment.com", "x.com", ]; export function Customers() { return ; } ``` For a static logo cloud, set `deckSize` to 1. For wide wordmark lockups instead of square logos, use the [customer logo wall](/docs/use-cases/customer-logo-wall). ## Test the wall Scroll the wall off-screen and back, and check that it pauses. Turn on reduced motion in your operating system, and check that the grid holds still. Add `made-up-startup.io` to the list, and check that its tile shows a monogram, not a broken image. > [card] [Logo.dev CDN](/docs/logo-images/introduction) > > Every image parameter: size, format, theme, greyscale, and fallback. > [card] [Customer logo wall](/docs/use-cases/customer-logo-wall) > > Build a trusted-by wall from wide wordmark lockups. # Import a brand kit Source: https://www.logo.dev/docs/use-cases/brand-kit-import Skip the logo-upload step. One domain imports the brand's logo, brandmark, banners, and colors, then themes the customer's workspace with them. brand assets ```text Use case prompt wrap theme={null} Build a brand kit import, following https://www.logo.dev/docs/use-cases/brand-kit-import.md Read that page and inspect this project's stack. Use this project's existing conventions. A user types a domain, and a tray fills with the brand's logo, brandmark, first social banner, and colors. On the server, look up the brand, download each image into this project's storage, and keep the stored files, not the image URLs. On a later import, download an image again only when it changed or when you request it at a different size. From the colors, pick the first one with enough chroma to work as an accent and a text color that is legible on it, store that theme with the customer's account, and apply it through theme variables in the interface and in each page, slide, or email that the app generates. Show a loading state while the brand is indexing, and retry until the retry window ends. When there is no brand or the request fails, show the domain's logo from the Logo.dev CDN and use the default theme. A color that the customer picks comes before any lookup result. For API details, read https://www.logo.dev/docs/brand/introduction.md and https://www.logo.dev/docs/logo-images/introduction.md ``` Slide tools, design apps, website builders, and white-label products all need the customer's brand. An upload step asks for files that most people do not have. An import that fills itself from a domain removes that step, and a workspace in the customer's own colors feels like their tool from the first session. Logo.dev returns the brand's name, images, and colors in one response. Your app stores the files, picks the accent, and decides what to show when a brand has no data. ## Import the brand on your server Look up the domain with [Brand](/docs/brand/introduction), from your server with your [secret key](/docs/platform/api-keys). The kit uses `data.logo`, `data.brandmark`, the first of `data.social_banners`, and `data.colors`. | Result | Save | Show | | - | - | - | | Brand found | Brand id, stored files with their etags and sizes, colors | The tray. Skip each slot that has no image. | | Still indexing | Nothing yet | A loading state, until the brand is ready | | No brand, or request failed | The attempt time | The domain's logo from the [Logo.dev CDN](/docs/logo-images/introduction), and your default theme | Store the files, not the URLs. The image URLs expire, so download each image at import time. On a later import, replace only the images whose `etag` changed, as [images](/docs/brand/introduction#images) describes. The `etag` identifies the source image, not the size or theme of your download. Store the size and theme with each file, and download the image again when you request a different one. The following route looks up the brand, stores its images, and returns the kit. It writes the files to `public/brand-kits/`. Replace the two file calls with your object storage: ```ts api/brand-kit.ts expandable theme={null} import { mkdir, readFile, writeFile, rm } from "node:fs/promises"; import path from "node:path"; type Image = { url: string; etag: string }; type Brand = { id: string; name: string; logo: Image | null; brandmark: Image | null; social_banners: Image[]; colors: Color[]; }; type Color = { hex: string; oklch: { l: number; c: number; h: number } }; type Theme = { accent: string; onAccent: string }; // variant records the requested size and theme, so a new size replaces old files. type StoredImage = { etag: string; variant: string; path: string }; type BrandKit = { brandId: string; name: string; logo: StoredImage | null; brandmark: StoredImage | null; banners: StoredImage[]; colors: string[]; theme: Theme; }; const ROOT = path.join(process.cwd(), "public", "brand-kits"); const DEFAULT_THEME: Theme = { accent: "#18181b", onAccent: "#ffffff" }; // Colors come most dominant first. Take the first one with enough chroma to // work as an accent. Tune 0.08 to your design; neutrals are close to 0. function pickAccent(colors: Color[]): Theme { const accent = colors.find((color) => color.oklch.c >= 0.08); if (!accent) { return DEFAULT_THEME; } // Light accents, such as yellow or bright green, need dark text. return { accent: accent.hex, onAccent: accent.oklch.l > 0.7 ? "#18181b" : "#ffffff", }; } async function readKit(domain: string): Promise { try { return JSON.parse(await readFile(path.join(ROOT, domain, "kit.json"), "utf8")); } catch { return null; } } // Download an image only when its etag or the requested variant changed // since the last import. The etag does not change with the size or theme. // Download parameters: https://www.logo.dev/docs/brand/introduction#images async function storeImage( domain: string, slot: string, image: Image, previous: StoredImage | null | undefined, size: number, theme?: "light" | "dark" ): Promise { const variant = `${size}-${theme ?? "default"}`; if (previous?.etag === image.etag && previous.variant === variant) { return previous; } // The signature in the URL is the credential, so send no key. const url = new URL(image.url); url.searchParams.set("format", "png"); // Without size, the download is a small default. An editor needs larger files. url.searchParams.set("size", String(size)); if (theme) { url.searchParams.set("theme", theme); } const res = await fetch(url); if (!res.ok) { throw new Error(`Download failed: ${res.status}`); } const file = `${slot}-${variant}-${image.etag.slice(0, 16)}.png`; await writeFile(path.join(ROOT, domain, file), Buffer.from(await res.arrayBuffer())); return { etag: image.etag, variant, path: `/brand-kits/${domain}/${file}` }; } export async function GET(request: Request) { const domain = new URL(request.url).searchParams.get("domain")?.trim().toLowerCase(); if (!domain || !/^[a-z0-9.-]+\.[a-z]{2,}$/.test(domain)) { return Response.json({ status: "error" }, { status: 400 }); } const res = await fetch( `https://api.logo.dev/v2/brands?domain=${encodeURIComponent(domain)}`, { headers: { Authorization: `Bearer ${process.env.LOGO_DEV_SECRET_KEY}` } } ); // Not indexed yet: https://www.logo.dev/docs/brand/introduction#handle-each-status if (res.status === 202) { // Retry timing and the retry window: // https://www.logo.dev/docs/platform/errors#not-found-vs-still-indexing-202 const body = await res.json().catch(() => null); const pending = body?.metadata?.pending; const retryAfter = Number(res.headers.get("Retry-After")) || pending?.retry_after_seconds || 30; const expiresIn = Number(pending?.expires_in_seconds) || 0; return Response.json({ status: "pending", retryAfter, expiresIn }, { status: 202 }); } if (res.status === 404) { return Response.json({ status: "not_found" }); } if (!res.ok) { return Response.json({ status: "error" }, { status: 502 }); } const { data }: { data: Brand } = await res.json(); const previous = await readKit(domain); await mkdir(path.join(ROOT, domain), { recursive: true }); const kit: BrandKit = { brandId: data.id, name: data.name, logo: data.logo && (await storeImage(domain, "logo", data.logo, previous?.logo, 512)), // The tray shows brandmarks on white, so request the light-background version. brandmark: data.brandmark && (await storeImage(domain, "brandmark", data.brandmark, previous?.brandmark, 800, "light")), banners: await Promise.all( data.social_banners .slice(0, 1) .map((banner, i) => storeImage(domain, `banner-${i}`, banner, previous?.banners[i], 800)) ), colors: data.colors.map((color) => color.hex), theme: pickAccent(data.colors), }; await writeFile(path.join(ROOT, domain, "kit.json"), JSON.stringify(kit)); // Delete files the new kit no longer uses, such as an image that changed. const kept = new Set( [kit.logo, kit.brandmark, ...kit.banners].flatMap((image) => (image ? [image.path] : [])) ); const old = previous ? [previous.logo, previous.brandmark, ...previous.banners] : []; for (const image of old) { if (image && !kept.has(image.path)) { await rm(path.join(ROOT, domain, path.basename(image.path)), { force: true }); } } return Response.json({ status: "ready", kit }); } ``` To import the brand again when it changes, use [update webhooks](/docs/webhooks). The etags tell you which files to replace. ## Render the asset tray The tray calls the route, retries while the brand is indexing, and shows the stored files. When there is no kit, it shows the domain's logo from the CDN: ```tsx BrandAssetTray.tsx expandable theme={null} import { useRef, useState } from "react"; type StoredImage = { etag: string; variant: string; path: string }; type BrandKit = { name: string; logo: StoredImage | null; brandmark: StoredImage | null; banners: StoredImage[]; colors: string[]; }; type Result = | { status: "idle" | "loading" | "not_found" | "error" } | { status: "pending"; retryAfter: number; expiresIn: number } | { status: "ready"; kit: BrandKit }; // Resolves after the delay, or rejects as soon as the run is aborted. const wait = (seconds: number, signal: AbortSignal) => new Promise((resolve, reject) => { const timer = setTimeout(resolve, seconds * 1000); signal.addEventListener("abort", () => { clearTimeout(timer); reject(signal.reason); }); }); export function BrandAssetTray({ token }: { token: string }) { const [input, setInput] = useState(""); const [domain, setDomain] = useState(""); const [result, setResult] = useState({ status: "idle" }); const currentRun = useRef(null); const importBrand = async (event: React.FormEvent) => { event.preventDefault(); const next = input.trim().toLowerCase(); if (!next.includes(".")) { return; } // A new import cancels the previous one, so a slow retry for an // older domain can never replace this result. currentRun.current?.abort(); const run = new AbortController(); currentRun.current = run; setDomain(next); setResult({ status: "loading" }); try { // Retry a 202 until the brand is ready or the retry window ends. // The window starts at the first 202. Retry timing and the window: // https://www.logo.dev/docs/platform/errors#not-found-vs-still-indexing-202 let deadline = 0; let retryAfter = 0; do { if (retryAfter > 0) { await wait(retryAfter, run.signal); } const res = await fetch(`/api/brand-kit?domain=${encodeURIComponent(next)}`, { signal: run.signal, }); const body: Result = await res.json(); if (run.signal.aborted) { return; } if (body.status !== "pending") { setResult(body); return; } deadline ||= Date.now() + body.expiresIn * 1000; retryAfter = body.retryAfter; // Stop when the next attempt would start after the window ends. } while (Date.now() + retryAfter * 1000 < deadline); setResult({ status: "error" }); } catch { if (!run.signal.aborted) { setResult({ status: "error" }); } } }; // The CDN falls back to a monogram, so this image always renders. const cdnLogo = `https://img.logo.dev/${domain}?token=${token}&size=40&retina=true&format=webp`; return (
setInput(e.target.value)} placeholder="acme.com" type="text" value={input} />
{result.status === "loading" && (
)} {(result.status === "not_found" || result.status === "error") && (
{`${domain}
No brand kit for {domain}. The logo is ready to use.
)} {result.status === "ready" && (
{`${result.kit.name}
{result.kit.brandmark && (
{`${result.kit.name}
)}
{result.kit.banners[0] && ( {`${result.kit.name} )}
{result.kit.colors.map((hex) => (
))}
)}
); } ``` ```tsx Usage theme={null} import { BrandAssetTray } from "./BrandAssetTray"; export function ImportPanel() { return ; } ``` Connect each asset to your editor's insert or drag action. A canvas needs only the stored file path. ## Theme the workspace with the brand colors The import also stores a theme: the first color in the palette with an OKLCH chroma (`oklch.c`) of 0.08 or more as the accent, and a text color that is legible on it. Palettes often start with black or white, so the first color is not always the accent. Store the theme with the customer's account, and render from it: | Result | Save | Show | | - | - | - | | Brand with a saturated color | Brand id, accent, text color | The customer's accent | | Brand with only neutral colors | Brand id | Your default theme | | Customer picks a color | Their color, in a separate field | Their color, before any lookup result | Set the stored colors as theme variables at the top of the customer's workspace. Every button, link, and highlight that reads the variables then uses the customer's accent: ```tsx BrandedWorkspace.tsx expandable theme={null} import type { CSSProperties, ReactNode } from "react"; type Theme = { accent: string; onAccent: string }; export function BrandedWorkspace({ name, domain, theme, token, children, }: { name: string; domain: string; theme: Theme; token: string; children: ReactNode; }) { const variables = { "--brand-accent": theme.accent, "--brand-on-accent": theme.onAccent, } as CSSProperties; return (
{`${name} {name}
{children}
); } ``` ```tsx Usage theme={null} import { BrandedWorkspace } from "./BrandedWorkspace"; // The theme comes from the spotify.com brand kit, stored with the account. export function Workspace() { return ( View all projects ); } ``` Use the same accent and logo in the pages, slides, and emails that you generate for the customer. ## Test the import Import a brand with full data (`spotify.com`), a brand whose accent is light enough to need dark text, a domain that Logo.dev has not indexed yet, and an invented domain. An invented domain can return `202` before it returns `404`. Import the same brand two times, and check that the second import downloads no files. Set a color as the customer, and check that a new import keeps it. Make the lookup fail once, and check that the tray still shows a logo and the default theme shows. > [card] [Brand](/docs/brand/introduction) > > See every field, status code, and image parameter, including colors in hex and OKLCH. > [card] [Onboarding personalization](/docs/use-cases/onboarding-personalization) > > Get the domain at signup and theme the workspace from day one. # Build a company search autocomplete Source: https://www.logo.dev/docs/use-cases/company-autocomplete Let users pick their company by typing a name. Capture a clean name, domain, and logo in one step with the Logo.dev API. Company ```text Use case prompt wrap theme={null} Build a company search autocomplete, following https://www.logo.dev/docs/use-cases/company-autocomplete.md Read that page and inspect this project's stack. Use this project's existing conventions. Build a company field that suggests companies with their logos as the user types. Send each debounced query to a server route that searches in typeahead mode, and show each candidate's name, domain, and logo. Make the field a keyboard-accessible combobox. If nothing matches, let the user keep the typed name. If the request fails, show an error and keep the typed text. When the user picks a candidate, store its name and domain. For API details, read https://www.logo.dev/docs/brand-search/introduction.md and https://www.logo.dev/docs/logo-images/introduction.md ``` A "which company?" field lets users type a few letters and pick their company from a list of logos. One pick gives your app a clean name and a domain to store, instead of a hand-typed guess. Logo.dev supplies the candidates. Your app decides how many to show, what to store after a pick, and what to do when the company is not in the list. If you are moving from Clearbit's autocomplete, this field replaces it. ## Proxy Search from your server [Search](/docs/brand-search/introduction) takes your [secret key](/docs/platform/api-keys), so the browser calls your route, and your route calls Logo.dev. Use `method=typeahead` while the user types, because it matches prefixes: `st` finds Stripe. ```ts api/company-search.ts theme={null} type SearchResult = { object: "search_result"; name: string; domain: string; logo_url: string; }; export async function GET(request: Request) { const q = new URL(request.url).searchParams.get("q")?.trim(); if (!q) { return Response.json([]); } const url = new URL("https://api.logo.dev/v2/search"); url.searchParams.set("q", q); url.searchParams.set("method", "typeahead"); url.searchParams.set("limit", "6"); const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.LOGO_DEV_SECRET_KEY}` }, }); if (!res.ok) { // Every error status ends here: https://www.logo.dev/docs/platform/errors return Response.json([], { status: 502 }); } const body: { data: SearchResult[] } = await res.json(); return Response.json(body.data); } ``` ## Handle every result | Result | Save | Show | | - | - | - | | User picks a candidate | The `name` and `domain` | The picked name in the field | | No candidates | Nothing | "No companies found". The user keeps the typed name. | | Request failed | Nothing | "Search unavailable". The typed text stays. | A search result is a candidate, not a brand record. To get the full profile after a pick, look up the domain with [Brand](/docs/brand/introduction), as [onboarding personalization](/docs/use-cases/onboarding-personalization) does. ## Render the field Each candidate carries a ready `logo_url`, so the list needs no second lookup: ```tsx CompanyAutocomplete.tsx expandable theme={null} import { useEffect, useRef, useState } from "react"; type Company = { name: string; domain: string; logo_url: string }; // logo_url already carries a token, so set parameters instead of concatenating. // Parameters: https://www.logo.dev/docs/logo-images/introduction#parameters function logoSrc(logoUrl: string) { const url = new URL(logoUrl); url.searchParams.set("size", "56"); url.searchParams.set("retina", "true"); url.searchParams.set("format", "webp"); return url.toString(); } export function CompanyAutocomplete({ onSelect, }: { onSelect?: (company: Company) => void; }) { const [query, setQuery] = useState(""); const [results, setResults] = useState([]); const [open, setOpen] = useState(false); const [active, setActive] = useState(0); const [selected, setSelected] = useState(null); const [error, setError] = useState(false); const [loading, setLoading] = useState(false); const abortRef = useRef(null); // Debounce input by 200ms, and abort the request in flight when the query // changes, so an old response never overwrites a newer one. useEffect(() => { const q = query.trim(); if (!q || selected) { setResults([]); setError(false); setLoading(false); return; } setLoading(true); const timer = setTimeout(async () => { abortRef.current?.abort(); const controller = new AbortController(); abortRef.current = controller; try { const res = await fetch( `/api/company-search?q=${encodeURIComponent(q)}`, { signal: controller.signal } ); if (!res.ok) { throw new Error("Search request failed"); } setResults((await res.json()) as Company[]); setActive(0); setError(false); setLoading(false); } catch (err) { if ((err as Error).name !== "AbortError") { setResults([]); setError(true); setLoading(false); } } }, 200); return () => { clearTimeout(timer); abortRef.current?.abort(); }; }, [query, selected]); const select = (company: Company) => { setSelected(company); setQuery(company.name); setOpen(false); onSelect?.(company); }; const onKeyDown = (e: React.KeyboardEvent) => { if (!(open && results.length)) { return; } if (e.key === "ArrowDown") { e.preventDefault(); setActive((i) => (i + 1) % results.length); } else if (e.key === "ArrowUp") { e.preventDefault(); setActive((i) => (i - 1 + results.length) % results.length); } else if (e.key === "Enter") { e.preventDefault(); select(results[active]); } else if (e.key === "Escape") { setOpen(false); } }; return (
0 ? `company-option-${active}` : undefined } aria-autocomplete="list" aria-controls="company-listbox" aria-expanded={open && results.length > 0} autoComplete="off" className="w-full rounded-xl border border-zinc-950/10 bg-white py-3 px-4 text-base focus:outline-none focus:ring-2 focus:ring-zinc-950/20 dark:border-white/20 dark:bg-zinc-900 dark:text-white" onBlur={() => setOpen(false)} onChange={(e) => { setQuery(e.target.value); setSelected(null); setOpen(true); }} onFocus={() => setOpen(true)} onKeyDown={onKeyDown} placeholder="Type a company name…" role="combobox" type="text" value={query} /> {open && results.length > 0 && (
    {results.map((company, i) => (
  • { e.preventDefault(); select(company); }} onMouseEnter={() => setActive(i)} role="option" > {company.name} {company.domain}
  • ))}
)} {error && (

Search unavailable. Try again.

)} {open && !error && !loading && query.trim() && results.length === 0 && (
No companies found
)}
); } ``` ```tsx Usage theme={null} import { useState } from "react"; import { CompanyAutocomplete } from "./CompanyAutocomplete"; export function AttachCompany() { const [company, setCompany] = useState<{ name: string; domain: string } | null>(null); return (
setCompany({ name, domain })} /> {company &&

Attached: {company.name} ({company.domain})

}
); } ``` Store the domain with the record. Every later logo is then a URL built from that domain, as in [CRM logos](/docs/use-cases/crm-logos). ## Test the field Type `st` and pick Stripe with the keyboard. Then type a string that matches nothing, and make the route return an error once. Check that the field shows each state and keeps the typed text. > [card] [Search](/docs/brand-search/introduction) > > Read every parameter and the response shape for `/v2/search`. > [card] [Onboarding personalization](/docs/use-cases/onboarding-personalization) > > Prefill a company profile from a work email. # Add company logos to CRM records Source: https://www.logo.dev/docs/use-cases/crm-logos Make every account recognizable at a glance. Show company logos in CRM lists and record pages, served from one Logo.dev image URL per domain. \
    \
    Stage
    \
    ```text Use case prompt wrap theme={null} Add company logos to CRM records, following https://www.logo.dev/docs/use-cases/crm-logos.md Read that page and inspect this project's stack. Use this project's existing conventions. Show a small logo in each row of the account list and a larger one in the account record header. Take the domain from the account's website, then from a contact's work email, then from a Search endpoint match that a rep confirms. On the server, enrich each account once with the Logo.dev Brand endpoint to add a description and a brand color, and key that data by the brand id. Keep rep edits in separate fields, and show them before any enrichment. For API details, read https://www.logo.dev/docs/logo-images/introduction.md, https://www.logo.dev/docs/brand/introduction.md, and https://www.logo.dev/docs/brand-search/introduction.md ```Sales reps recognize a company's logo faster than its name. A logo in each row of the account list and in each record header makes a CRM easy to scan. Your app decides where each domain comes from, what a record shows while enrichment is pending, and which values a rep can change.## Find the domain for each accountThe logo needs only a domain, and most accounts already have one:```mermaid theme={null} flowchart TD A[Account] --> B{Website on the account?} B -- Yes --> E[Domain] B -- No --> C{Contact with a work email?} C -- Yes --> E C -- No --> D[Search by account name] D --> F[Rep confirms the match] F --> E E --> G[Logo.dev CDN by domain] ```- **The account has a website.** Store its bare hostname, such as `stripe.com`. - **A contact has a work email.** Use the part after `@`. Skip free email providers, such as `gmail.com`, because that domain is not the account's company. - **You have only the account name.** Send it to [Search](/docs/brand-search/introduction) from your server, and let the rep confirm a candidate. The [company autocomplete](/docs/use-cases/company-autocomplete) shows this flow.## Render the list and the record headerBoth views use the same [Logo.dev CDN](/docs/logo-images/introduction) URL at a different size: 20px in list rows and 56px in the record header. An account with no logo shows the [generated monogram](/docs/logo-images/introduction#fallback-images):```tsx AccountLogo.tsx expandable theme={null} const logoUrl = (domain: string, token: string, size: number) => `https://img.logo.dev/${domain}?token=${token}&size=${size}&retina=true&format=webp`; export function AccountRow({ name, domain, token, }: { name: string; domain: string; token: string; }) { return (
    {/* Decorative: the account name is next to the logo. */} {name}
    ); } export function AccountHeader({ name, domain, token, description, accent, }: { name: string; domain: string; token: string; description?: string | null; accent?: string | null; }) { return (
    {`${name}
    {name} {accent ? ( ) : null}
    {domain}
    {description ?
    {description}
    : null}
    ); } ``````tsx Usage theme={null} import { AccountHeader, AccountRow } from "./AccountLogo"; export function Accounts() { return (
    ); } ```To show your own avatar for an account with no logo, use the component from [logo from a domain](/docs/use-cases/logo-from-domain).## Enrich the record on your serverThe same domain gets the brand's description and colors from [Brand](/docs/brand/introduction). Call it once when an account gets its domain, not on every page view:```ts api/enrich-account.ts expandable theme={null} type Color = { hex: string }; type Brand = { id: string; name: string; domain: string | null; description: string | null; colors: Color[]; }; // GET /api/enrich-account?domain=stripe.com export async function GET(request: Request) { const domain = new URL(request.url).searchParams.get("domain")?.trim(); if (!domain) { return Response.json({ error: "domain is required" }, { status: 400 }); } const res = await fetch( `https://api.logo.dev/v2/brands?domain=${encodeURIComponent(domain)}`, { // Secret key, server only: https://www.logo.dev/docs/platform/api-keys headers: { Authorization: `Bearer ${process.env.LOGO_DEV_SECRET_KEY}` }, signal: AbortSignal.timeout(20_000), } ); if (res.status === 202) { // Still indexing: https://www.logo.dev/docs/platform/errors#not-found-vs-still-indexing-202 const retryAfter = Number(res.headers.get("Retry-After") ?? 30); return Response.json({ status: "pending", retryAfter }, { status: 202 }); } if (res.status === 404) { return Response.json({ status: "not_found" }); } if (!res.ok) { // Any other 4xx or 5xx: an integration problem, not an empty record. // Status codes: https://www.logo.dev/docs/platform/errors#logo-api-status-codes return Response.json({ status: "error" }, { status: res.status }); } const { data }: { data: Brand } = await res.json(); return Response.json({ status: "ready", brandId: data.id, // Key the enrichment on this id. It survives domain changes. name: data.name, description: data.description, colors: data.colors.map((color) => color.hex), }); } ```Save the result with the account, and render the record from it:| Result | Save | Show | | - | - | - | | `ready` | Brand id, description, colors, lookup time | The logo, the description, and a brand color | | `pending` | The retry time | The logo and the name. Retry when the brand is [ready](/docs/platform/errors#not-found-vs-still-indexing-202). | | `not_found` | The lookup time | The logo and the name, with no description | | Request failed | The attempt time | The logo and the name. Retry later with backoff. | | Rep edit | The value, in a separate field | The rep's value, before any enrichment |A palette often starts with black or white, so use the first color with an OKLCH chroma (`oklch.c`) of 0.08 or more as the accent. The [brand kit import](/docs/use-cases/brand-kit-import) use case has a picker.## Test the account viewsTest with an account that has a website, one with only a contact email, and one with only a name. Enrich a domain that Logo.dev has not indexed, and check that the `pending` state retries. Check that a `not_found` result shows the logo and the name with no description. Then enrich an account again, and check that the rep edit stays.> [card] [Brand](/docs/brand/introduction) > > Every field, status, and identifier for brand lookups.> [card] [Company autocomplete](/docs/use-cases/company-autocomplete) > > Capture a clean domain when a rep adds a company. # Show token logos in a crypto wallet Source: https://www.logo.dev/docs/use-cases/crypto-wallet-logos Make balances, trades, and portfolios easy to scan. Put the right token logo next to every symbol from one image URL per token.
      ```text Use case prompt wrap theme={null} Build a token list with crypto logos, following https://www.logo.dev/docs/use-cases/crypto-wallet-logos.md Read that page and inspect this project's stack. Use this project's existing conventions. Each row shows the token logo, the token name, the balance, and the value. Build each logo URL from the token symbol. A token with no logo keeps the generated monogram, so every row has the same shape. If the app needs a token's name, description, or colors, look the token up on the server with the Logo.dev Brand endpoint, and allow for a token with no domain. For API details, read https://www.logo.dev/docs/logo-images/crypto.md, https://www.logo.dev/docs/logo-images/introduction.md, and https://www.logo.dev/docs/brand/introduction.md ``` Wallets, exchanges, and portfolio trackers show dozens of tokens on one screen. A logo next to each symbol lets people find a holding before they read its ticker. Your app decides which symbol each asset uses and what a row without a logo looks like. ## Choose the lookup from the data you have * **You have the token symbol.** Build a [crypto logo](/docs/logo-images/crypto) URL from the symbol. * **You need the token's name, description, or colors.** Look the token up by symbol with [Brand](/docs/brand/introduction) on your server. Some tokens have no website, so allow for a `null` domain. ## Render the list Each row is one image next to the balances you already have. A token with no logo shows the [generated monogram](/docs/logo-images/introduction#fallback-images), so every row keeps the same shape: ```tsx TokenList.tsx expandable theme={null} type Holding = { symbol: string; name: string; amount: number; value: number; }; const usd = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", }); export function TokenList({ token, holdings, }: { token: string; holdings: Holding[]; }) { return (
        {holdings.map((h) => (
      • {`${h.name}
        {h.name}
        {h.amount.toLocaleString("en-US")} {h.symbol}
        {usd.format(h.value)}
      • ))}
      ); } ``` ```tsx Usage theme={null} import { TokenList } from "./TokenList"; export function Wallet() { return ( ); } ``` ## Test the list Test with a major token such as `BTC`, a stablecoin such as `USDC`, a lowercase symbol such as `eth`, and a symbol that has no logo. Check that every row keeps its size while images load. > [card] [Crypto logos](/docs/logo-images/crypto) > > Look up token logos by symbol. > [card] [Stock watchlists](/docs/use-cases/stock-ticker-logos) > > Build the same row pattern for stocks. # Build a customer logo wall with wordmarks Source: https://www.logo.dev/docs/use-cases/customer-logo-wall Show customer logos people recognize. A trusted-by wall of wide wordmark lockups built from a domain list, with no logo files to collect by hand.
        ```text Use case prompt wrap theme={null} Build a trusted-by wall of customer wordmarks, following https://www.logo.dev/docs/use-cases/customer-logo-wall.md Read that page and inspect this project's stack. Use this project's existing conventions. At build time or on a schedule, look up the brandmark for each customer domain on the server. Download a light and a dark variant of each one, host the files with the site, and save each etag so a later run downloads only changed images. If a lookup fails, keep the last good copy. If a customer has no brandmark, or a file fails to load, show the square logo instead. Give each mark its own optical height, and show a skeleton until it loads. For API details, read https://www.logo.dev/docs/brand/introduction.md and https://www.logo.dev/docs/logo-images/introduction.md ``` A trusted-by wall needs the wide wordmark of each customer, not the square icon. A row of square icons looks like an app grid, and visitors recognize the wide lockups. Logo.dev supplies each customer's brandmark from a domain. Your app decides which customers to show, where to host the files, and how tall each mark renders so that the row reads evenly. ## Download the brandmarks at build time A marketing wall is static, so download each brandmark once and host it with your site. Don't put the lookup `url` in your page. Keep the `etag` with your copy, and download again only when the `etag` changes. See [images](/docs/brand/introduction#images) for how the `url` and `etag` work. This script runs on your server or in CI. It downloads a light and a dark variant of each brandmark and writes a manifest for the wall: ```ts fetch-brandmarks.ts expandable theme={null} import { mkdir, readFile, writeFile } from "node:fs/promises"; type Customer = { name: string; domain: string; height: number }; type WallEntry = Customer & { etag: string | null; light: string | null; dark: string | null; }; // Optical heights are tuned by eye. All-caps marks need less height. const CUSTOMERS: Customer[] = [ { name: "Stripe", domain: "stripe.com", height: 26 }, { name: "Twilio", domain: "twilio.com", height: 26 }, { name: "DoorDash", domain: "doordash.com", height: 20 }, { name: "Vercel", domain: "vercel.com", height: 22 }, { name: "Discord", domain: "discord.com", height: 24 }, { name: "Airbnb", domain: "airbnb.com", height: 25 }, { name: "Spotify", domain: "spotify.com", height: 26 }, { name: "Datadog", domain: "datadoghq.com", height: 19 }, ]; const OUT_DIR = "public/logo-wall"; const MANIFEST = `${OUT_DIR}/manifest.json`; const sleep = (seconds: number) => new Promise((resolve) => setTimeout(resolve, seconds * 1000)); async function lookupBrandmark(domain: string) { const url = new URL("https://api.logo.dev/v2/brands/brandmark"); url.searchParams.set("domain", domain); // Retry a 202 (still indexing) until its retry window ends: // https://www.logo.dev/docs/platform/errors#not-found-vs-still-indexing-202 let deadline = 0; while (deadline === 0 || Date.now() < deadline) { const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.LOGO_DEV_SECRET_KEY}` }, signal: AbortSignal.timeout(15_000), }); if (res.status === 202) { const { metadata } = await res.json(); deadline ||= Date.now() + metadata.pending.expires_in_seconds * 1000; await sleep(Number(res.headers.get("Retry-After")) || metadata.pending.retry_after_seconds); continue; } if (res.status === 404) { return null; // No brand, or the brand has no brandmark. } if (!res.ok) { throw new Error(`${domain}: HTTP ${res.status}`); } const { data }: { data: { url: string; etag: string } } = await res.json(); return data; } throw new Error(`${domain}: still indexing`); } async function download(signedUrl: string, theme: "light" | "dark", file: string) { // Send no key with the signed URL: https://www.logo.dev/docs/brand/introduction#images const url = new URL(signedUrl); url.searchParams.set("size", "320"); url.searchParams.set("format", "webp"); url.searchParams.set("theme", theme); const res = await fetch(url); if (!res.ok) { throw new Error(`${file}: HTTP ${res.status}`); } await writeFile(`${OUT_DIR}/${file}`, Buffer.from(await res.arrayBuffer())); return `/logo-wall/${file}`; } async function main() { await mkdir(OUT_DIR, { recursive: true }); const previous: WallEntry[] = JSON.parse( await readFile(MANIFEST, "utf8").catch(() => "[]") ); const entries: WallEntry[] = []; for (const customer of CUSTOMERS) { const old = previous.find((e) => e.domain === customer.domain); try { const mark = await lookupBrandmark(customer.domain); if (!mark) { entries.push({ ...customer, etag: null, light: null, dark: null }); } else if (old?.etag === mark.etag && old.light && old.dark) { entries.push({ ...old, ...customer }); } else { const slug = customer.domain.replace(/\W/g, "-"); entries.push({ ...customer, etag: mark.etag, light: await download(mark.url, "light", `${slug}-light.webp`), dark: await download(mark.url, "dark", `${slug}-dark.webp`), }); } } catch (err) { // Keep the last good copy, so one failed lookup never empties a slot. console.error(err); entries.push(old ?? { ...customer, etag: null, light: null, dark: null }); } } await writeFile(MANIFEST, JSON.stringify(entries, null, 2)); } main(); ``` Run the script on deploy or on a schedule, not on each page view. ## Handle every brandmark result | Result | Save | Show | | - | - | - | | New brandmark | The light and dark files and the `etag` | The brandmark for the current theme | | Same `etag` as the last run | Nothing new | The files you already host | | Still indexing, or the request failed | Nothing new | The last good copy, or the square logo | | No brand, or no brandmark | A `null` brandmark | The square logo from the [Logo.dev CDN](/docs/logo-images/introduction) | Some well-known brands have no brandmark, so the wall always needs the square logo as a fallback. Check each brandmark by eye before you ship. Some marks are white or very light, and they disappear on a light surface. ## Render the wall The wall reads the manifest and shows the light or dark file for your theme: ```tsx LogoWall.tsx expandable theme={null} import { useState } from "react"; type WallEntry = { name: string; domain: string; /** Optical height in px, tuned by eye. */ height: number; light: string | null; dark: string | null; }; function WallLogo({ entry, dark, token, }: { entry: WallEntry; dark: boolean; token: string; }) { const brandmark = dark ? entry.dark : entry.light; const [state, setState] = useState<"loading" | "loaded" | "failed">( brandmark ? "loading" : "failed" ); // No brandmark, or the file failed to load: show the square logo. // Fallbacks: https://www.logo.dev/docs/logo-images/introduction#fallback-images if (state === "failed" || !brandmark) { return ( {`${entry.name} ); } return ( <> {state === "loading" && (