Brandohue API Documentation
Extract logos, favicons, color palettes, and brand metadata from any website with a single API call. Designed for developers who value speed and simplicity.
Authentication
All API requests require authentication via an API key. Include your key in the x-api-key header of every request.
How to get an API key
- Create an account on Brandohue.
- Navigate to the API Keys page in your dashboard.
- Click "Create API Key" and give it a name.
- Copy your key and store it securely — it won't be shown again.
x-api-key: br_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Extract Endpoint
/api/v1/extractThe extract endpoint analyzes a website and returns structured brand data including logos, favicons, color palettes, Open Graph metadata, and more. Colors are extracted from multiple sources (HTML, CSS, JavaScript, logo images, and screenshots) and grouped by color family with named identifiers. Each request costs 1 credit.
https://api.brandohue.comRequest Parameters
The request body must be application/json.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| url | string | Yes | — | The URL of the website to extract brand data from. Must include http:// or https://. |
| useCache | boolean | No | false | When true, returns cached results if available (within 24 hours). Cached responses cost 0 credits. |
| extractLogoColors | boolean | No | true | Extract dominant colors from the site's logo image. |
| logoColorsLimit | number | No | 6 | Maximum number of logo colors to extract. Must be between 2 and 12. |
| extractScreenshotColors | boolean | No | true | Extract colors from a full-page screenshot of the website. |
| screenshotColorsLimit | number | No | 12 | Maximum number of screenshot colors to extract. Must be between 2 and 12. |
| extractHtmlColors | boolean | No | true | Extract colors directly from the HTML markup (inline styles, attributes). |
| extractCssColors | boolean | No | true | Extract colors from CSS stylesheets and style tags. |
| extractJsColors | boolean | No | false | Extract colors from JavaScript files and inline scripts. |
| hexColor | boolean | No | false | When true, force hex color format in the response. |
| extractLogoDimensions | boolean | No | false | When true, extract logo dimensions (width and height). |
| callbackUrl | string | No | — | A URL that will receive the extraction results via POST. When provided, the API returns 200 immediately and sends results asynchronously. See the Callback / Webhook section for details. |
Success Response
A successful extraction returns the brand data along with billing information. The response includes detailed color analysis grouped by source and color family.
data
The extracted brand information:
- siteName — Domain name of the analyzed site
- logoUrl — URL of the detected logo (SVG prioritized)
- faviconUrl — URL of the favicon
- colors — Array of extracted brand colors
- title — Page title or Open Graph title
- description — Meta or Open Graph description
- nearestColors — Colors grouped by name (e.g. black, dodgerblue, crimson) with identifiers
- visualPalette — Colors organized by source: Logo, Homepage, HTML, CSS, and JavaScript
- screenshot — Base64-encoded screenshot of the page (null if disabled)
- logoFormat — Format of the detected logo (svg, png, etc.)
- logoWidth — Logo width in pixels
- logoHeight — Logo height in pixels
- logoSource — Source method used to detect the logo
- darkModeLogoUrl — URL of the dark mode variant of the logo
- faviconFormat — Format of the favicon (ico, png, svg)
- faviconSource — Source method used to detect the favicon
- appleTouchIcon — URL of the apple-touch-icon
- manifestIcons — Array of icons from the web manifest
- colorPalette — Dominant, accent, and background colors with labels
- contrastRatios — Contrast ratios for accessibility (dominantOnWhite, accentOnWhite, backgroundOnWhite)
- ogTitle — Open Graph title
- ogDescription — Open Graph description
- ogImage — Open Graph image URL
- twitterCard — Twitter card type
- twitterImage — Twitter card image URL
- jsonLd — Array of JSON-LD structured data found on the page
billing
- cost — Credits consumed (1 per extraction)
- newBalance — Remaining credits after deduction
- message — Human-readable billing summary
{
"data": {
"siteName": "Google",
"logoUrl": null,
"faviconUrl": "https://www.gstatic.com/images/branding/searchlogo/ico/favicon.ico",
"colors": [
"rgba(104, 29, 168, 1)",
"rgba(50, 50, 50, 1)",
"rgba(11, 80, 208, 1)",
...
],
"title": "Google",
"description": null,
"nearestColors": {
"rebeccapurple": [
{ "color": "rgba(104, 29, 168, 1)", "group": "rebeccapurple", "name": "rebeccapurple-100" }
],
"darkslategray": [
{ "color": "rgba(50, 50, 50, 1)", "group": "darkslategray", "name": "darkslategray-100" }
],
"royalblue": [
{ "color": "rgba(11, 80, 208, 1)", "group": "royalblue", "name": "royalblue-100" }
],
...
},
"visualPalette": {
"Logo Colors": [],
"Homepage Colors": [],
"HTML Colors": [
{ "color": "rgba(104, 29, 168, 1)", "name": "rebeccapurple" },
{ "color": "rgba(68, 71, 70, 1)", "name": "darkslategray" },
...
],
"CSS Colors": [
{ "color": "rgba(11, 87, 208, 1)", "name": "royalblue" },
...
],
"JavaScript Colors": []
},
"screenshot": null,
"logoFormat": null,
"logoWidth": null,
"logoHeight": null,
"logoSource": null,
"darkModeLogoUrl": null,
"faviconFormat": "ico",
"faviconSource": "link_icon",
"appleTouchIcon": null,
"manifestIcons": [],
"colorPalette": {
"dominant": { "hex": "#000000", "label": "Primary Black" },
"accent": { "hex": "#0B50D0", "label": "Accent Royalblue" },
"background": { "hex": "#000000", "label": "Dark Black" }
},
"contrastRatios": {
"dominantOnWhite": 21,
"accentOnWhite": 6.8,
"backgroundOnWhite": 21
},
"ogTitle": null,
"ogDescription": null,
"ogImage": null,
"twitterCard": null,
"twitterImage": null,
"jsonLd": []
},
"billing": {
"cost": 1,
"newBalance": 44,
"message": "Successful call! 1 credit(s) charged."
}
}Cached Response
When useCache: true is set and a cached result exists within the last 24 hours, the API returns the cached data without deducting any credits. The billing response includes a cached: true flag.
{
"data": {
"siteName": "Google",
"logoUrl": null,
"faviconUrl": "https://www.gstatic.com/images/branding/searchlogo/ico/favicon.ico",
"colors": ["rgba(104, 29, 168, 1)", "rgba(50, 50, 50, 1)", ...],
"title": "Google",
"description": null,
"nearestColors": { ... },
"visualPalette": { ... },
"screenshot": null,
"logoFormat": null,
"logoWidth": null,
"logoHeight": null,
"logoSource": null,
"darkModeLogoUrl": null,
"faviconFormat": "ico",
"faviconSource": "link_icon",
"appleTouchIcon": null,
"manifestIcons": [],
"colorPalette": { ... },
"contrastRatios": { ... },
"ogTitle": null,
"ogDescription": null,
"ogImage": null,
"twitterCard": null,
"twitterImage": null,
"jsonLd": []
},
"billing": {
"cost": 0,
"newBalance": 100,
"message": "Data retrieved from cache. No credits were deducted.",
"cached": true
}
}Cache entries expire after 24 hours. The same URL extracted within that window with useCache: true will return a free cached result.
Callback / Webhook
When you provide a callbackUrl in your request, the API returns 200 immediately with a "processing" status. The extraction runs in the background and the results are sent to your URL via POST.
The API responds immediately when callbackUrl is provided. Your credits are deducted immediately.
{
"status": "processing",
"message": "Extraction started. Results will be sent to the callback URL."
}When extraction completes successfully, your callback URL receives this payload via POST.
{
"status": "completed",
"data": {
"siteName": "Stripe",
"logoUrl": "https://images.stripeassets.com/...",
"faviconUrl": "https://images.stripeassets.com/...",
"colors": ["#635BFF", "#0A2540", "#00D924"],
"title": "Stripe | Financial Infrastructure...",
"description": "Stripe is a financial services platform...",
"nearestColors": { ... },
"visualPalette": { ... },
"colorPalette": { ... },
"contrastRatios": { ... },
"...": "..."
},
"billing": {
"cost": 1,
"newBalance": 999,
"message": "Successful call! 1 credit(s) charged."
}
}If extraction fails, your callback URL receives an error payload.
{
"status": "failed",
"error": "Could not extract data from the provided URL.",
"detail": "Timeout exceeded"
}Background extractions have a 30-second timeout. If the extraction exceeds this limit, your callback will receive a "failed" payload. Credits are deducted regardless of the outcome.
Error Responses
All error responses follow the same structure, with an error message and an optional detail field.
The URL field is missing, the provided URL is invalid, or the limit parameters are out of range.
{
"error": "The \"url\" field is required."
}
// or
{
"error": "Invalid URL. Provide a URL with http or https protocol."
}
// or
{
"error": "logoColorsLimit and screenshotColorsLimit must be between 2 and 12."
}Your account doesn't have enough credits to complete the request. You'll receive an email notification.
{
"error": "Payment Required. Insufficient credits.",
"details": "Your current balance is 0 credits. This call costs 1 credit."
}The extraction took too long. This usually happens when the target website blocks the request or is unreachable.
{
"error": "Could not extract data from the provided URL.",
"detail": "Timeout exceeded"
}The extraction failed due to the website being inaccessible or returning unexpected content.
{
"error": "Could not extract data from the provided URL.",
"detail": "Failed to fetch page content"
}Status Codes
| Status | Meaning | Description |
|---|---|---|
| 200 | OK | Extraction completed successfully (synchronous). Or, if callbackUrl was provided, returns {"status":"processing"} immediately. |
| 400 | Bad Request | Missing or invalid url parameter, or limit values out of range. |
| 402 | Payment Required | Insufficient credits. Purchase more in the billing page. |
| 408 | Timeout | Extraction exceeded the time limit. Target website may be unreachable. |
| 422 | Unprocessable | Extraction failed. The website might block requests or return invalid content. |
Code Examples
Ready-to-use examples for common languages and HTTP clients. Replace YOUR_API_KEY with your actual API key.
cURL
curl -X POST https://api.brandohue.com/api/v1/extract \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://stripe.com"}'
# With caching enabled
curl -X POST https://api.brandohue.com/api/v1/extract \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://stripe.com", "useCache": true}'
# Custom color extraction options
curl -X POST https://api.brandohue.com/api/v1/extract \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://stripe.com",
"extractLogoColors": true,
"logoColorsLimit": 8,
"extractScreenshotColors": true,
"screenshotColorsLimit": 10,
"extractHtmlColors": true,
"extractCssColors": true,
"extractJsColors": false,
"hexColor": false
}'
# With callback URL (async)
curl -X POST https://api.brandohue.com/api/v1/extract \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://stripe.com", "callbackUrl": "https://your-app.com/webhook"}'JavaScript (fetch)
const response = await fetch(
'https://api.brandohue.com/api/v1/extract',
{
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://stripe.com',
useCache: false,
extractLogoColors: true,
logoColorsLimit: 6,
extractScreenshotColors: true,
screenshotColorsLimit: 12,
extractHtmlColors: true,
extractCssColors: true,
extractJsColors: false,
hexColor: false,
}),
}
);
const result = await response.json();
if (response.ok) {
console.log('Logo:', result.data.logoUrl);
console.log('Colors:', result.data.colors);
console.log('Nearest colors:', result.data.nearestColors);
console.log('Visual palette:', result.data.visualPalette);
console.log('Credits left:', result.billing.newBalance);
} else {
console.error('Error:', result.error);
}JavaScript — with callback
// Send extraction request with callback URL
const response = await fetch(
'https://api.brandohue.com/api/v1/extract',
{
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://stripe.com',
callbackUrl: 'https://your-app.com/webhook',
}),
}
);
const result = await response.json();
// { status: "processing", message: "Extraction started..." }
// Your webhook endpoint receives:
// POST /webhook
// { status: "completed", data: {...}, billing: {...} }
// or
// { status: "failed", error: "...", detail: "..." }Python (requests)
import requests
response = requests.post(
'https://api.brandohue.com/api/v1/extract',
headers={
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
json={
'url': 'https://stripe.com',
'useCache': False,
'extractLogoColors': True,
'logoColorsLimit': 6,
'extractScreenshotColors': True,
'screenshotColorsLimit': 12,
'extractHtmlColors': True,
'extractCssColors': True,
'extractJsColors': False,
'hexColor': False,
},
)
data = response.json()
if response.status_code == 200:
print(f"Logo: {data['data']['logoUrl']}")
print(f"Colors: {data['data']['colors']}")
print(f"Nearest colors: {data['data']['nearestColors']}")
print(f"Visual palette: {data['data']['visualPalette']}")
print(f"Credits left: {data['billing']['newBalance']}")
else:
print(f"Error: {data['error']}")Python — with callback
import requests
response = requests.post(
'https://api.brandohue.com/api/v1/extract',
headers={
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
json={
'url': 'https://stripe.com',
'callbackUrl': 'https://your-app.com/webhook',
},
)
data = response.json()
# { "status": "processing", "message": "Extraction started..." }
print(data['status']) # "processing"
# Your webhook endpoint receives:
# POST /webhook
# { "status": "completed", "data": {...}, "billing": {...} }
# or
# { "status": "failed", "error": "...", "detail": "..." }Node.js (axios)
const axios = require('axios');
async function extractBrand(url) {
try {
const { data } = await axios.post(
'https://api.brandohue.com/api/v1/extract',
{
url,
extractLogoColors: true,
logoColorsLimit: 6,
extractScreenshotColors: true,
screenshotColorsLimit: 12,
extractHtmlColors: true,
extractCssColors: true,
extractJsColors: false,
},
{
headers: {
'x-api-key': process.env.BRANDOHUE_API_KEY,
'Content-Type': 'application/json',
},
}
);
console.log(data.data.colors);
console.log(data.data.nearestColors);
console.log(data.data.visualPalette);
return data;
} catch (error) {
if (error.response?.status === 402) {
console.error('Insufficient credits');
}
throw error;
}
}
extractBrand('https://stripe.com');Node.js — with callback
const axios = require('axios');
async function extractWithCallback(url, callbackUrl) {
const { data } = await axios.post(
'https://api.brandohue.com/api/v1/extract',
{ url, callbackUrl },
{
headers: {
'x-api-key': process.env.BRANDOHUE_API_KEY,
'Content-Type': 'application/json',
},
}
);
// { status: "processing", message: "Extraction started..." }
console.log(data.status); // "processing"
}
extractWithCallback('https://stripe.com', 'https://your-app.com/webhook');
// Your webhook endpoint receives:
// POST /webhook
// { status: "completed", data: {...}, billing: {...} }
// or
// { status: "failed", error: "...", detail: "..." }