If you've ever needed to load a page or app from one website onto a different website, you've used an <iframe>. One limitation that iframes have is that there's no communication between the parent page and the embedded page — at least not by default. The window.postMessage() method makes this communication possible.

Two-Way Communication

This is some Inception level stuff that I'll try not to make super confusing. In the following example, I have an iframe that's loading an external website containing a color picker. By taking advantage of window.postMessage(), I can read the color that is currently selected in the color picker and apply it to my website, even though the color picker is loading from a completely different website.

Not only can I read data coming from the embedded website, I can also send data back. I have a textbox below that is coming directly from the source code of my website. When you update the text in that textbox, the title of the color picker will also update. I've added a couple buttons as well (also coming from my website's source code) to help reset things, so you're not stuck with an obnoxious background color.

zachpatrick.com source code

Sending data from an iframe to the parent window

Below is a simplified version of how I'm making the current color available to the parent window. It's worth mentioning the importance of specifying a PARENT_ORIGIN. This ensures that only websites you've okayed can communicate with your website through an iframe. Neglecting to specify this leaves your site vulnerable to bad guys.

iframe.js

const colorPicker = document.getElementById('colorPicker');
const PARENT_ORIGIN = "https://zachpatrick.com";

// when the color picker updates
colorPicker.addEventListener('input', (e) => {
  const color = e.target.value;

  // check if window.parent exists so we only run this when being loaded in an iframe
  if (window.parent) {
    // send the message to the parent
    window.parent.postMessage({ type: "COLOR_SELECTED", color }, PARENT_ORIGIN);
  }
});

Receiving data from an iframe

Now we can listen for data coming from the iframe and do something with it.

parent.js

const IFRAME_ORIGIN = "https://beautiful-florentine-c08957.netlify.app";
const iframe = document.getElementById("child-iframe");

window.addEventListener("message", (e) => {
  if (!iframe) return;

  // only accept messages from the specified url
  if (e.origin !== IFRAME_ORIGIN) return;
  
  // make sure the source of the message matches the correct iframe
  if (e.source !== iframe.contentWindow) return;

  // make sure the iframe has sent us the type of data we're expecting
  if (e.data?.type === "COLOR_SELECTED") {
    if (e.data?.color) {
      // change the background color of the page and relevant elements
    }
  }
});