Model or dataset
tight-studio/OpenBrand avatar
tight-studio/OpenBrand

OpenBrand pulls logos, colours and brand names out of any URL

Extract brand assets (logos, colors, backdrops) from any website; open source alternative to Brand.dev

801 stars66 forksTypeScriptMIT

At a glance

What is it?
OpenBrand is an MIT licensed TypeScript project that extracts brand assets from a website URL, shipped as a hosted API, an npm library, an MCP server, an agent skill and a self hostable Next.js app.
Who is it for?
Adopt OpenBrand when your pipeline needs brand assets pulled from a URL without maintaining a scraper per site, and when you can either take a hosted API key or run the Next.js app yourself with bun. Do not adopt it if you need guaranteed output for a specific site, since the extraction is heuristic and the documentation lists no guarantees, version coverage or rate limits.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 166 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Brand scraping as a reusable pipeline stage

Every piece of marketing collateral needs the same assets: a logo in a usable format, the right brand colours, a backdrop image, the product or company name. Collecting those by hand for a list of partner or customer sites is slow, and the obvious alternative is a scraper written for one site at a time. OpenBrand is positioned as the opposite of that: extract brand assets, logos, colors, backdrops and the brand name from any website URL. The project describes itself as an open source alternative to Brand.dev, which frames both the use case and the competitive set. The audience is developers building agent tools, website builders, mockup generators, presentation pipelines and any workflow where a URL in means a brand kit out. The homepage is https://openbrand.sh and the licence is MIT, so the interesting question for an adopter is not whether the idea is sound but which of the five delivery modes fits your setup, because they differ in whether they need a hosted account, a key, or nothing at all.

Four extraction fronts, and the sources each one reads

The extraction logic is organised around four asset types, and the documentation is specific about where each one comes from. Logos are taken from favicons, apple-touch-icons, header and nav logos, and inline SVGs, with dimension probing applied so that the smallest icon is not mistaken for the real mark. Brand colors are read from theme-color meta tags and manifest.json, plus dominant colors extracted from the logo imagery itself, which is the only part of the pipeline that touches pixels rather than markup. Backdrop images come from og:image, CSS backgrounds and hero or banner images. The brand name is derived from og:site_name, application-name, logo alt text and the page title, in that order of appearance. Underneath, the stack is Next.js, React, TypeScript, Cheerio, Sharp and Tailwind CSS: Cheerio for parsing markup, Sharp for image work, and probe-image-size among the dependencies for working out image dimensions. That combination explains the design: most of the extraction is DOM scraping with a few image measurements bolted on.

The hosted API needs a key, the three client snippets do not

The quickest route to a result is the hosted endpoint at openbrand.sh/api/extract, and it needs a bearer token, which you get from the dashboard. The cURL call passes the target URL as a query parameter:

bash
curl "https://openbrand.sh/api/extract?url=https://stripe.com" \
  -H "Authorization: Bearer your_api_key"

The same request from TypeScript:

typescript
const res = await fetch(
  "https://openbrand.sh/api/extract?url=https://stripe.com",
  { headers: { Authorization: "Bearer your_api_key" } }
);
const brand = await res.json();

And from Python:

python
import requests

res = requests.get(
    "https://openbrand.sh/api/extract",
    params={"url": "https://stripe.com"},
    headers={"Authorization": "Bearer your_api_key"},
)
brand = res.json()

All three produce the same JSON document, so the choice of client language is a matter of what your pipeline already uses. The key comes from the dashboard, which is worth understanding before you plan a deployment: the example environment file shows Supabase configured for auth and API key management, with NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY and SUPABASE_SERVICE_ROLE_KEY. The same file also records that the Jina AI fallback at r.jina.ai works without authentication, which tells you there is a secondary fetching path for pages that resist a direct request.

The npm library path returns a typed result and no key

The npm package is the mode with the fewest moving parts for a server side job, and it states that no API key is required because it runs as a library from your own server side code. Installation is one command:

bash
npm add openbrand

The single exported function returns a discriminated result:

typescript
import { extractBrandAssets } from "openbrand";

const result = await extractBrandAssets("https://stripe.com");
if (result.ok) {
  // result.data.brand_name → "Stripe"
  // result.data.logos → LogoAsset[]
  // result.data.colors → ColorAsset[]
  // result.data.backdrop_images → BackdropAsset[]
} else {
  // result.error.code → "ACCESS_BLOCKED" | "NOT_FOUND" | "SERVER_ERROR" | ...
  // result.error.message → human-readable explanation
}

Two things stand out. The success branch is structured data with typed asset arrays rather than a bag of URLs, which means you can consume colours and logos programmatically instead of parsing markup downstream. And the failure branch is a first class part of the contract, with error codes such as ACCESS_BLOCKED, NOT_FOUND and SERVER_ERROR plus a human readable message, so a caller can distinguish a site that refused the fetch from a site that simply has no brand assets. The package is built with tsup, publishing dist/index.js, dist/index.mjs and dist/index.d.ts, and the current version in package.json is 0.2.3.

