Brand Kits
Apply consistent colors, fonts, logos, and styling across every chart — without touching each spec. Six built-in presets, plus custom kits you manage via the dashboard or API.
Built-in presets
Pass the preset name directly as brandKitId — no dashboard setup required:
| brandKitId | Description |
|---|---|
| obsidian | Dark slate background, emerald accent — high contrast dark mode |
| linen | Warm off-white background, subtle grid — clean and readable |
| polar | Cool blue-grey palette — suited for analytical dashboards |
| studio | Neutral studio tones — versatile across light and dark contexts |
| ember | Warm orange-red palette — energetic and bold |
| harbor | Muted coastal tones — calm and professional |
{
"type": "bar",
"brandKitId": "obsidian",
"data": {
"labels": ["Jan", "Feb", "Mar", "Apr"],
"datasets": [{ "label": "Revenue", "data": [12000, 15000, 18000, 22000] }]
}
}Before & after
The same chart spec with and without a brand kit — one line added, completely different output:
Without brand kit (system default)
{ "type": "bar", "data": { ... } }With brandKitId: "obsidian"
{ "type": "bar", "brandKitId": "obsidian", "data": { ... } }Custom brand kits
Via the dashboard
- Go to Brand Kits in your dashboard
- Click Create kit
- Set colors, font, grid style, corner rounding, and optionally a logo URL
- Save — you get a UUID to use as
brandKitId
Via the API
POST /api/v1/brand-kits
{
"name": "Acme Corp",
"primaryColor": "#e85729",
"accentColor": "#3a6cf5",
"font": "Inter",
"gridStyle": "subtle",
"rounding": 4,
"isDefault": false,
"logoUrl": "https://acme.com/logo.png",
"logoHeight": 32,
"logoAlign": "right"
}The response includes an id (UUID). Pass it as brandKitId in render requests.
Logo
Saved brand kits can carry a logoUrl that is automatically rendered in the header region of full-card compositions. You can also set it per-request on header.logoUrl without a brand kit.
| Field | Default | Description |
|---|---|---|
| logoUrl | — | HTTPS image URL. HTTP is rejected. Private/loopback hosts are blocked. |
| logoHeight | 32 px | Rendered height in logical pixels (range 16–120). Width is calculated from aspect ratio. |
| logoAlign | 'right' | Which side of the header the logo is pinned to: 'left' or 'right'. |
{
"type": "bar",
"width": 800,
"height": 480,
"brandKitId": "your-kit-uuid",
"header": {
"eyebrow": "Q4 2024",
"title": "Monthly Revenue",
"logoUrl": "https://acme.com/logo.png",
"logoHeight": 28,
"logoAlign": "right"
},
"data": {
"labels": ["Jan", "Feb", "Mar"],
"datasets": [{ "label": "Revenue", "data": [12000, 15000, 18000] }]
}
}If the logo URL is unreachable at render time, the logo is silently skipped — the render completes normally.
Per-request theme override
The theme object lets you override any brand-kit token on a per-render basis. Useful when a preset is close but you need a custom background or palette for a specific chart.
{
"type": "line",
"brandKitId": "polar",
"theme": {
"backgroundColor": "#0f172a",
"palette": ["#60a5fa", "#34d399", "#f472b6"],
"mode": "dark"
},
"data": { ... }
}Theme precedence chain
When multiple sources define the same token, the highest-priority source wins:
- Per-request
theme— highest priority - Brand kit (preset or saved UUID)
- Template defaults (when using a template)
- Raw Chart.js values in your spec
- System defaults — lowest priority
Saved kit fields
| Field | Required | Description |
|---|---|---|
| name | yes | Human-readable name for the dashboard |
| primaryColor | yes | Main chart elements (bars, lines, first series) |
| accentColor | yes | Secondary elements and highlights |
| palette | no | Array of hex colors overriding the two-color generation logic |
| backgroundColor | no | Card and chart background color |
| font | no | Inter (default), Roboto, Source Sans, Montserrat, or DM Sans |
| mode | no | "light" or "dark" — affects axis tick and legend text color |
| gridStyle | no | "none" or "subtle" |
| rounding | no | Bar corner radius in px: 0, 4, or 8 |
| isDefault | no | When true, applied automatically when brandKitId is omitted |
| logoUrl | no | HTTPS URL of the logo image (card compositions only) |
| logoHeight | no | Rendered logo height in logical pixels (16–120, default 32) |
| logoAlign | no | "left" or "right" (default "right") |