Wistia and oEmbed

oEmbed is a simple API to get information about embedded content on a URL. For Wistia, it's a great way to programmatically get embed codes for videos if you have their URLs.

Grab embed codes using your video's URL with oEmbed, an easy API to implement with Wistia.

The Endpoint

Our oEmbed endpoint is: https://fast.wistia.com/oembed

Pass a Wistia URL as the url parameter and the endpoint returns an embed code (plus metadata) for that media. The endpoint is host-agnostic — it matches on the URL path, not the domain — so a URL on your own Wistia subdomain (your-subdomain.wistia.com/...), on home.wistia.com, or on a wi.st short domain all work the same way.


Media URLs

These are the URL forms that point at a single piece of media. All four resolve to the same embed code for that media:

FormExampleNotes
/medias/<hashed_id>https://your-subdomain.wistia.com/medias/e4a27b971dCanonical form. The ID is the media's hashed ID.
/medias/<hashed_id>/managehttps://your-subdomain.wistia.com/medias/e4a27b971d/manageThe trailing /manage is accepted and resolves identically — you don't have to strip it.
/m/<hashed_id>https://your-subdomain.wistia.com/m/e4a27b971dShort form. Uses the same hashed ID as /medias/.
/s/<slug>https://your-subdomain.wistia.com/s/a1b2c3d4Share link. The slug is a different identifier from the media hashed ID (see below).

/m/ and /medias/ share an ID — /s/ does not

/m/<id> and /medias/<id> use the same hashed ID, so you can convert between them with a path-only swap.

A /s/<slug> share link is its own identifier space — the slug is not the media hashed ID. The endpoint maps the slug back to the underlying media, but a find-and-replace from /medias/ to /s/ (or vice versa) will not produce a working link, because the slug and the hashed ID are different values.

📝

Share links only resolve while unlocked

A /s/<slug> URL resolves through oEmbed only when the share link is unlocked. A locked share link returns an empty response. Treat /s/ as "valid input, but only resolves for unlocked share links" — don't assume every /s/ link will return an embed.


Channel URLs

A channel is embedded through a single URL form. Unlike media, one of the two channel URLs you'll encounter is not a valid oEmbed input:

FormValid oEmbed input?What it is
https://fast.wistia.com/embed/channel/<hashed_id>YesThe channel share link — the URL the channel's share affordance and the Customize modal hand you. Use this one.
https://<your-subdomain>.wistia.com/channels/<hashed_id>NoThe channel's page URL (the logged-in, account-gated destination you see in the address bar). Returns an empty response from the oEmbed endpoint.
⚠️

Use the share link, not the page URL

Paste the fast.wistia.com/embed/channel/<hashed_id> share link into the oEmbed endpoint. The your-subdomain.wistia.com/channels/<hashed_id> page URL is not a valid input — it returns an empty response.

Note one asymmetry: when the share link resolves, the canonical url field in the response points back at the /channels/ page URL. The endpoint emits that /channels/ URL but won't accept it as input — don't feed the response's url value back in.

The response is a script embed, not an iframe

A channel oEmbed returns "type": "rich". The html is a channel.js <script> tag plus a <div class="wistia_channel ..."> container — not an <iframe>. This is by design: channels are not iframe-compatible, so they use a script-based embed rather than the iframe embed you get for a single media.

By default the embed renders as a popover at 360×360.

For example:

curl "https://fast.wistia.com/oembed?url=https%3A%2F%2Ffast.wistia.com%2Fembed%2Fchannel%2F9c5u5vvz1d"

returns:

{
  "version": "1.0",
  "type": "rich",
  "html": "<script src=\"https://fast.wistia.com/assets/external/channel.js\" async></script><link rel=\"stylesheet\" href=\"https://fast.wistia.com/embed/channel/project/9c5u5vvz1d/font.css\" /><div class=\"wistia_channel wistia_async_9c5u5vvz1d mode=popover\" style=\"height:360px;position:relative;width:360px;\"></div>",
  "provider_name": "Wistia, Inc.",
  "provider_url": "https://wistia.com",
  "title": "Talking Too Loud with Chris Savage",
  "url": "https://home.wistia.com/channels/9c5u5vvz1d",
  "thumbnail_url": "https://embed-ssl.wistia.com/deliveries/0d2f9fb0f948e4c6dd6bae96299e0a65/file.?image_crop_resized=200x200",
  "thumbnail_width": 200,
  "thumbnail_height": 200
}

Embedding a channel inline

To render the channel inline (in the page flow) instead of as a popover, pass mode=inline on the channel URL. As with media parameters, this travels with the url value, so it must be URL-encoded:

https://fast.wistia.com/embed/channel/<hashed_id>?mode=inline
⚠️

Inline embeds need explicit dimensions

Unlike the popover (which defaults to 360×360), an inline embed has no default size. You must give it dimensions one of two ways:

  • pass both width and height, or
  • pass responsive=true for a fluid-width embed.

