Tainted Canvas: why the browser blocks your canvas (and how to unblock it)

by Reynaldi •

Working with the <canvas> feels simple at first, load an image, draw it, export it. But the moment that image lives on a different origin you hit an error: calls such as canvas.toDataURL() or getImageData() shows error with “Tainted canvases may not be exported.” The browser is preventing you from reading the pixels of that canvas.

Tainted cavas error Tainted cavas error

What’s with the tainted canvas?

When you draw an image fetched from another origin without proper CORS setup, the browser makes the entire canvas as “tainted.” Any attempt to read those pixels (getImageData, toBlob, toDataURL, etc.) is then blocked.

To solve this, you need to add crossOrigin="anonymous" to asks the browser to send the request in CORS mode, but the server must still reply with a matching Access-Control-Allow-Origin header.

<img src="https://example.com/image.png" crossorigin="anonymous" />

Solving the tainted canvas error

You’ve got two options to solve the tainted canvas error:

  • Control the server?
    Add the header Access-Control-Allow-Origin: * (or your domain) and keep crossOrigin="anonymous" on your <img> tag or drawImage source.

  • Don’t control the server?

    • Backend relay: Fetch the image in your own backend, then serve it with the right CORS header so the browser sees it as same-origin.
    • CORS proxy: Use a CORS proxy that injects the header for you, ideal if you are running a static only site or don’t have a backend.
    const image = new Image();
    image.crossOrigin = "anonymous";
    image.src = "https://proxy.corsfix.com/?https://example.com/image.png";
    image.onload = () => {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    ctx.drawImage(image, 0, 0);
    const dataUrl = canvas.toDataURL();
    console.log(dataUrl);
    };

Conclusion

A tainted canvas is just the browser’s way of preventing you from accessing a canvas that contains cross-origin data. Tell the browser to expect CORS (crossOrigin="anonymous") and tell the server to allow it (Access-Control-Allow-Origin). If you can’t modify the server, relay the image through your backend or use a CORS proxy. Need something production-ready? Give Corsfix a spin, it’s free to start and only costs when you scale.

Say Goodbye to CORS Errors

With comprehensive documentation, easy-to-use APIs, and advanced features, you can focus on building your website without worrying about CORS.