Cookbook
Agents & skills · for AI agents

Brand the chat — colours and logo

Match a customer's brand on a share link or embedded widget: one colour, a logo, and CSS only when the brand guide demands it.

MCP tools:list_sharesconfigure_share

Principle — give one colour, not a palette. Foreground colours are derived from it on save, so every combination stays readable. Picking your own text colours is how you ship a button nobody can read.

Branding lives on the share, not the agent: the same agent can be a white-label widget on one site and a plain link somewhere else. So get the token first.

list_shares(agent_name="mortgage-advisor")
# → [{ token: "RuqY…", label: "Website widget", config: { theme_color: "#F7B331", … } }]
 
configure_share(
  agent_name="mortgage-advisor",
  token="RuqY…",
  theme_color="#F7B331",
  logo_url="https://cdn.example.com/brand/mark-512.png",
)

Only the fields you pass change — the rest of the configuration is left alone.

Colour: pass one, get four

theme_color is the brand's primary colour, #RGB or #RRGGBB. On save the platform derives the foregrounds by WCAG contrast and stores them:

DerivedUsed for
theme_color_fgtext on the brand colour — send button, user bubbles, unread badge
theme_color_textthe brand colour used as text, on a light background
theme_color_text_darkthe same, on a dark background

A light brand colour therefore gets dark text on it rather than white. #F7B331 with white text measures 1.83:1 — below even the 3:1 floor for UI components, meaning the label is genuinely unreadable; the derived dark foreground measures 10.21:1.

Do not compute a palette yourself and do not try to set the text colours — they are server-derived and your values are overwritten. Passing one colour is the whole job.

Clearing it (theme_color="") drops the derived values too and returns the widget to the default blue. Leaving it unset does the same — the built-in tokens are already a matched pair.

Logo: aspect ratio decides where it can be used

Pass an absolute URL. The logo appears in two places with different constraints:

  • Header bar — height-aligned, width free. Any aspect ratio works, including a wide wordmark.
  • Collapsed bubble — square, because the logo is the shape of the bubble. Only ratios between 0.74 and 1.35 are used here; a wide wordmark falls back to the platform icon instead of being squeezed into a strip too small to read.

So for a wide wordmark, the practical answer is two files: the wordmark for the header, a square mark for the bubble. If the customer only has a wordmark, the header still shows their brand and the bubble shows a neutral icon — better than an illegible sliver.

Do not crop a wordmark to square. Cropping leaves half a word, which is no longer their trademark.

When the brand guide overrides everything

Some customers have a strict palette that will not follow ours in either theme. custom_css is injected after the brand variables, so a plain declaration already wins — no !important needed. (It used to be required, because the colours were set as inline styles. They are not any more.)

⚠️ Read this before writing any CSS

You must write two blocks: :root for light, html[data-theme="dark"] for dark.

:root matches in both themes and outranks the platform's dark rules (same specificity, and yours comes later). So a palette written only under :root means the visitor's light/dark toggle changes nothing at alldata-theme flips, no variable follows it.

This has already happened in production: an agent put a full dark palette under :root, the page looked great, and the theme button became a dead control that nobody noticed for weeks. The page looks correct, which is exactly why this goes unreported.

If the customer genuinely wants one theme only, set the share's theme field to light or dark instead. That hides the toggle rather than breaking it.

Correct shape — copy this and replace the values:

/* LIGHT — the light values go here, not the dark ones */
:root{
  --acc: #6b21a8;        /* brand primary — backgrounds, focus rings */
  --acc-fg: #ffffff;     /* text on --acc: YOU own the contrast here */
  --acc-text-l: #581c87; /* brand colour used as text, light theme */
  --bg: #fdfbff;
  --surface: #ffffff;
  --text: #1e1b2e;
  --border: #e6e0f0;
}
/* DARK — required whenever you touched --bg / --surface / --text above */
html[data-theme="dark"]{
  --acc: #a855f7;
  --acc-fg: #1a0b2e;
  --acc-text-d: #c084fc; /* note: -d, the dark-theme variant */
  --bg: #120c1d;
  --surface: #1c142b;
  --text: #f0e9ff;
  --border: #32254a;
}

That is the full set worth overriding — the widget consumes few colours on purpose.

Which variables need the dark block? The ones that describe the surface, because they invert between themes: --bg, --surface, --text, --border. --acc is the brand colour and normally stays the same in both, though the example brightens it for the dark theme because a deep purple on a near-black background is hard to see.

Two more things to hold on to:

  • custom_css carries no readability guarantee. theme_color does. Reach for CSS only for what the derivation cannot express, and keep theme_color set as the baseline.
  • Setting --acc-text-l and --acc-text-d to the same value defeats their purpose. They exist precisely so the brand colour can be readable as text against opposite backgrounds.

configure_share returns a warnings array when it detects the single-:root mistake — read it. The console shows the same warning next to the CSS editor.

css_url loads an external stylesheet instead, for customers who keep their own theme file.

Also on the share

  • input_modetext (default) or voice, which opens straight into hold-to-talk. Needs a speech-to-text backend enabled on the platform.
  • launcher — the bubble's hover tooltip.
  • theme — force light / dark, or leave empty to follow the visitor's system setting. Prefer empty: the widget sits inside the customer's page and should match it.

Verify

Open the chat_url from list_shares and look at the send button. If the label is hard to read, theme_color is not set and something is overriding it — check custom_css for a hard-coded color.