An MCP server and a skill for coding agents

The most interesting distribution mode targets agents rather than scripts. The MCP server, published as openbrand-mcp, is added to Claude Code, Cursor or any MCP compatible client. Installing it needs no key:

bash
claude mcp add --transport stdio openbrand -- npx -y openbrand-mcp

The key is added afterwards as an environment variable, either on the command:

bash
claude mcp add --transport stdio \
  --env OPENBRAND_API_KEY=your_api_key \
  openbrand -- npx -y openbrand-mcp

or in the project settings file:

json
{
  "mcpServers": {
    "openbrand": {
      "command": "npx",
      "args": ["-y", "openbrand-mcp"],
      "env": {
        "OPENBRAND_API_KEY": "your_api_key"
      }
    }
  }
}

Once registered, a client can be asked to extract brand assets from a URL and it calls the extract_brand_assets tool. The separate agent skill route does the same thing for a wider set of clients, with the install command npx skills add tight-studio/openbrand, advertised for Claude Code, Cursor, Codex, Gemini CLI and 40 other agents. That breadth is the reason to care about this mode: the extraction logic sits behind a tool call, so the agent decides which URLs to try and how to use the colours, and your code never touches the HTTP layer at all.

Self hosting the Next.js app with bun

If you would rather not send traffic to a hosted service, the web app is in the same repository and is designed to run locally or on your own infrastructure. The documented sequence is three commands:

bash
git clone https://github.com/tight-studio/openbrand.git
cd openbrand
bun install
bun dev

No environment variables are required for the local web app, which opens on http://localhost:3000. The bun.lock file in the repository root and the bun test integration_test/ script in package.json show that bun is the expected runtime and test runner rather than an accident of the tutorial. The Next.js side of the project has its own scripts, with next dev, next build and next start, and the library is built separately with the build:pkg script that runs tsup. The repository also holds a supabase/ directory, a middleware.ts and a SKILL.md file, which lines up with the hosted tier handling keys through Supabase while the open source core stays local. That split is the practical answer to how the commercial and open source halves of the project relate, and it is the reason self hosting is a supported path rather than a community workaround.

No releases, a quiet last push, and no documented guarantees

The limitations are mostly about predictability. The repository has no GitHub releases, so there is no versioned changelog to track and no upgrade path to follow; the version field in package.json reads 0.2.3 and the CHANGELOG.md file exists in the tree, but the last push to the repository was on 2026-05-12, so the pace of work has been quiet for a while. More importantly, the extraction is heuristic by nature. Logos are found by looking at favicons, apple-touch-icons, header and nav logos and inline SVGs, and colours partly come from dominant colours in logo imagery, so a site with a dark mode theme, a heavy inline SVG or an unusual markup can produce a plausible but wrong answer. Nothing in the documentation promises coverage, accuracy or a service level for the hosted API, and rate limits are not described either. The documented error codes, ACCESS_BLOCKED, NOT_FOUND and SERVER_ERROR, tell you the project expects blocked sites to be a normal outcome rather than an exception, which is exactly why the ACCESS_BLOCKED case and the Jina AI fallback path matter for anyone running this at volume.

Editorial conclusion

Adopt OpenBrand when your pipeline needs brand assets pulled from a URL without maintaining a scraper per site, and when you can either take a hosted API key or run the Next.js app yourself with bun. Do not adopt it if you need guaranteed output for a specific site, since the extraction is heuristic and the documentation lists no guarantees, version coverage or rate limits. Verify first that the npm package or your self hosted instance returns the logo and colour types you expect for your target sites, that your environment variables for Supabase are set if you plan to issue API keys, and that the API key path and the keyless library path produce the same shape of result.

Frequently asked questions

How do I extract brand assets from a URL with OpenBrand?

Call the hosted endpoint with the target URL and a bearer token from the openbrand.sh dashboard, use the extractBrandAssets function from the openbrand npm package for a keyless library call from your server, or register the openbrand-mcp server in an MCP client. The npm route needs no API key.

What does OpenBrand extract from a website?

Logos from favicons, apple-touch-icons, header and nav logos and inline SVGs, brand colors from theme-color meta tags, manifest.json and dominant colors in logo imagery, backdrop images from og:image, CSS backgrounds and hero images, and the brand name from og:site_name, application-name, logo alt text and the page title.

Can I self host OpenBrand without an API key?

Yes. The README documents cloning the repository, then bun install and bun dev, which opens the web app on http://localhost:3000 with no environment variables required. The npm library also runs from your own server side code without a key.

How does OpenBrand report failures?

The npm library returns a discriminated result where the error branch carries a code such as ACCESS_BLOCKED, NOT_FOUND or SERVER_ERROR together with a human readable message. The MCP server and hosted API surface the same underlying extraction for tool calls.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. tight-studio/OpenBrand on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tight-studio-openbrand.svg)](https://hysenlabs.com/projects/tight-studio-openbrand)

Was this useful?