PlayerConcepts

Element vs iframe

How to reach the player in each embed mode, and what the iframe does not expose

The player ships in two embed modes, and the choice shapes everything else in this documentation: how you get a reference to the player, and which features you can reach at all.

The custom element puts <vturb-smartplayer> directly in your page. The iframe loads the player from converteai.net in a separate browsing context, and the SDK bridges the two.

Getting a reference to the player

On the custom element, the player is an element in your own DOM, so you query for it:

player.js
const player = document.querySelector("vturb-smartplayer");

player.addEventListener("video:play", (event) => {
  console.log("video:play");

  // the player reference is available on the event
  console.log(event.target);

  // use it to call the player methods
  event.target.play();
});

You still have to wait for player:ready before calling methods — the element exists in the DOM before the player behind it is initialized.

On the iframe, your page cannot reach inside. The SDK dispatches iframe:connected on the <iframe>, bubbling up to document, once the bridge is up, and hands you an IframePlayer in event.detail.player:

player.js
// don't call methods before the connection:
// window.vturbSdk.get("PLAYER_ID") returns undefined until then,
// and window.vturbSdk itself is undefined until the SDK script loads

document.addEventListener("iframe:connected", (event) => {
  // identify which player connected
  if (event.detail.id !== "PLAYER_ID") return;

  const player = event.detail.player;

  // the iframe player is connected now
  player.fullscreen();
});

// or, listening on the iframe element itself

const iframe = document.getElementById("ifr_PLAYER_ID");

iframe.addEventListener("iframe:connected", (event) => {
  const player = event.detail.player;
  // do something
});

Because the event fires for every player on the page, event.detail.id is how you tell them apart.

player:ready never fires on the iframe, and iframe:connected never fires on the element. Code that waits for the wrong one waits forever.

What the iframe does not expose

Everything below works on the custom element and is unavailable — or behaves differently — inside an iframe. Not by omission: the browser's cross-origin rules make most of it impossible.

FeatureElementIframe
Events and methodsyesyes, after iframe:connected
player:readyyesno, use iframe:connected
CSS variablesyesno, cross-origin
fluid, pauseonetouchyesno
injectUrlUpdateryesno
Headline custom JSyesyes, but not under a CSP

If you need to restyle the player, the custom element is the only mode that allows it. Styling is the most common reason teams move off the iframe embed.

Which one to use

Reach for the iframe when you cannot control the host page well enough to add a script tag, or when the page belongs to a platform that strips custom elements. Everywhere else the custom element is the better default: same API surface, no bridge to wait for, and the customization and attributes stay available.

On this page