Brand extraction API

Point it at a domain. Get the brand back.

Logos, colour roles and type for any company on the internet, measured from the page as it renders rather than read off the stylesheet. No headless browser to babysit, no favicon guessing, no stale PNGs in your database.

Try it on a domain
Nothing sampled yet

Every domain sampled here joins the shared cache. Read one that is already there and it comes back in milliseconds, free, for everyone.

What comes back

Three things, and all of them usable.

Every field is what the brand publishes on its own pages, measured from the page as it renders rather than read off the stylesheet, and versioned so a redesign never silently changes shape underneath you.

Logos

SVG where the site has one, raster where it does not.

  • The mark, at the URL the site serves it from
  • The light variant when a site publishes one
  • Source recorded — inline SVG, header img, og:image
  • Dominant colours and transparency of the mark itself

Colour

Ranked by how much of the rendered page each one covers.

  • Primary, secondary, background and text, named
  • A named palette for everything beyond those four
  • Roles assigned from painted area, not source frequency
  • Read off the rendered page, gradients included

Type

The faces that rendered, not the ones the stack asked for.

  • Heading and body resolved separately
  • Google font, custom webfont or system fallback, per face
  • The families that rendered, in prominence order
  • Letter-spacing and weight as the page authors them
5

domains in the shared cache, readable by anyone

37s

median cold read, when a domain is new to us

5 max

colours per brand, ranked by painted area

0

cost to re-read a domain already in the cache

How it works

Reading the CSS is not the same as seeing the page.

Most extractors parse stylesheets and rank colours by how often they appear in the source. That breaks in ways your users notice, because a modern page paints almost nothing the way it declares it.

Dead tokens

Design systems ship dozens of custom properties that never get painted. Source readers return them as brand colours. Measurement never sees them, so it never reports them.

--brand-500 #f2542d painted 21%
--brand-ink #0e1e2b painted 38%
--legacy-teal #12a6a6 never painted
--accent-alt #8e7bc4 never painted

Gradients

A hero gradient has no single hex. Parsers pick a stop or average the ramp and return a colour the brand does not use. We sample the painted region and report what dominates it.

parser averages the ramp #b44a55, unused
measured dominant across region #f2542d, 62%

Weighting

Frequency in source is not prominence on screen. A border colour declared in forty rules loses to an accent painted across a fifth of the viewport. Roles come from rendered area and position.

#e3e6eb41 rules
0.4% area
#f2542d2 rules
21% area
primary = #f2542d

Fonts

The stack is a wish list, not the result. A declared family means nothing if the file fails to load or the glyphs fall through. We report the face that rendered, with the fallback that actually resolved.

declared"Tiempos Headline", Georgia, serif
loadedTiempos Headline failed, 403
renderedGeorgia
reportedGeorgia, fallback of Tiempos
The response

One versioned shape, with the evidence attached.

Every extraction reports how sure it is, per field, and names the fields it could not resolve. Set a floor in your own code and fall back to your defaults below it, rather than shipping a guess to your customer.

$ curl https://api.extractbrand.com/v1/brands/helio.com \
    -H "Authorization: Bearer eb_live_..."

{
  "object": "brand",
  "domain": "helio.com",
  "cache_status": "hit",
  "extracted_at": "2026-07-30T09:14:22.104Z",
  "expires_at": "2026-08-29T09:14:22.104Z",
  "brand": {
    "name": "Helio",
    "tagline": "Power that follows the sun",
    "positioning_statement": "Helio sells rooftop solar to homeowners who …",

    "primary": "#f2542d",
    "secondary": "#0e1e2b",
    "background": "#ffffff",
    "text": "#14161a",
    "palette": [ { "name": "Ember", "hex": "#f2542d", "role": "accent" }, … ],

    "fonts": ["Tiempos", "Inter"],
    "typography": {
      "heading": { "family": "Tiempos", "availability": "custom-webfont" },
      "body":    { "family": "Inter",   "availability": "google" }
    },

    "logo": {
      "url":         "https://helio.com/logo.svg",
      "on_dark_url": "https://helio.com/logo-light.svg",
      "source":      "inline-svg",
      "dominant_colors": ["#f2542d"], …
    },

    "visual_style": { "theme": "light", "corner_style": "rounded", … },
    "motion":       { "intensity": "subtle", "speed": "moderate", … },
    "copywriting":  { "cta_style": "imperative — Get, Start, Book", … },
    "tone": ["direct", "warm"],

    "confidence": 0.94,
    "gaps": [],
    "schema_version": "v2"
  },
  "quota": { "used": 128, "limit": 5000, "period_end": "2026-08-01T00:00:00.000Z" }
}

Confidence is on every extraction

A brand read from a clean, well-marked page is not the same result as one pieced together from a page that blocked the render. Both come back; only one says it is sure.

  • confidence — the overall figure, 0 to 1
  • confidence_per_field — the same, per extracted field
  • gaps — fields no specialist could resolve, named
  • confidence_signals — what drove the number, in words

A low score is reported, never hidden and never rounded up. The useful answer to a page we could not read is that we could not read it.

Where it goes

Anywhere a company name currently sits on its own.

Onboarding

Ask for a work email and the first screen already carries their logo and their colour. Activation moves because the product looks like it was set up for them.

CRM and enrichment

Every account, lead and company record with a real mark instead of two grey initials. One call at write time, cached from then on.

Generated documents and decks

Proposals, invoices and slides that pick up the recipient's brand at render time — colour roles, type and spacing, not just a logo drop.

Agents that build things

A generator needs more than a hex triple. Roles, contrast pairs, the faces that actually load and what to substitute when they do not.

Pricing

Metered on fresh reads, not on seats.

A domain nobody has sampled costs us a browser and two model calls. A domain already in the cache costs nothing, so reading it costs you nothing — cached reads are free and unmetered on every tier. Per-read prices land when the meter has enough real extractions behind it to set them from cost rather than from guesswork.

Free

Unlimited cached reads

  • Every domain already in the cache
  • 100 fresh reads included each month
  • Full response shape, no trimmed fields
Build

Fresh reads, metered

  • Pay only for domains new to the cache
  • Set your own monthly ceiling
  • Refresh a brand on demand
Embedded

Volume and platform terms

  • Committed-volume pricing
  • Hosted MCP server for your agents
  • Direct line to the people who built it

Want the prices when they are set? hello@extractbrand.com.

Give it a domain you know well.

You will know inside one read whether the colours and type match what you would have picked by hand.