Web: embed and WebGPU

Put a live, talking avatar on any web page with one iframe. It renders in the bitHuman cloud, or in the visitor's tab with WebGPU.

bitHuman cloud In the browser (WebGPU)
sofia-ramirez, the Essence 2 sample avatar

Live in your browser, no account. Up to 3 minutes; allow the microphone when asked.

The avatar renders in the bitHuman cloud, and the conversation runs on bitHuman's servers.

The web surface is one URL: https://www.bithuman.ai/embed/<CODE>. Put it in an <iframe> and the page gets a live avatar that listens and answers. By default the avatar renders in the bitHuman cloud and streams to the page; with render=local it renders in the visitor’s tab with WebGPU. There is no npm package, no install and no secret in the browser.

Captured on Chrome 154 on Linux · the web embed · sofia-ramirez (Essence 2) · 2026-09-27. The visitor's question is the microphone input, mixed into the recording.

Before you start

  • A current browser. For lip-sync rendered in the tab, a usable GPU (WebGPU).
  • An agent code: A23WJF0199 (the wise-pup sample) or your own from Agents.
  • For a private agent, an embed token minted by your server.

Authenticate

A public agent needs no credential. For a private agent, your server mints an embed token with your API secret and passes it to the page. Sessions bill the agent’s owner: credits pay for session time, talking or idle, and the conversation (speech recognition, language model and voice) bills in every mode (pricing).

First frame

<!doctype html>
<html>
  <body style="margin:0">
    <iframe src="https://www.bithuman.ai/embed/A23WJF0199"
            allow="microphone *" style="width:100%;height:100vh;border:0"></iframe>
  </body>
</html>

Expected: the avatar appears, asks for the microphone, and answers when you speak. Keep the * in allow, or the microphone is blocked. To try it without a page, open https://www.bithuman.ai/embed/A23WJF0199.

Complete example

A whole page with a live avatar: one HTML file and a local web server.

Requirements

You needNotes
A current browserChrome, Edge, Safari or Firefox
A local web serverthe page must be served over http://localhost or HTTPS for the microphone to work
Nothing elseno account for the sample avatar; your own agent works the same way while its Anonymous Share setting is on, and its sessions bill you

Get the code

