the overengineer

Enabling CORS for HTML5 video element screenshots

• blog

Or:

Preventing Uncaught SecurityError: Failed to execute ‘toDataURL’ on ‘HTMLCanvasElement’: Tainted canvases may not be exported.

Scenario

You are trying to take a screenshot of a HTML5 video element, from a video that is on a different domain, and you are getting a security error similar to the above.

For example
Your video playing client is here:
http://www.myapp.com/player.html
Your video is being served from here:
http://cdn.myapp.com/video.mp4

The solution

Run through the following check-list to ensure you have absolutely everything configured correctly.

Chrome

This seems to be just in Chrome, but even just loading your HTML5 video will fail if your video is being served from any port other than 80 and is not using https:

THIS WILL FAIL
Client at http://www.myapp.com/player.html:

<video crossOrigin="anonymous" src="http://cdn.myapp.com:81/video.mp4"></video>

THIS WILL SUCCEED
Client at http://www.myapp.com/player.html:

<video crossOrigin="anonymous" src="https://cdn.myapp.com:81/video.mp4"></video>

(the src is set to https in the successful example)

Timing

getImageData() and toDataURL() will be security blocked unless crossorigin is set to anonymous or use-credentials ([as defined here][1]) before the video is loaded. You can achieve this either by adding crossOrigin directly to the HTML element, or ensuring that javascript sets it before the src is loaded:

THIS WILL FAIL

    vid.src = "...";
    vid.load();
    vid.crossOrigin = "anonymous";

THIS WILL SUCCEED

    vid.src = "...";
    vid.load();
    vid.crossOrigin = "anonymous";

THIS WILL SUCCEED

    <video crossOrigin="anonymous" controls></video>
    vid.src = "...";
    vid.load();

Spelling

If you are going to set crossOrigin in javascript, be sure to use the correct casing for the javascript property: crossOrigin (NOT crossorigin) [1]: https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes

THIS WILL FAIL

    vid.crossorigin = "anonymous";
    vid.src = "...";
    vid.load();

THIS WILL SUCCEED

    vid.crossOrigin = "anonymous";
    vid.src = "...";
    vid.load();

Serving of data

You will need your CDN to deliver your video with the Access-Control-Allow-Origin set to something useful for you. For more details on this header see here, but to test you can use * as a value (highly dangerous, not recommended for production) otherwise you must specify the domain of your client, in the examples case above the header would look like:

Access-Control-Allow-Origin:http://www.myapp.com

Everything should now work

Providing you have met all of these requirements, you should be good to go. Happy CORSing!

comments powered by Disqus