If you request mode=inline without width/height and without responsive=true, the returned embed has empty width/height values (height:px;width:px;) and won't lay out correctly.

So pass dimensions explicitly:

https://fast.wistia.com/embed/channel/<hashed_id>?mode=inline&width=960&height=600

which returns a container styled height:600px; width:960px;. Or go fluid with responsive=true:

https://fast.wistia.com/embed/channel/<hashed_id>?mode=inline&responsive=true

which returns a container styled min-height:100vh; width:100%;. You can also use maxwidth / maxheight to cap dimensions.

Embedding a channel as a playlist

A channel's videos can also be embedded as a playlist by passing mode=playlist. There's no separate playlist URL — a playlist is a mode of the channel embed, so you use the same channel share link:

https://fast.wistia.com/embed/channel/<hashed_id>?mode=playlist

This returns "type": "rich" — a playlist.js <script> plus a <wistia-playlist> web component bound to the channel:

{
  "version": "1.0",
  "type": "rich",
  "html": "<script src=\"https://fast.wistia.com/playlist.js\" async></script><wistia-playlist channel-id=\"9c5u5vvz1d\"></wistia-playlist>",
  "provider_name": "Wistia, Inc.",
  "provider_url": "https://wistia.com",
  "title": "Talking Too Loud with Chris Savage"
}

Pass responsive=true for a fluid-width playlist (which adds a responsive="true" attribute and drops fixed width/height); width / height / maxwidth / maxheight work here too.


📝

Domain Restrictions apply at render time, not at the endpoint

If a channel has Domain Restrictions enabled, the oEmbed endpoint still resolves and returns the embed code normally. The restriction is enforced when the embed renders: on a domain that isn't on the channel's approved list, the channel shows "This channel is not authorized to be here" instead of playing. So a successful oEmbed response does not guarantee the channel will display — the page it's embedded on must be on an approved domain.


Live Event URLs

A live event is embedded through either of two URL forms — they behave identically:

FormExample
/live/events/<hashed_id>https://your-subdomain.wistia.com/live/events/u3l2wffdc9 (audience share link)
/live/<hashed_id>https://your-subdomain.wistia.com/live/u3l2wffdc9 (address-bar form)

Both resolve the same event. The URL form is not what determines the embed — the embedType parameter is.

embedType is required

A live event URL has no default embed type. You must pass an embedType parameter, URL-encoded onto the url value, or the endpoint returns an error:

curl "https://fast.wistia.com/oembed?url=https%3A%2F%2Fyour-subdomain.wistia.com%2Flive%2Fevents%2Fu3l2wffdc9"

Returns:

{"error": "Live event embed code type is required."}

This is expected behavior, not a broken URL — the fix is to add an embedType, not to change the URL. There are exactly two valid values: webinar and registration. Any other value returns an enum error:

{"error": "Unknown live event embed code type 'foo'. Expected one of the following: registration, webinar."}

📝

Event States

The endpoint doesn't gate on event state. The oEmbed endpoint returns an embed regardless of whether the event is upcoming, live, or ended — a webinar embed resolves normally for an event that already finished. The live/replay/ended experience is resolved by the embed component when it renders, not by the endpoint (the same render-time pattern as channel Domain Restrictions).

embedType=webinar

The webinar type embeds the event experience itself — the room, with the registration → live → replay progression handled inline by the component. It returns "type": "rich": a webinar-v1.js <script> plus a <wistia-webinar> web component.

curl "https://fast.wistia.com/oembed?url=https%3A%2F%2Fyour-subdomain.wistia.com%2Flive%2Fevents%2Fu3l2wffdc9%3FembedType%3Dwebinar"
{
  "version": "1.0",
  "type": "rich",
  "html": "<script src=\"https://fast.wistia.net/assets/external/webinar-v1.js\" async></script><wistia-webinar event-id=\"u3l2wffdc9\"></wistia-webinar>",
  "provider_name": "Wistia, Inc.",
  "provider_url": "https://wistia.com",
  "title": "Live Event - Jun 1st, 2026"
}

Pass a width parameter to set a fixed pixel width on the component (e.g. &width=960 renders <wistia-webinar ... style="width: 960px;">).


embedType=registration

The registration type returns the event's registration entry point — a form.js <script> plus a bare <wistia-form> web component bound to the event:

curl "https://fast.wistia.com/oembed?url=https%3A%2F%2Fyour-subdomain.wistia.com%2Flive%2Fevents%2Fu3l2wffdc9%3FembedType%3Dregistration"
{
  "version": "1.0",
  "type": "rich",
  "html": "<script src=\"https://fast.wistia.net/assets/external/form.js\"></script><wistia-form live-event-id=\"u3l2wffdc9\"></wistia-form>",
  "provider_name": "Wistia, Inc.",
  "provider_url": "https://wistia.com",
  "title": "Live Event - Jun 1st, 2026 Registration Form"
}
📝

