Wistia

to the tippy ↑

Async Embeds

Warning: You are heading into developer territory!

Our APIs are designed for programmers. If our APIs were a ski trail, they'd be a nice blue cruiser - anyone can do it, but expect to fall a few times if you don't know what you're doing!

If you're new to web development, we recommend taking a lesson before you hit our slopes. Try a class from Frontend Masters or Skillshare!

Async API embeds work a lot like traditional API embeds, except we have a different way of setting options and getting an API handle. These docs explain how Async API (or Standard) embeds work.

How to get an Async Embed Code

Async embeds are here! Wistia's Standard and Popover embeds are asynchronous. Just navigate to the Embed and Share modal and select the "Standard Embed" from the "Inline Embed" tab, choose the "Popover Embed" tab. It's seriously that easy.

Note that iframe embeds are already async because that's just how iframes work.

Playlists are not asynchronous. But we've got Embed Links, which are better anyway. :)

The Composition of an Async API Embed

Here's an example async API embed, straight out of the embed modal:

wistia_js.js
1
2
<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script>
<div class="wistia_embed wistia_async_g5pnf59ala videoFoam=true" style="width:640px;height:360px;">&nbsp;</div>

First, we have an async script tag for E-v1.js.

<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script>
<div class="wistia_embed wistia_async_g5pnf59ala videoFoam=true" style="width:640px;height:360px;">&nbsp;</div>

This script tag can go anywhere on your page. Header, footer, before the embed, after the embed, it doesn't matter. That script loads our video embedding libraries into the window.Wistia namespace and watches the page for markup that looks like async Wistia embed codes.

Next we have the video container.

<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script>
<div class="wistia_embed wistia_async_g5pnf59ala videoFoam=true" style="width:640px;height:360px;">&nbsp;</div>

The video container is where your video will be placed when all the initialization steps are complete. The video container's attributes control how the video is initialized.

As part of the video container, first, the wistia_embed class.

<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script>
<div class="wistia_embed wistia_async_g5pnf59ala videoFoam=true" style="width:640px;height:360px;">&nbsp;</div>

The wistia_embed class is a signal to our embedding library that this container is a Wistia embed. Without this, we cannot get a handle to the API.

Second, the wistia_async_hashedid class.

<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script>
<div class="wistia_embed wistia_async_g5pnf59ala videoFoam=true" style="width:640px;height:360px;">&nbsp;</div>

This class tells our embedding library two things: (1) it's an async embed, and (2) it should embed a video with hashed ID g5pnf59ala. When you grab your embed code from the Embed Modal, it will have its own hashed ID unique to the video.

Third, option=value style classes.

<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script>
<div class="wistia_embed wistia_async_g5pnf59ala videoFoam=true" style="width:640px;height:360px;">&nbsp;</div>

In this case, we set videoFoam to true. But you could also set any options available in the Embedding Options page. If you're setting more than one option, just separate them with spaces. If your option's value includes spaces, then percent encode it!

Side note: You might say, "hey, that's not a valid class!" But alas, it is. All characters--except the null terminator--are valid in the class attribute. Some are just much harder to target with CSS rules, which is not necessary in this case. For more info, check out Mathias's notes on CSS escapes, the HTML5 id and class attributes, and his demos of CSS escapes with crazy classes.

We chose to set options in the class attribute because they are less likely than HTML5 data- attributes to be stripped out of CMSes, and the syntax aligns nicely with options for our iframe embeds.

Fourth, the style attribute.

<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script>
<div class="wistia_embed wistia_async_g5pnf59ala videoFoam=true" style="width:640px;height:360px;">&nbsp;</div>

By default, we always define a width and height for the video. We recommend always using values in px to set the width and height, and using videoFoam if the video needs to be responsive. Also, to avoid issues with video foam and fullscreen, we recommend NOT adding borders, padding, or margin directly to the video container. Instead, you should create a wrapper element and add them there.

Last, the contents of the container.

<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script>
<div class="wistia_embed wistia_async_g5pnf59ala videoFoam=true" style="width:640px;height:360px;">
  &nbsp;
</div>

By default, we have an invisible space &nbsp; as the content, which means nothing appears in the element until the video is ready. You can change this to be any HTML. When the video initialization is complete, this content will be completely replaced by the video.

Using the Wistia library asynchronously