Save this as index.html:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>bitHuman web embed</title>
  <style>
    html, body { margin: 0; height: 100%; background: #0f1115; }
    body { display: flex; align-items: center; justify-content: center; }
    iframe { border: 0; border-radius: 16px; }
  </style>
</head>
<body>
  <iframe src="https://www.bithuman.ai/embed/A23WJF0199"
          allow="microphone *; camera *; autoplay *" style="width:100%;height:100vh;border:0"></iframe>
</body>
</html>

Run it

python3 -m http.server 8765 --bind 127.0.0.1

Open http://127.0.0.1:8765/ and allow the microphone.

Expected output

The avatar greets you within a few seconds. Speak, or type into the Type or speak… box, and it answers out loud with its lips in sync. The red button ends the session.

How it works

The iframe loads the hosted viewer for agent A23WJF0199. The viewer opens a real-time session: your microphone audio goes to the agent, and the agent’s voice and video come back. allow="microphone *" lets the iframe ask for the microphone; without the * the browser blocks it. URL parameters are on Web; session events on Embedding.

Make it your own

  • Your own avatar: replace A23WJF0199 with your agent code. Anyone with the code can open it and sessions bill your account; turn off Anonymous Share in the agent’s sharing settings to stop that.
  • Push what it says: from your backend, POST /v1/agent/{code}/speak makes a live avatar say a line (Agents).
  • Size and layout: any width and height work; keep roughly a 7:12 portrait shape for Expression 2 avatars.

Integrate into your app

Add parameters to the URL:

ParameterValuesEffect
rendercloud (default), localWhere the avatar renders: our servers, or the visitor’s tab
rendering_modebrowser, avatarLong form of render=local; avatar renders in the tab and lip-syncs the visitor’s own microphone, with no conversation
greetingLanga language code, for example esLanguage of the first greeting
greetingMsgtextThe first thing the avatar says

A private agent also takes token, and a session can pin its model with model; both are on Embedding. Other parameters are ignored.

Render in the visitor’s tab (WebGPU)

render=local renders the avatar in the visitor’s browser tab with WebGPU. It works for any avatar you can embed and is off by default: without it, every session renders in the bitHuman cloud and streams to the page.

  • One download: the avatar’s web bundle (50–200 MB) downloads to the browser once, then comes from the cache. Tell visitors before it starts on a metered connection.
  • Fallback: a browser without a usable GPU is switched to cloud rendering, so every visitor gets lip-sync.
  • Where the conversation runs: with the web embed, the conversation runs on bitHuman’s servers, even when the avatar renders in the tab (render=local).
  • Private agents: the embed token the iframe already uses covers it (Embedding).
THE VISITOR'S BROWSER TABThe avatar renders in the tabWebGPUBITHUMAN'S SERVERSThe conversation runs herespeech recognition, language model, voicemicrophoneaudiothe voice reply
The web embed with render=local. With render=local the avatar renders in the visitor's browser tab with WebGPU. The conversation runs on bitHuman's servers, even when the avatar renders in the tab: the microphone audio goes to bitHuman and the voice reply comes back.

Check for a usable GPU before you choose render=local:

async function hasRealGPU() {
  if (!navigator.gpu) return false;
  const once = async () => { try { return (await navigator.gpu.requestAdapter()) ?? null; } catch { return null; } };
  const adapter = (await once()) ?? (await once());   // the first request can return null while the GPU starts
  return !!adapter && adapter.isFallbackAdapter !== true && adapter.info?.isFallbackAdapter !== true;
}
const mode = (await hasRealGPU()) ? "local" : "cloud";
iframe.src = `https://www.bithuman.ai/embed/A23WJF0199?render=${mode}`;

Do not send Cross-Origin-Embedder-Policy from the page that holds the iframe: the embed does not send one itself, so the browser refuses to load it.

React and other frameworks

There is no npm package: the embed is an iframe in any framework. In React:

export function Avatar({ code }) {
  return <iframe src={`https://www.bithuman.ai/embed/${code}`} allow="microphone *" style={{ width: "100%", height: 600, border: 0 }} title="Talking avatar" />;
}

For a floating avatar, one script tag adds a widget to any page, Next.js included (Website widget). The persona and your own model are settings on the agent (Providers), so there is no server to run.

To build your own video UI instead of the hosted page, subscribe to a cloud-rendered avatar over LiveKit.

Platform notes

  • Expression 1 avatars render in the cloud only.
  • The in-tab render works for Essence 1, Expression 2, and Essence 2 avatars that have a browser build.

Performance

Measured in the tab with WebGPU. The figures are the engine’s render speed in Chrome on an Apple M4, not the frame rate a visitor sees.

ConfigurationEssence 2Expression 2
Chrome on Apple M4 Web browser (WebGPU)
1.7× real timeChrome on Apple M4 · web viewer · measured 2026-09-27
1.9× real timeChrome on Apple M4 · web viewer · measured 2026-09-27
Chrome on Apple M4 Web browser (WebGPU) held 10 min
2.1× real timeChrome on Apple M4 · web viewer · held 10 min · measured 2026-09-27
2.0× real timeChrome on Apple M4 · web viewer · held 10 min · measured 2026-09-25

Times real time: seconds of avatar video rendered per second. At 1.0× or more, an avatar holds a live conversation. Select a figure for its release and date. All configurations and how we measure.

Troubleshooting

SymptomCauseFix
The microphone never activatesallow is missing microphone *use allow="microphone *"
404the agent code is wrong, or the agent is privatecheck the code; mint an embed token for a private agent
render=local reloads as render=cloudno usable GPU (WebGPU) in this browser, or this Essence 2 avatar has no browser buildnothing to do; it is served from the cloud. Check hasRealGPU() first to choose the mode yourself
The iframe shows a browser error pageyour page sends Cross-Origin-Embedder-Policyremove that header from the page that holds the iframe
A blank framea service problemcheck status.bithuman.ai, then reload
Your own avatar shows Embedding is disabled for this agentits Anonymous Share setting is offturn Anonymous Share back on in the agent’s sharing settings

Reference