Skip to navigation

Interactive Avatar: Add the widget to your website

Put an Interactive Avatar on your website without building any UI.

The managed widget is the Synthesia-hosted way to add an Interactive Avatar to your website. Create a deployment in Studio, paste its snippet into your page, and Synthesia runs the experience end to end: the widget, the conversation and the call. You don’t need API keys, an LLM or a room of your own.

For full control over the avatar’s brain (your own LLM and speech stack) and over room management, use the bring-your-own integration instead.

Add the widget

Adding the widget takes three steps. You do the first two in Studio and the last one on your page.

1. Create a deployment

In Studio, create a deployment for your avatar. A deployment holds the widget’s settings, such as which avatar to show, how it looks and which sites may use it. Its type decides which snippet you get on the Deploy tab. Both snippets load the same widget, but they give you different options:

TypeSnippetWhat you get
WidgetA script tagA floating bubble or an inline frame. You can control it from your page and hold it back until the visitor consents.
EmbedAn iframe tagThe avatar inline at a fixed size, with no script on your page. There’s no bubble, no page API and no consent deferral.

Use an Embed if your page allows frames but not third-party scripts. Otherwise, use a Widget. An Embed is always open in place, so the deployment’s corner, starting state and logo settings don’t apply to it.

2. Allow your site’s origin

The widget only runs on sites you allow, so a copy of your snippet on someone else’s site stays blank. Add every origin that shows the widget to the deployment’s allowed origins. The match is exact, so https://www.example.com and https://example.com are two different origins. If your site uses both, add both.

A subdomain pattern such as https://*.example.com covers the subdomains of example.com, but not example.com itself. You can’t use * on its own to allow any origin, so list each origin or use a subdomain pattern.

On an origin that isn’t allowed, the browser refuses to show the widget frame (see Errors for what your page gets). If another site shows your page inside its own frame, read Frames and page builders too.

3. Paste the snippet into your page

Copy the snippet from the Deploy tab and paste it into your page. A Widget’s script snippet looks like this:

<script
async
src="https://interactive-avatars.synthesia-embeds.io/v1/runtime.js"
data-deployment-id="dep_…"
></script>

An Embed gives you an iframe snippet instead, described in Embed with an iframe. If your site sends security headers, check Security policies before you go live.

Script snippet attributes

The script snippet reads its settings from data- attributes on the script tag. The snippet from Studio already has the deployment ID. Add the other attributes when you need them:

AttributeRequiredDescription
data-deployment-idYesThe ID of the deployment to show.
data-modeNobubble (default) shows a floating bubble in a corner. inline puts a frame inside your layout.
data-targetNoIn inline mode, a CSS selector for the container the frame goes into. The container must exist when the script runs. If it doesn’t, or you leave this out, the frame goes right after the script tag. If the tag is in <head>, the frame goes at the end of the page.
data-consentNoSet to deferred to load nothing until you call init(). See Consent deferral.
data-titleNoThe frame’s accessible title, which screen readers announce.

You set the bubble’s corner, colors and logo on the deployment in Studio, not with attributes.

The bubble shows above your page’s content, whatever its z-index. Dialogs and popovers your page opens later show above the bubble. On screens narrower than 640 pixels, such as phones, the bubble starts minimized and opens full screen.

The bubble can cover a cookie banner in the same corner. Pick another corner in Studio, or use consent deferral.

Use the custom element

The script also defines a custom element, <synthesia-interactive-avatar>. It’s often easier to work with than a script tag if you use a framework or a CMS block, because you can add and remove it like any other element. Load the script without a deployment ID, and give the element the same attributes without the data- prefix:

<script
async
src="https://interactive-avatars.synthesia-embeds.io/v1/runtime.js"
></script>
<synthesia-interactive-avatar
deployment-id="dep_…"
mode="inline"
></synthesia-interactive-avatar>

In inline mode, the frame goes inside the element. In bubble mode, the element stays empty and the bubble floats over the page.

Single-page apps

Here’s how the widget behaves when your app changes routes or replaces parts of the page:

  • If your app inserts a script tag later, its widget mounts when the tag is inserted. If your app renders the same tag again while the widget is on the page, nothing changes, and a call in progress keeps going.
  • When an element leaves the page, its widget is destroyed. The exception is an element your app puts back synchronously, in the same task, as frameworks do when they move an element. A new element with the same deployment ID that takes its place in the same task mounts as well. Moving an inline element reloads its frame, because browsers reload any iframe that moves.
  • Each deployment mounts once per page. A second tag or element with the same deployment ID is ignored while the first one’s widget is on the page, and takes over once that widget is gone.

Some libraries navigate by replacing the page’s <body> instead of loading a new page. Here’s what happens to the widget with the common ones:

  • With Turbo Drive, you get a new, idle widget in the new body, and a call in progress ends with the old body. A tag with consent deferral comes back deferred, so call init() again, as on the first page load.
  • With htmx’s hx-boost, the body’s content is replaced and the tag in it runs again, with the same result. Keep the tag inside the body.
  • Swup, jquery-pjax and Barba swap a container rather than the whole body, so the bubble stays where it is.
  • When the browser restores a cached copy of the page on a back navigation, the widget mounts once, without a second bubble.

An inline frame inside a data-target container moves with that container. If your app takes the container out of the page and puts it back, the frame comes back with it, reloaded. After a body swap, a tag with the same deployment ID in the new body takes over and places the frame where its own data-target says. If the new body has no such container, the frame goes right after the tag, as on a first load of that page.

Embed with an iframe

The iframe snippet is a single tag with no script on your page. It loads https://interactive-avatars.synthesia-embeds.io/v1/dep_… in a 400 × 620 frame.

Keep the allow and referrerpolicy attributes the snippet comes with. allow gives the widget the microphone and autoplay, and referrerpolicy lets it check your origin. Security policies explains both.

Frames and page builders

If another site shows your page inside a frame, the origin check covers that site too, not only your page. The widget stays blank unless that site’s origin is allowed as well. This happens in:

  • Page builder editors and previews, such as Webflow Designer, the WordPress or Elementor customizer and the Shopify theme editor.
  • Learning management systems, intranet portals and other sites that show your page in a frame.

Add those origins to the deployment as well. Each frame between the top page and the widget also needs:

  • allow="microphone". A frame can only pass on the microphone it was given, so one missing attribute blocks the microphone.
  • No sandbox attribute, or one that includes both allow-scripts and allow-same-origin. Without them, the widget can’t run.

Shopify

Shopify serves your store on two origins, so allow both. Add your custom domain and your store’s exact https://your-store.myshopify.com origin. You can’t use a *.myshopify.com pattern, because every Shopify store shares the myshopify.com domain.

Load the script from our URL

Always load runtime.js from https://interactive-avatars.synthesia-embeds.io/v1/runtime.js. Don’t copy it to your server, bundle it into your app or serve it through a proxy. The script reads its own URL to find the widget, so a copy on your origin points the frame at your origin and the widget doesn’t load.

We also ship fixes to runtime.js without any change to your page, and a copy never gets them. Browsers and our edge each cache it for up to five minutes, so a fix reaches your visitors within about ten minutes.

Don’t add an integrity attribute (Subresource Integrity). The file changes with every release, so a pinned hash stops the widget from loading after our next release. crossorigin="anonymous" is fine, because we serve the script with CORS headers.

Supported browsers

The widget needs a current browser with WebRTC and microphone access, such as Chrome, Edge, Firefox or Safari. Internet Explorer isn’t supported. Your page must use HTTPS, because browsers only give the microphone to secure pages.

Next steps

Once the widget is on your page, these pages help you control it, keep it compliant and plan for updates.