Docs / Guides /Deploy

Embed widget

Drop a talking avatar onto any website with a single iframe — zero backend — and mint short-lived embed tokens for per-visitor session tracking.

Drop-in iframe

Embed an agent as an iframe — no SDK install, drop it on any page. The avatar runs in bitHuman’s cloud; your page just hosts the frame:

<iframe
  src="https://bithuman.ai/embed/A78WKV4515"
  allow="microphone *; camera *; autoplay *"
  style="width: 400px; height: 700px; border: none; border-radius: 12px;"
></iframe>

Replace A78WKV4515 with your agent code — find it in the Library or the Deploy & Share dialog. URL parameters customize the widget.

Note The allow attribute must grant microphone (and camera, if you use vision) to the embed origin. If the parent page sets a restrictive Permissions-Policy, allowlist agent.viewer.bithuman.ai or the mic prompt won’t appear in some browsers.

Production: mint short-lived embed tokens

For per-visitor session tracking and rate limiting, mint a short-lived embed token from your backend and pass it to the iframe. Your api-secret never reaches the browser. (The mint endpoint authenticates your api-secret upstream and is covered by a per-IP request limit rather than your plan tiers.)

// SERVER — mint a token (api-secret stays server-side)
const res = await fetch("https://api.bithuman.ai/v1/embed-tokens/request", {
  method: "POST",
  headers: {
    "api-secret": process.env.BITHUMAN_API_SECRET,
    "content-type": "application/json",
  },
  body: JSON.stringify({
    agent_id: "A78WKV4515",
    fingerprint: visitorFingerprint,   // stable per-device hex — required
  }),
});
const { data: { token } } = await res.json();
<!-- BROWSER — pass the token in the iframe URL -->
<iframe
  src="https://bithuman.ai/embed/A78WKV4515?token=YOUR_TOKEN"
  allow="microphone *; camera *; autoplay *"
  style="width: 400px; height: 700px; border: none;"
></iframe>

The token is a 1-hour JWT (HS256-signed). Mint one per visitor session. Both agent_id and fingerprint are required; the response also returns a sid session identifier for tracking the embed instance. See POST /v1/embed-tokens/request for the full request shape.

Pin a serving tier

By default the platform routes each session down the model’s serving chain (GPU → Apple Neural Engine → CPU), overflowing on capacity (details). For benchmarking or placement testing, append ?model= with a force-tier slug (essence-2-gpu/-ane/-cpu, expression-2-gpu/-cpu/-ane) to the embed (or viewer) URL to pin the session to that tier — a forced tier never overflows:

<iframe
  src="https://bithuman.ai/embed/A66GYD8664?token=YOUR_TOKEN&model=expression-2-cpu"
  allow="microphone *; camera *; autoplay *"
  style="width: 400px; height: 700px; border: none;"
></iframe>

The tier slugs per model are listed in each model guide — Expression 2, Essence 2, Essence 2 Max (single tier). An unrecognized value falls back to the agent’s default routing. For production, omit ?model= and let the platform choose — direct elastic tiers scale from zero and can cold-start on first connect (what to expect).

Prefer validating the choice when you mint the token: pass model in the POST /v1/embed-tokens/request body and the API checks it up front — an unknown value returns 400, and a model family the agent can’t be launched as (a per-identity artifact that hasn’t been generated, or essence-2-max on an agent with no stored identity video — generated internally by Essence creations) returns 409 MODEL_NOT_GENERATED rather than a session that fails to start. The mint response’s supported_models array tells you which model families the agent can launch as right now — send those values straight back as model, mapping the two internal tier spellings first (essence-2-lightessence-2, essence-2-qualityessence-2-max; the former is rejected with 400 by POST /v1/video/generate).

Webhooks

bitHuman POSTs to your endpoint when session events occur. Return 200 immediately and offload work to a queue — long handlers risk the timeout.

room.join — fired once when a user connects:

{ "agent_code": "A80HVD8577", "event_type": "room.join",
  "data": { "room_name": "support", "participant_count": 1,
            "session_id": "session_xyz" }, "timestamp": 1705312200.0 }

chat.push — fired per message (user and agent):

{ "agent_code": "A80HVD8577", "event_type": "chat.push",
  "data": { "role": "user", "message": "help with order #12345",
            "session_id": "session_xyz" }, "timestamp": 1705312285.0 }

Endpoint setup, signature verification, and retry policy are in the API reference.

Where to go next