Construct a Wistia Embed Code
Learn to programmatically construct an embed code starting with just the video ID!
If you need to build lots of embed codes for your videos dynamically, this guide breaks down how to dynamically construct or request embed codes for each embed type.
NoteThe Wistia APIs were specifically built for videos in projects. We do not formally support using our APIs for audio files in projects, or audio or video episodes in Channels at this time. For the most reliable experience, we recommend continuing to use these for videos in projects.
Embed Code Types
Before we get started, let's define some jargon around embed code types. At this time, the two (and a half) embed code types you can use with Wistia are:
- async - in the Wistia app we call this the "Standard" embed. If you want to use the Player API to interact with your video, use this embed type.
- iframe - in the Wistia app we call this the "Fallback" embed. It's super simple, supported almost everywhere, and easy to build.
- popover - our async embed, but with more pop
Using the oEmbed Endpoint
Here's a quick primer on using the Wistia oEmbed endpoint, which is the easiest way to generate each of the Wistia embed code types.
The Endpoint
Our oEmbed endpoint is: https://fast.wistia.net/oembed
By default, the endpoint returns JSON, but use https://fast.wistia.net/oembed.xml to return XML.
Our oEmbed endpoint recognizes two URL formats, iframe embed URLs and public media URLs.
iframe Embed URLs
You can build these for single videos or generate them through your account. If you're looking to build these for a playlist, that feature has been deprecated and we recommend using embed links.
Examples
- single video -
https://fast.wistia.net/embed/iframe/26sk4lmiix
Public Media URLs
Public Media URLs are the address to a video in your account.
- example -
https://support.wistia.com/medias/26sk4lmiix
The Regex
If you're looking to automatically detect Wistia URLs and run them against our
endpoint, we recommend using this regular expression:
/https?:\/\/(.+)?(wistia\.com|wi\.st)\/(medias|embed)\/.*/
Or if you don't speak regex, here's what we're matching:
http(s)://*wistia.com/medias/*
http(s)://*wistia.com/embed/*
http(s)://*wi.st/medias/*
http(s)://*wi.st/embed/*
Note, it's likely we'll add support for more URLs in the future so feel free to use a more general regular expression so you don't miss out on future enhancements! Perhaps this:
/https?:\/\/(.+)?(wistia\.com|wi\.st)\/.*/
oEmbed Parameters
The required URL parameter that's passed in supports all the options detailed in the Player API.
We also accept some additional parameters that can change the output of the embed code:
| Name | Type | Description |
|---|---|---|
| callback | string | Only applicable to JSON requests. When specified, json is wrapped in a javascript function given by the callback param. This is to facilitate JSONP requests. |
| embedType | string | Only applicable to videos and playlists. Accepts async, iframe, async_popover, playlist_iframe, playlist_api, playlist_popover, and open_graph_tags (videos only). |
| width | integer | The requested width of the video embed. Defaults to the native size of the video or 640, whichever is smaller. |
| height | integer | The requested height of the video embed. Defaults to the native size of the video or 360, whichever is smaller. |
| handle | string | Only applicable to async, and playlist_api embed types. Sets the javascript handle. Default is wistiaEmbed for medias and wistiaPlaylist for playlists. |
You can also get a popover embed code by using the async embedType, and adding popover=true to the URL. Check out our tutorial for a full break down.
If given a width, height, maxwidth, or maxheight parameter (or any combination of those), the other dimensions in the resulting embed code may change so that the video's aspect ratio is preserved.
NoteThese parameters are attached to the Wistia media URL, and not the oEmbed call. So they must be URL-encoded to travel with the Wistia URL.
Troubleshooting
- If an invalid URL (one that doesn't match our regular expression above) is given, the endpoint will return 404 Not Found.
- If an unparseable URL is given in the URL param, the endpoint will return 404 Not Found.
- If a media is found but has no available embed code, the endpoint will return 501 Not Implemented. Only videos are embeddable.
- If a playlist is found but has no videos, the endpoint will return 501 Not Implemented.
Standard (async) Embed Tutorial
Using the oEmbed
Here is how we can get the embed code and some information for a video at https://support.wistia.com/medias/26sk4lmiix in JSON format:
Quick noteāwe have yet to update the oEmbed return to automatically return the Standard (async) embed code type. Currently, this is Wistia's recommended embed type. To call the Standard embed:
curl "https://fast.wistia.net/oembed?url=https%3A%2F%2Fsupport.wistia.com%2Fmedias%2F26sk4lmiix&embedType=async"
Which returns:
{
"version":"1.0",
"type":"video",
"html":"<script charset=\"ISO-8859-1\" src=\"//fast.wistia.com/assets/external/E-v1.js\" async></script><div class=\"wistia_embed wistia_async_26sk4lmiix\" style=\"height:540px;width:960px\"> </div>",
"width":960,
"height":540,
"provider_name":"Wistia, Inc.",
"provider_url":"https://wistia.com",
"title":"Nice.",
"thumbnail_url":"https://embed-ssl.wistia.com/deliveries/56cacb9a5d6ea04b1f29defaf4b55d1ec979e1b0.jpg?image_crop_resized=960x540",
"thumbnail_width":960,
"thumbnail_height":540,
"duration":44.457
}The html returned in the JSON body is the Standard embed code you can use to add this video to your website.
For all the fine details about the options supported, see the official oEmbed spec.
Using a Template Approach (Standard)
If you want to avoid making the additional request against the oEmbed endpoint, you can also build an Standard embed code template, and then add in the video's hashed ID.
For this example we'll be using a hashed ID of 'abcde12345'.
The basic Standard embed code looks like this:
<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script><div class="wistia_embed wistia_async_<media-hashed-id>" style="height:366px;width:600px"> </div>So to use this template with the hashed ID 'abcde12345', we insert it in
place of <media-hashed-id>:
<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script><div class="wistia_embed wistia_async_abcde12345" style="height:366px;width:600px"> </div>
NoteBecause height and width will change based on your video's content, the template approach is probably best when your entire library uses a consistent size.
If you'd like to use a responsive template:
<script charset="ISO-8859-1" src="//fast.wistia.com/assets/external/E-v1.js" async></script><div class="wistia_responsive_padding" style="padding:56.25% 0 28px 0;position:relative;"><div class="wistia_responsive_wrapper" style="height:100%;left:0;position:absolute;top:0;width:100%;"><div class="wistia_embed wistia_async_abcde12345 videoFoam=true" style="height:100%;width:100%"> </div></div></div>Popover Embed Tutorial
To grab a popover oEmbed, you can use the embedType=async_popover, or add &popover=true to the request:
curl "https://fast.wistia.net/oembed?url=https%3A%2F%2Fsupport.wistia.com%2Fmedias%2F26sk4lmiix&embedType=async&popover=true"
curl "https://fast.wistia.net/oembed?url=https%3A%2F%2Fsupport.wistia.com%2Fmedias%2F26sk4lmiix&embedType=async_popover"
Both options return:
{
"version":"1.0",
"type":"video",
"html":"<script charset=\"ISO-8859-1\" src=\"//fast.wistia.com/assets/external/E-v1.js\" async></script><span class=\"wistia_embed wistia_async_26sk4lmiix popover=true\" style=\"display:inline-block;height:100px;width:150px\"> </span>",
"width":960,
"height":540,
"provider_name":"Wistia, Inc.",
"provider_url":"https://wistia.com",
"title":"Nice.",
"thumbnail_url":"https://embed-ssl.wistia.com/deliveries/56cacb9a5d6ea04b1f29defaf4b55d1ec979e1b0.jpg?image_crop_resized=960x540",
"thumbnail_width":960,
"thumbnail_height":540,
"duration":44.457
}For more fun embed options, check out the full list of embed options.
Fallback (iframe) Embed Tutorial
Using the oEmbed
And finally, here's a quick tutorial for calling the iframe (Fallback) embed. You may also call the iframe embed code type:
curl "https://fast.wistia.net/oembed?url=https%3A%2F%2Fsupport.wistia.com%2Fmedias%2F26sk4lmiix"
This returns:
{
"version":"1.0",
"type":"video","
html":"<iframe src=\"//fast.wistia.net/embed/iframe/26sk4lmiix\" title=\"Nice. Video\" allow=\"autoplay; fullscreen\" allowtransparency=\"true\" frameborder=\"0\" scrolling=\"no\" class=\"wistia_embed\" name=\"wistia_embed\" msallowfullscreen width=\"960\" height=\"540\"></iframe>\n<script src=\"https://fast.wistia.net/assets/external/E-v1.js\" async></script>",
"width":960,
"height":540,
"provider_name":"Wistia, Inc.",
"provider_url":"https://wistia.com",
"title":"Nice.",
"thumbnail_url":"https://embed-ssl.wistia.com/deliveries/56cacb9a5d6ea04b1f29defaf4b55d1ec979e1b0.jpg?image_crop_resized=960x540",
"thumbnail_width":960,
"thumbnail_height":540,
"player_color":"f27398",
"duration":44.42
}Note the html returned in the JSON body is the iframe embed code you can use to add this video to your website.
Using a Template Approach (Fallback)
Just like the Standard embed, you can build an iframe embed code template, and swap out the video's hashed ID.
Again, for this example we'll be using a hashed ID of 'abcde12345'.
The basic iframe embed code looks like this:
<iframe src="https://fast.wistia.net/embed/iframe/<media-hashed-id>?seo=true&videoFoam=false" title="video-title" allow="autoplay; fullscreen" allowtransparency="true" frameborder="0" scrolling="no" class="wistia_embed" name="wistia_embed" msallowfullscreen width="640" height="360"></iframe>
<script src="https://fast.wistia.net/assets/external/E-v1.js" async></script>So to use this template with the hashed ID 'abcde12345', we insert it in place of <media-hashed-id>:
<iframe src="//fast.wistia.net/embed/iframe/abcde12345?seo=true&videoFoam=false" title="video title " allow="autoplay; fullscreen" allowtransparency="true" frameborder="0" scrolling="no" class="wistia_embed" name="wistia_embed" msallowfullscreen width="640" height="360"></iframe>
<script src="https://fast.wistia.net/assets/external/E-v1.js" async></script>
NoteBecause height and width will change based on your video's content, the template approach is probably best when your entire library uses a consistent size.
Just like the Standard embed, the iframe embed can be responsive. Here's the template:
<div class="wistia_responsive_padding" style="padding:56.25% 0 0 0;position:relative;"><div class="wistia_responsive_wrapper" style="height:100%;left:0;position:absolute;top:0;width:100%;"><iframe src="https://fast.wistia.net/embed/iframe/abcde12345?seo=true&videoFoam=true" title="video title " allow="autoplay; fullscreen" allowtransparency="true" frameborder="0" scrolling="no" class="wistia_embed" name="wistia_embed" msallowfullscreen width="100%" height="100%"></iframe></div></div>
<script src="https://fast.wistia.net/assets/external/E-v1.js" async></script>AMP Embed Tutorial
Wistia videos are compatible with AMP HTML pages as well! You'll just want to make sure your AMP webpage includes the following script:
<script async custom-element="amp-wistia-player" src="https://cdn.ampproject.org/v0/amp-wistia-player-0.1.js"></script>Then you can embed your Wistia video by placing it inside of an amp-wistia-player tag like so:
<amp-wistia-player
data-media-hashed-id="abc123"
width="700"
height="394"
></amp-wistia-player>We have an example of how that all looks on a live webpage here. For further information regarding supported layouts for the embed, you can go to the AMP webpage here.
Using JSONP
JSONP is a javascript technique used to get information from a server that is not the same origin as your current domain. This means they can avoid cross-domain security issues.
In this example, we'll write some javascript to pull data for our video against the oEmbed endpoint, utilizing JSONP. Then, we'll manipulate the data returned to embed the thumbnail image.
Given the oEmbed base URL, your account URL, and a media hashed id, we can use the jQuery getJSON function to call against the oEmbed endpoint to return the video data.
Note this function also takes a callback function as a parameter. We'll set up that callback function next.
var baseUrl = "https://fast.wistia.com/oembed/?url=";
var accountUrl = encodeURIComponent("https://home.wistia.com/medias/");
var mediaHashedId = "01a1d9f97c";
function getThumbnailUrl(hashedId, callback) {
$.getJSON(baseUrl + accountUrl + hashedId + "&format=json&callback=?", callback);
}This function will return a JSON data object, and pass it to our callback function, which will parse the JSON and log the thumbnail URL. Let's write that callback function now:
function parseJSON(json) {
console.log(json.thumbnail_url);
};Finally, we'll setup something to call these functions for our media hashed id:
getThumbnailUrl(mediaHashedId, parseJSON);Working With The Thumbnail
Part of the JSON returned by the oEmbed is the thumbnail_url. This URL is a direct link to the thumbnail image asset. If your implementation involves using the thumbnail image (i.e. building your own 'popover' embeds, displaying your own play button, etc.) you should use this thumbnail image, which by default has no Wistia play button overlaid on it.
See our working with Wistia images guide for more info!
Embedding in sandboxed iframes and WebViews
If you're embedding a Wistia player inside a sandboxed iframe, a mobile WebView, or any other locked-down browser context, the player has a couple of requirements that aren't obvious until something breaks. This section covers what the player needs, the errors you'll see when it doesn't get it, and how to fix it for both the current Aurora player and legacy embeds.
Why the player needs same-origin access
Whichever embed you use, the Wistia player reads localStorage while it boots ā it's how the player persists small bits of state like volume. In a normal embed that's invisible. But if the player ends up running inside an <iframe sandbox="ā¦">, the browser blocks localStorage access unless you explicitly allow it, and the player stalls ā usually showing the poster image or thumbnail and never starting playback.
You'll see one of these in the browser console:
Uncaught SecurityError: Failed to read the 'localStorage' property from 'Window':
The document is sandboxed and lacks the 'allow-same-origin' flag.
In Firefox the same problem reads:
Uncaught DOMException: Window.localStorage getter: Forbidden in a sandboxed
document without the 'allow-same-origin' flag.
The root cause is always the same: the player is running in a sandbox that's missing the flags it needs. Where the sandbox attribute lives ā and therefore where you fix it ā depends on which embed you're using.
Aurora player (<wistia-player> / player.js)
<wistia-player> / player.js)The Aurora embed is a web component that runs directly in your page's context ā there's no Wistia-owned iframe wrapping it:
<script src="https://fast.wistia.com/player.js" async></script>
<script src="https://fast.wistia.com/embed/abc123.js" async type="module"></script>
<wistia-player media-id="abc123"></wistia-player>So Aurora only hits the sandbox problem when your whole page is itself loaded inside a sandboxed iframe or a WebView ā for example, an embed-within-an-embed, or a page rendered inside a mobile app's WebView shell. The fix is on that outer container, not on anything Wistia gives you: whoever controls the iframe that wraps your page needs to include allow-scripts and allow-same-origin in its sandbox attribute.
<!-- the iframe that loads YOUR page, controlled by the host -->
<iframe
src="https://your-site.example.com/page-with-wistia-player"
sandbox="allow-scripts allow-same-origin"></iframe>If you don't control that outer iframe, the player can't be made to work inside it ā the host has to relax the sandbox.
Legacy embeds (E-v1.js)
E-v1.js)Legacy Standard (async) and iframe (Fallback) embeds load the older E-v1.js script. The iframe embed ships its own Wistia-owned iframe, so the sandbox attribute lives on the embed code itself. If you must keep it, add both allow-scripts and allow-same-origin:
<iframe
src="https://fast.wistia.net/embed/iframe/abcde12345"
sandbox="allow-scripts allow-same-origin"
title="video title"
allow="autoplay; fullscreen"
allowtransparency="true"
frameborder="0"
scrolling="no"
class="wistia_embed"
name="wistia_embed"
msallowfullscreen
width="640"
height="360"></iframe>With the legacy iframe embed you may also see a companion error as the player navigates its own inner frame ā same root cause:
Unsafe attempt to load URL https://fast.wistia.net/embed/iframe/<hashed-id> from
frame with URL https://fast.wistia.net/embed/iframe/<hashed-id>#?secret=ā¦
Domains, protocols and ports must match.
Security note
allow-scriptstogether withallow-same-originlets the framed document remove its own sandboxing. That's fine for content you trust (a Wistia embed served fromfast.wistia.net), but don't apply this combination to untrusted third-party content in the same frame. If you can't grantallow-same-origin, drop thesandboxattribute on the Wistia iframe entirely rather than leaving it half-configured.
A common culprit: auto-oEmbedSome platforms (WordPress, for example) will auto-convert a pasted Wistia URL into their own sandboxed preview iframe ā WordPress uses
sandbox="allow-scripts", with noallow-same-originā which triggers exactly this failure. The fix is to stop the platform from oEmbed-ing the URL: paste Wistia's real embed code into a raw-HTML / custom-HTML block instead of pasting a bare link.
Mobile WebViews and local HTML
Mobile WebViews (iOS WKWebView, Android WebView, and cross-platform wrappers like Flutter's webview_flutter) hit the same storage requirement as a sandboxed iframe, plus two more assumptions the player makes ā these apply to both the Aurora and legacy players:
- JavaScript and DOM storage must be enabled. The player needs both to boot. In most WebViews these are on by default, but some wrappers disable DOM storage ā turn it back on (for example,
domStorageEnabled = trueon Android'sWebSettings). - The host page needs a real origin. Loading your embed HTML from a
file://URL or a raw HTML string gives the WebView an opaque ornullorigin, which trips the same same-origin storage restriction you see in a sandboxed iframe. Serve the page overhttp(s)ā even a local dev server ā so the embed runs against a normal origin.
Choosing between embed types
Switching embed types alone won't fix a sandbox error ā every Wistia player needs the same storage access. Choose based on how much control you have over the page:
- Aurora player (
<wistia-player>) ā Wistia's current embed and the right default. Because it runs directly in your DOM, there's no Wistia iframe boundary to configure; you only deal with sandboxing if your whole page is framed by someone else. - Legacy Standard (async) embed ā drives the player from your page with the older Player API; also injects into your DOM, so no inner iframe to configure.
- Legacy iframe (Fallback) embed ā self-contained and supported almost everywhere, which is exactly why it tends to end up inside a
sandboxā so remember theallow-scripts allow-same-originrequirement above.
If you've granted the right sandbox flags (or removed sandbox), enabled DOM storage, and served the page over a real origin, and the player still won't start, grab the console error and reach out to Support ā the exact error text tells us which assumption is being violated.
Embedding Options and Plugins
Once you have your embed code built, you probably want to tailor the appearance and behavior to your wishes. You may also want to add a plugin like Wistia Forms or a Call-to-Action.
For a list of available embedding options to be used with the Customize API, check our Embedding Options Documentation.
Retrieving .m3u8 files
For those that would like to create an .m3u8 playlist for all videoās assets, the fast.wistia.net/embed/medias/<hashed_id>.m3u8 endpoint will return the .m3u8 manifest and allow for adaptive playback. We do not recommend using this method as it will pull the video file outside of our player; as a result, you donāt get any stats, analytics, or customizations. Using them, however, does count towards your accountās bandwidth.
Updated 5 days ago