Content-Security-Policy
If your site sends a CSP, allow the widget the following. These assume the default data-plane originhttps://agent.karta.sh; if you set a custom
data-base-url, use that origin for connect-src instead.
script-src https://cdn.karta.sh- the async loader (karta.js) and the UI/core chunk it lazily imports are both served from the CDN.connect-src https://agent.karta.sh- the widgetfetches the embed token mint (/v1/embed/session-tokens), runtime config (/v1/embed/config), and the streaming session API (/{org}/{project}/v1/…) from the data plane. Use yourdata-base-urlorigin here if you override it.style-src 'unsafe-inline'- the widget renders inside a Shadow DOM and injects its stylesheet as an inline<style>element in the shadow root. It does not (and cannot) carry your page’s CSP nonce, so an inlinestyle-srcallowance is required for the widget’s CSS.
The widget does not use
eval or new Function, so no
script-src 'unsafe-eval' is needed. The Shadow DOM keeps the widget’s
styles off the rest of your page regardless of the inline style-src
allowance.data-theme-agent-avatar pointing at an image),
also allow that image host in img-src. Emoji/text avatars need nothing.
Origin allowlist
The publishablepk_live_… embed key is meant to ship in your page’s HTML - it
is not a secret. Its blast radius is fenced by the allowed-origins allowlist,
not by hiding the key.
- The browser sends its real
Originheader on the token mint. The data plane reads that header (never a body-supplied value, which a hostile page could spoof) and refuses the mint if the origin is not on the key’s allowlist. - The match is exact on scheme + host + port. There are no wildcards - list each origin you embed on.
- Rotating or disabling the key on the Embed tab cuts off token minting immediately.
The safety model
The widget never holds a long-lived credential, and anonymous traffic is bounded:- Short-lived session tokens. The embed key is exchanged for a short-lived, project-scoped session token per session. The browser only ever holds that expiring token, never an API key.
- Anonymous spend cap. Each key has a hard ceiling on what anonymous (non-verified) traffic can cost per period, set on the Embed tab. On hit, minting stops.
- Rate limits. The token-mint edge is rate-limited per IP, as a backstop against a key being hammered from one source.
Graceful limits
When a usage, spend, or rate limit is hit, the widget does not show a raw error. It shows a calm “check back later” state, locks the composer so the user cannot keep hammering a capped assistant, and emits a first-classlimit_reached event (with an optional
retryAfterSeconds) so your page can respond - for example, surfacing a contact
form. A hard cap has no client-side recovery within the page’s lifetime; the
limit clears server-side on its period boundary.
Privacy & data path
Be accurate with your users about where their chat goes:- Chat content reaches Karta and the model provider. Messages the end user types are sent to the Karta data plane and on to the model provider that backs the agent (your own, under BYOK, or Karta’s). Running an agent necessarily means its operator processes the content it handles - see Trust & compliance.
- Soft identity is advisory. A soft
userIdor attributes you attach are metadata, never an auth credential, and any page can set them. Do not put secrets in attributes. Use verified identity to bind a trusted subject. - The optional pre-chat consent string. The widget can show a pre-chat disclosure before the first message - with an optional Accept gate - to tell users the chat is AI-assisted and link your privacy policy. The disclosure text is sanitized through the same escape-first renderer as assistant output, so it is safe to author but cannot contain executable markup.
What you should disclose
As the site embedding the widget, you are the data controller for your users’ chats. Disclose, per your jurisdiction, that:- conversations are processed by an AI assistant and sent to Karta and a model provider to generate replies;
- what you log or retain on your side (the widget persists a lightweight
transcript in the user’s browser
localStoragefor reload continuity, keyed per identity, and clears it on an explicit shutdown/reset); - how a user can reach a human, if you wire the
escalatehook.
Related
Session tokens
The short-lived, project-scoped credential the embed key is exchanged for.
Identity
Anonymous, soft, and verified (HMAC) end-user identity.
Trust & compliance
The platform’s broader security posture and operator access.
BYOK
Keep your model-provider credentials under your own control.