How to get around the same-origin problem with iframes

One of Reloads clients recently requested a feature that allowed them to add some fancy video control buttons to their site, such as an auto-play function.

Initially, as a rough estimate from the top of my head I didn’t see any major issues with this - I had previously worked with videos and the HTMLMedia API is working surprisingly well out of the box, without any fancy Javascript libraries. Of course, it’s a native web API so it does have some odd kinks, such as the canPlayType method which either returns “probably”, “maybe” or an empty string (yes, really) - but for the client’s needs, the API would work fine.

Later on, when I was working on a more accurate estimate, i learned that the videos on the site are actually hosted through an external video service called TwentyThree - a service that we have written about before on this blog.

The videos are embedded onto the pages through an iframe, which was when I realized that this might not be as simple as I had hoped because:

You cannot manipulate an external iframe

Sure, you can use .contents() of jQuery to get and manipulate the contents of an iframe, but only if the iframe is displaying an URL from the same domain.

If you try to manipulate or read the contents of an iframe with a different origin, you will get an error like “Uncaught DOMException: Blocked a frame with origin "http://www.url.com" from accessing a cross-origin frame.”

This is a security measure (same-origin policy) and it really does make a lot of sense - it would be a huge security risk if the parent website could track what was happening inside an iframe from a different origin.

Is it totally hopeless then? Not quite...

Proces billede

The first time I ran into that problem I was really quite stumped - a classic case of the imposter syndrome that every single software developer will experience at one point or another.

As it turns out, I was (unsurprisingly) not the first person in the world that had run into this issue and as it turns out a glimmer of hope was added in HTML5: postMessage.

Window.postMessage is another web API which safely and securely enables communication between cross-origin sources, which is massively useful if used correctly.

The idea is that you can use postMessage to send an API call to a different origin and receive an answer. Previously there was no (easy) way to make communication like that happen unless it was same-origin.

It still requires that the target origin has taken this into consideration and created some kind of API that can receive the posted messages and do something with it, such as returning a response or some other kind of reaction.

A really cool example is this CodePen https://codepen.io/rasben/pen/XNoXjp by Brad Dougherty which shows exactly the kind of functionality I needed. In his example, he is controlling a Vimeo player that is embedded in an iframe.

It would appear that this is something a lot of the major video services take advantage of, such as DailyMotion and YouTube.

TwentyThree video and postMessage

Before I got too excited about all my issues being fixed, I had to curb my enthusiasm a bit though - all of this relies on the target party to have made some kind of API on their end also which is something I was unsure if TwentyThree had even done.

TwentyThree video does have a lot of documentation regarding their API but it’s mostly about receiving assets based on API keys and not so much about controlling an embedded video.

They also have a client side library for their videos called Visualplatform.js but there was not much help here - it’s more about how to actually embed the video and not about controlling it from your own end.

After searching through all their documentation and searching far and wide online, it seemed as if TwentyThree had not prepared any kind of postMessage API. In a last ditch effort, I started looking through their (many) repos on GitHub to see if they were at least working on something - and that’s when I found Glue and GlueFrame which is EXACTLY what I needed:

Glue is a framework that builds the actual video application and GlueFrame is a framework that provides methods for communicating with an application that is embedded in an iframe.

In my case Glue was not super useful as it is more about how they set up their application, but it is still well documented to the point where it becomes useful to understand what is going on behind the scenes.

GlueFrame, on the other hand, was exactly what I was looking for - it is essentially a smart framework that uses window.PostMessage in a streamlined, just like we saw with the Vimeo example.

It allows you to control the player, e.g. starting the player:

myApp.set("playing", true);

Or restarting the video:
myApp.set('currentTime', 0);

Or for you to bind eventlisteners to video events (such as when the video is ending):

myApp.bind("player:video:ended", function(eventName, obj) {
 console.log("The event " + eventName + " fired and this object was returned: " + obj);
});

The repo has an excellent documentation of how to use it and it is really beyond me why they would not write about this on their website as it really is a useful and easy framework to use (No “maybe” return values here)

Final words

Iframes are never a joy to work with, but it’s hard to see any better alternative when you consider the security limitations when working with external content.

When “new” stuff like postMessage is added, it takes us one step away from awful work-around hacks and makes all of our lives so much easier.

As a last word, if you are working on some kind of service that could be embedded in an iframe and may have value in being controlled remotely, then look into implementing a postMessage API - I sure am glad that TwentyThree did.