Skip to main content
The widget supports three levels of end-user identity. They differ in one thing: whether the server can trust who the user is.
LevelHow it is setTrusted by the server?
AnonymousNothing - the defaultNo. A per-browser visitor id is generated for continuity only.
Softkarta("identify", { userId }) / data-user-idNo. Advisory metadata; any page can set any value.
VerifieduserId + an HMAC identityTokenYes. The token proves your server vouches for this userId.

Anonymous

With no identity set, the widget stores a random visitor id in localStorage so a reload resumes the same conversation in the same browser. Nothing about the user is asserted to the server.

Soft (advisory) identity

Pass a userId (and optional attributes) to label the session for your own analytics and to key reload continuity:
karta("identify", { userId: "u_123", attributes: { plan: "pro" } });
Soft userId is advisory and is never used for auth or credentials. Any page can set any value, so the server does not bind it into the session token
  • it rides only as client-side session metadata. Do not use it to gate access to per-user data. For that, use verified identity below.

Verified identity (HMAC)

Verified identity proves to Karta that your server vouches for this userId, so the agent can safely act on per-user data. You sign the userId with a per-key secret; the widget forwards the signature; Karta verifies it and binds the verified subject into the short-lived session token.

The scheme

Compute the token on your server (never in the browser - the secret must not ship to a client):
identity_token = HMAC-SHA256(identity_verification_secret, userId)   // lowercase hex
  • The secret is the identity_verification_secret you generate on the project’s Embed tab. It is server-only and never shown in a browser.
  • The message is the exact userId string you also pass to the widget.
  • The output is lowercase hexadecimal (a SHA-256 HMAC, 64 hex chars).

Server-side signing

import crypto from "node:crypto";

function kartaIdentityToken(userId) {
  return crypto
    .createHmac("sha256", process.env.KARTA_IDENTITY_SECRET)
    .update(userId)
    .digest("hex"); // lowercase hex
}
Render the token into the page (it is per-user, short by nature, and safe to expose to that user’s browser - it only proves that user’s id).

Wiring it into the widget

Pass the userId and identityToken together - on the tag:
<script
  async
  src="https://cdn.karta.sh/widget/v1/karta.js"
  data-embed-key="pk_live_xxx"
  data-project="coffeeco/support-bot"
  data-user-id="u_123"
  data-identity-token="<hmac-hex-from-your-server>"
></script>
or via the command API:
karta("identify", {
  userId: "u_123",
  identityToken: serverMintedHmacToken,
});
The widget forwards user_id + identity_token to the embed token mint (POST /v1/embed/session-tokens). Karta recomputes the HMAC with the constant-time compare and, on a match, mints a session token whose sub is bound to that userId. A bad signature is rejected; a userId with no token stays soft (never bound).
The identityToken is not an auth source on its own - the embed key (or session token) is the credential. The token only upgrades a soft userId to verified. Its validation is entirely server-side.

Backend-minted tokens (alternative)

If you already mint session tokens server-side with a kt_live_… API key, skip the embed key entirely and hand the widget a token function or endpoint. Your backend holds the secret key; the browser only ever sees the short-lived token.
karta("init", {
  projectRef: "coffeeco/support-bot",
  tokenEndpoint: "/api/karta-token", // your endpoint returns { token }
});
Your endpoint calls POST https://api.karta.sh/agent_projects/:slug/session_tokens with your kt_live_… key and returns the minted JWT. Because the kt_live_… key is the trust anchor here, the subject you put on the token is authoritative without an HMAC. See Session tokens. The headless client also accepts a refreshable tokenFn (re-called with { force: true } after a 401) - see Headless & React.

Next

Theming & config

Generate and rotate the identity secret on the Embed tab.

Security & privacy

The credential boundaries and the data path.