Skip to main content
The widget’s look and behavior come from two places: the project’s Embed tab in the dashboard (fetched at runtime, per key) and inline data-* / init overrides on the page. Config from the dashboard means you can change the widget’s appearance and limits without editing the script tag on your site.

The Embed tab

Open your project and go to the Embed tab. Each embed key carries:
FieldWhat it controls
Embed key (pk_live_…)The publishable key in your script tag. Shown in full once at creation; rotate to get a new value.
Allowed originsThe scheme+host+port allowlist. A browser request from an origin not on the list is refused at token mint. No wildcards.
Theme (JSON)The widget’s look + copy (see fields below). Stored server-side and delivered at runtime. Capped in size.
Anonymous spend capA hard ceiling on what anonymous (non-verified) traffic on this key can cost per period. On hit, the widget shows a friendly limit_reached state.
Identity-verification secretThe per-key HMAC secret for verified identity. Generate / rotate / reveal-once / clear here.
Enable / disableReversibly turn the key off without deleting it. A disabled key mints no tokens.
RotateReplace the key value (the old one stops working); all other config carries over.
RevokePermanently retire the key.

Runtime config

The loader fetches the key’s config from GET /v1/embed/config at mount, keyed by the embed key and gated by the browser’s real Origin. It returns only the theme and feature flags - never the allowed-origins list. So you can recolor the widget, change the greeting, or toggle the footer from the dashboard and it takes effect on the next load, with no code change on your site. Config is merged in this precedence (later wins):
built-in defaults  <  server config (Embed tab)  <  data-* attributes  <  init overrides
The server-config fetch is optional - if it is unavailable, the widget falls back to defaults + data-* and never throws into your page.

Theme fields

Set these in the Embed-tab theme JSON, or inline with data-theme-* (camelCase becomes kebab-case), or in karta("init", { theme: {...} }).
Fielddata-theme-*Notes
accentdata-theme-accentPrimary color (launcher, buttons, links).
accentForegrounddata-theme-accent-foregroundText/icon color on the accent.
positiondata-theme-positionbottom-right (default) or bottom-left.
colorSchemedata-theme-color-schemelight, dark, or auto (default).
launcherIcondata-theme-launcher-iconEmoji or short glyph in the launcher.
agentNamedata-theme-agent-nameTitle shown in the header.
agentAvatardata-theme-agent-avatarURL or emoji.
greetingdata-theme-greetingFirst-open assistant message.
suggestedPromptsdata-theme-suggested-promptsPipe-separated on the tag: `“ABC”`.
showPoweredBydata-theme-powered-byfalse hides the footer.
The agent name and greeting are also localizable, along with every other visible string and screen-reader label, via the locale map on the theme. The widget can show an optional pre-chat disclosure before the first message - for example, to tell users their chat is processed by an AI assistant and link to your privacy policy.
<script
  async
  src="https://cdn.karta.sh/widget/v1/karta.js"
  data-embed-key="pk_live_xxx"
  data-project="coffeeco/support-bot"
  data-theme-consent="true"
  data-theme-consent-text="This chat is AI-assisted. See our [privacy policy](https://example.com/privacy)."
  data-theme-consent-require-accept="true"
></script>
or via the theme object:
karta("init", {
  theme: {
    consent: {
      enabled: true,
      text: "This chat is AI-assisted. See our [privacy policy](https://example.com/privacy).",
      requireAccept: true,
    },
  },
});
OptionEffect
enabledShow the disclosure line above the composer. Default false.
textThe disclosure markdown. Rendered through the same escape-first sanitizer as assistant text - only basic formatting + http/https/mailto links survive, so a privacy-policy link is safe and no executable markup can reach the page.
requireAcceptShow an Accept button that must be clicked before the composer is usable. Acceptance is remembered per identity, so it is not re-shown on every reload.
The disclosure is associated with the composer for screen readers (aria-describedby), and the Accept button is keyboard-focusable. See Security & privacy for what you should disclose.

Next

Command API & events

Drive the configured widget from your page.

Security & privacy

Origin allowlist, spend cap, and the data path in depth.