What this renders is state-dependent

The oEmbed registration output is always this bare

⚠️

Never embed host or panelist links

Only the audience links (/live/events/


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)\/.*/

An Example

Get the embed code and metadata for a media at https://home.wistia.com/medias/e4a27b971d in JSON format. The url parameter must be URL-encoded:

curl "https://fast.wistia.com/oembed?url=https%3A%2F%2Fhome.wistia.com%2Fmedias%2Fe4a27b971d"

This returns:

{
  "version": "1.0",
  "type": "video",
  "html": "<iframe src=\"https://fast.wistia.net/embed/iframe/e4a27b971d\" title=\"Brendan - Make It Clap 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": "Brendan - Make It Clap",
  "thumbnail_url": "https://embed-ssl.wistia.com/deliveries/2d2c14e15face1e0cc7aac98ebd5b6f040b950b5.jpg?image_crop_resized=960x540",
  "thumbnail_width": 960,
  "thumbnail_height": 540,
  "player_color": "174bd2",
  "duration": 16.51
}

If you're looking for XML instead of JSON, use: https://fast.wistia.com/oembed.xml

For all the fine details about the options supported, see the official oEmbed spec.


Parameters

Our endpoint supports all the options detailed at oembed.com.

The required url parameter that's passed in supports all the options detailed in the Embed Options Documentation.

We also accept some additional parameters that can change the output of the embed code:

NameTypeDescription
callbackstringOnly applicable to JSON requests. When specified, JSON is wrapped in a javascript function given by the callback param. This is to facilitate JSONP requests.
embedTypestringOnly applicable to videos. Accepts iframe, async, async_popover, and open_graph_tags (videos only).
widthintegerThe requested width of the video embed. Defaults to the native size of the video or 360, whichever is smaller.
heightintegerThe requested height of the video embed. Defaults to the native size of the video or 640, whichever is smaller.
popoverHeightintegerOnly applicable to "popover" embed type. The requested height of the popover. Defaults to maintain the correct aspect ratio, with respect to the width.
popoverWidthintegerOnly applicable to "popover" embed type. The requested width of the popover. Defaults to 150.

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.

📝

Note

These 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.

Example

In this example, we'll request an API embed code type, with the javascript handle oEmbedVideo:

First, the media URL we'll request:

https://home.wistia.com/medias/e4a27b971d

Next, we'll add the parameters for our request:

https://home.wistia.com/medias/e4a27b971d?embedType=api&handle=oEmbedVideo

We'll URL-encode this request:

https%3A%2F%2Fhome.wistia.com%2Fmedias%2Fe4a27b971d%3FembedType%3Dapi%26handle%3DoEmbedVideo

📝

Note

We URL-encoded this request, because we want the parameters embedType and handle passed along as part of the url param, not at the top level of the oembed endpoint.

And now use the oEmbed endpoint:

curl "https://fast.wistia.com/oembed.json?url=http%3A%2F%2Fexplanatoryvideos-1.wistia.com%2Fmedias%2F5u2svaqmbt%26embedType%3Dseo%26width%3D593"

This returns:

{
  "version":"1.0",
  "type":"video",
  "html":"<div id=\"wistia_e4a27b971d\" class=\"wistia_embed\" style=\"width:640px;height:360px;\" data-video-width=\"640\" data-video-height=\"360\">&nbsp;</div>\n<script charset=\"ISO-8859-1\" src=\"//fast.wistia.com/assets/external/E-v1.js\"></script>\n<script>\noEmbedVideo = Wistia.embed(\"e4a27b971d\", {\n  version: \"v1\",\n  videoWidth: 640,\n  videoHeight: 360\n});\n</script>",
  "width":640,
  "height":360,
  "provider_name":"Wistia, Inc.",
  "provider_url":"https://wistia.com",
  "title":"Brendan - Make It Clap",
  "thumbnail_url":"https://embed-ssl.wistia.com/deliveries/2d2c14e15face1e0cc7aac98ebd5b6f040b950b5.jpg?image_crop_resized=640x360",
  "thumbnail_width":640,
  "thumbnail_height":360,
  "duration":16.43
}

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 = escape("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!


Troubleshooting

  1. If an invalid URL (one that doesn't match our regular expression above) is given, the endpoint will return 404 Not Found.
  2. If an unparseable URL is given in the url param, the endpoint will return 404 Not Found.
  3. If a media is found, but failed to process, the endpoint will return 404 Not Found.
  4. If a media is found but has no available embed code, the endpoint will return 501 Not Implemented. Video, Image, Audio, and Document files all currently implement oembeds. This will also occur if the video is not finished processing.

Make Your Life Easier

If you're contemplating doing an oEmbed implementation with Wistia (or any oEmbed provider for that matter), we strongly recommend checking out Embedly. By integrating with them you'll have immediate access to over 100 oEmbed providers. They also have great documentation and ready-made libraries for every popular language, plus they're just nice folks!