Because E-v1.js is loaded asynchronously, we need to make sure any code that references it only runs after window.Wistia is defined. There are a few ways to do that.

The simplest way is as follows:

async_wistia_init.js
1
2
3
window.wistiaInit = function(W) {
  console.log("Wistia library loaded and available in the W argument!");
};

That function will be called as soon as E-v1.js loads. If E-v1.js is already loaded when you define the function, it will execute asynchronously in 500ms or less.

If you are writing code that is supposed to be repeatable--say for your entire website, or as a snippet for other users--we recommend using the following form instead:

async_wistia_init.js
1
2
3
4
window.wistiaInitQueue = window.wistiaInitQueue || [];
window.wistiaInitQueue.push(function(W) {
  console.log("Wistia library loaded and available in the W argument!");
});

window.wistiaInitQueue functions the same way as window.wistiaInit except it will not clobber any other functions that have been defined to run on initialization.

Getting an API handle

Traditional API embeds set the wistiaEmbed variable right in the embed code. We can't do that with async embeds, so we need to use a new method: the Wistia.api() function.

async_api_handle.html
1
2
3
4
5
6
7
<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script>
<div id="my_video" class="wistia_embed wistia_async_g5pnf59ala" style="width:640px;height:360px;">&nbsp;</div>
<script>
window.wistiaInit = function(W) {
  W.api("my_video").play();
};
</script>

In that snippet, we defined an ID attribute on the video container, then referenced that ID after the Wistia library was initialized.

Now that you have a handle to the video, you can use it just like a traditional API embed, with the Player API.

Setting embed options

The option=value method is very simple if you only need to make a few small adjustments. But if you want to set more complex inline options, it gets a little clunky. In that case, you might want to use the Wistia.options function.

Note that these options only affect videos that are embedded after Wistia.options() is called. Videos that are already embedded will not be affected.

async_api_options.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script>
<div id="my_video" class="wistia_embed wistia_async_g5pnf59ala" style="width:640px;height:360px;">&nbsp;</div>
<script>
window.wistiaInit = function(W) {
  W.options("my_video", {
    autoPlay: true,
    plugin: {
      "socialbar-v1": {
        buttons: "facebook-twitter"
      }
    }
  });
};
</script>

The setup for this is similar to getting an API handle. We define an ID attribute on the video container, then reference it in the options function.

<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script>
<div id="my_video" class="wistia_embed wistia_async_g5pnf59ala" style="width:640px;height:360px;">&nbsp;</div>
<script>
window.wistiaInit = function(W) {
  W.options("my_video", {
    autoPlay: true,
    plugin: {
      "socialbar-v1": {
        buttons: "facebook-twitter"
      }
    }
  });
};
</script>

You can also set options globally for all embeds on a page by not specifying an ID. For example, I can say that all videos on this page should have a red playerColor:

async_api_options.js
1
2
3
window.wistiaInit = function(W) {
  W.options({ playerColor: "ff0000" });
};

How async embeds are initialized (for the curious)

The Wistia library defines Wistia.embeds.setup() which finds all (or a subset of) async video containers on the page and initializes them as Wistia videos. This function is called as soon as E-v1.js loads for the best experience. Once E-v1.js is loaded, it will watch the DOM forever for new Wistia embeds.

To setup that watch, we use a feature of modern browsers called mutation observers. They allow us to efficiently detect whenever a <div> with a wistia_embed and wistia_async_hashedid class is added to the DOM. Older browsers don't have mutation observers, so in those, we poll the DOM once every 500ms for any matching elements that have not been initialized.

The following information is for micro-optimization on older browsers. Going forward, this will be less and less important, so we advise only making these micro-optimizations if you have no other choice.

If you want to prevent any initialization lag in older browsers, you can call Wistia.embeds.setup() immediately after you inject a Wistia embed into the page.

If you have a site with an extremely large number of <div> elements and are optimizing for older browsers, you might want to turn off our automatic watch. To do that, you can add this javascript:

async_dont_watch.js
1
2
window.wistiaInitQueue = window.wistiaInitQueue || [];
window.wistiaInitQueue.push(function(W) { W.embeds.dontWatch(); });

If you choose to turn off the watch, then you will need to call Wistia.embeds.setup() manually whenever you inject a new Wistia embed into the DOM.