LearnHow to Securely Send Messages Between Windows with postMessage

   
Avatar

Matt West
writes on September 12, 2013

As we build an ecosystem where web applications can interact with one another we need a way of securely sending messages between windows. The postMessage() method provides just that.

For a long time sending messages between windows was only possible if the windows used the same protocol, port, and host. The postMessage() method lifts this restriction by providing a way to securely pass messages across domains.

In this blog post you are going to learn how to use the postMessage() method to communicate between a controller window and a receiver window running different domains.

Sending Messages with postMessage()

The postMessage() method accepts two parameters.

  • message – A string or object that will be sent to the receiving window.
  • targetOrigin – The URL of the window that the message is being sent to. The protocol, port and hostname of the target window must match this parameter for the message to be sent. Specifying "*" will match any URL however this is strongly discouraged for security reasons.

This method should be called on the window that the message is being sent to. A reference to the target window can be obtained in a number of different ways:

  • When using window.open() a reference to the new window will be returned by the open() method.
  • For iframes you can access the contentWindow property on the desired iframe.
targetWindow.postMessage('Hello World!', 'http://example.com');

Now lets take a look at how to receive messages sent to a window.

Setting up Event Listeners to Receive Messages

When a call to postMessage() is executed successfully a MessageEvent will be fired on the receiving window. You can use a standard event listener to watch for this event and execute some code when it occurs.

The event passed into the listener callback has a property called data that can be used to access the string or object that was sent by postMessage().

window.addEventListener('message', function(e) {
  var message = e.data;
});

Demo: Communicating with an iframe

Using postMessage to communicate with an iframe

Using postMessage to communicate with an iframe

Now that you understand how to use postMessage() to pass messages between two windows on different domains lets take a look at an example.

In this section we are going to go through the code needed to create a simple demo that passes a message from a controller page to a receiver page that is embedded using an iframe.

See the Demo Download The Code View on CodePen

The JavaScript Controller Window

To get started we need to write some HTML for the controller page. The main elements here are a <button> that will be used to send the message and an <iframe> that will display the receiver page (which is hosted on a different domain).

<h1>Controller Window</h1>
<p>
  This document is on the domain: http://codepen.io
</p>
<p>
  <button id="send">Send Message</button>
</p>

<iframe id="receiver" src="http://demos.matt-west.com/post-message/receiver.html" width="500" height="200">
  <p>Your browser does not support iframes.</p>
</iframe>

Turning to the JavaScript for the controller page, our first job is to get a reference to the receiver window and store it in a variable called receiver. We then get a reference to the button and store this in a variable called btn.

Next we need to write a function that will handle sending the message. This will be called when the user clicks the ‘Send Message’ button. In this function we call postMessage() on our receiver variable and pass in 'Hello Treehouse!' as our message data. The receiver page is hosted on the domain http://demos.matt-west.com so we pass in that URL for the targetOrigin parameter.

Finally we setup an event listener on btn that will call the sendMessage() function when the button is clicked.

window.onload = function() {
  // Get the window displayed in the iframe.
  var receiver = document.getElementById('receiver').contentWindow;

  // Get a reference to the 'Send Message' button.
  var btn = document.getElementById('send');

  // A function to handle sending messages.
  function sendMessage(e) {
    // Prevent any default browser behaviour.
    e.preventDefault();

    // Send a message with the text 'Hello Treehouse!' to the receiver window.
    receiver.postMessage('Hello Treehouse!', 'http://demos.matt-west.com');
  }

  // Add an event listener that will execute the sendMessage() function
  // when the send button is clicked.
  btn.addEventListener('click', sendMessage);
}

That’s everything that we need for the controller window so lets move on and take a look at the code for the receiver.

The Receiver Window

The HTML for the receiver window is pretty basic. The only key element here is a <div> with the ID message that will be used to display the message data passed to the window.

<h1>Receiver Window</h1>
<p>
  This document is on the domain: http://demos.matt-west.com
</p>
<div id="message"></div>

In the JavaScript for the receiver window we first need to get a reference to the <div> element in our HTML.

Next we create a function called receiveMessage that will be executed when the window receives a new message. Inside this function we first check to make sure that the message is coming from http://s.codepen.io (the domain for the controller page). Any website can pass a message to your page so it’s best to always check the origin of the message before executing any code. The origin can be found by examining the origin property on the event. We then retrieve the message data from the data property of the event
and use this to update the content of messageEle.

Finally we setup an event listener on the window that will execute the receiveMessage() function when the message event is fired.

window.onload = function() {
  // Get a reference to the div on the page that will display the
  // message text.
  var messageEle = document.getElementById('message');

  // A function to process messages received by the window.
  function receiveMessage(e) {
    // Check to make sure that this message came from the correct domain.
    if (e.origin !== "http://s.codepen.io")
      return;

    // Update the div element to display the message.
    messageEle.innerHTML = "Message Received: " + e.data;
  }

  // Setup an event listener that calls receiveMessage() when the window
  // receives a new MessageEvent.
  window.addEventListener('message', receiveMessage);
}

If you load up the live demo you should see that clicking the ‘Send Message’ button causes the Hello Treehouse! text to be displayed in the iframe. Success!

Try downloading the code archive and setting up this example for yourself. Be sure to change the domains in the JavaScript code to match your own.

Browser Support

Support for postMessage() has been around in browsers for some time now. Internet Explorer has included support since version 8 but it’s worth noting that IE8 and IE9 only support postMessage() for communicating between a document and an iframe, support for cross-window/tab messaging arrived in IE10.

IE Firefox Chrome Safari Opera
8+ 3.0+ 1.0+ 4.0+ 9.5+

Final Thoughts on Cross-Domain Messaging

In this blog post you have learned how to use postMessage() to communicate between two web pages that are hosted on different domains.

There are a few security considerations that need to be taken into account when using postMessage(). First make sure that you are always specifying full URLs as your targetOrigin parameter and not just using wildcards (*), otherwise you could inadvertently send data to a malicious website. Checking the origin of messages sent to your web pages is also a good way of keeping your pages secure.

It may not be something that you will find yourself using everyday but postMessage() is a really handy tool to have in your toolbox, especially if you do a lot of work with iframes.

GET STARTED NOW

Learning with Treehouse for only 30 minutes a day can teach you the skills needed to land the job that you've been dreaming about.

Get Started

16 Responses to “How to Securely Send Messages Between Windows with postMessage”

  1. The communication here is only one way – from one browsing context to another. It feels to me like this article should say something about how you might communicate back in the other direction.

  2. Muhammad Mohsan on August 11, 2017 at 6:00 am said:

    Hi sir,
    Thank you very much for this wonderful article.
    But sir i am facing one problem. Is this necessary to have both the sender and receiver windows open? I think its synchronous call. Actually sir i am trying to implement the Single Sign-On (SSO) using postmessage. Can you help me? how can i store the values when the user has clicked the button send message(or Login)? I want to store the user name and password for SSO purpose. Waiting for your kind response.

  3. Andrew J on May 26, 2017 at 8:03 am said:

    I’ve got this to work with a button and event listener but am struggling to just have the message send on page load. Is it possible? The only thing I’ve really changed from your example is having the message sent to an input value in the iframe rather than a div.

    • Hey Andrew,

      As far as I know that should be possible. Did you update the domain check at the start of the `receiveMessage` method? Make sure that matches the domain that your message is being sent from.

  4. isapati on April 26, 2017 at 11:48 pm said:

    Thank you for clean, well structured and educational instructions. I’m struggling with a particular problem – I’m using iFrameResize on the parent and iframe page, and it messes up the communications somewhat. I need a way to silently drop the messages from iFrameResize. I will try the selective approach you mentioned in the comment @strigga. If you have any further ideas on this matter, or have experience with these two scripts that do similar but not identical things, any hints would be much appreciated.

  5. Wondering how do you post messages to all secondary windows that are opened from the main parent window?

    Something like a publisher/subscriber model so that we don’t have to maintain the handle of windows that are opened.

  6. strigga on January 5, 2017 at 9:21 am said:

    i have 3 iframes on my page and all 3 send data to the parent window via postmessage.
    How to detect which iframe sent the data? i want to get the iframe which sent data.

    maybe a function on iframe click and get the id would help? but cant get it work

    • you can send something like this:
      in your iframe window.postMessage({sender: ”iframeName}, ‘* or your url’)

      on website: window.addEventListener(function(event) {
      if(event.data.sender && event.data.sender == ‘iframeName’){
      // your action here
      }
      })

  7. In postMessage method, Transferable object can be passed as a third parameter

  8. Alex Chiu on August 8, 2016 at 6:17 pm said:

    Hey Matt, thanks for writing the article, I downloaded your code and modified it to run on my local environment, but I am getting a javascript error in the receiver.html file that e is undefined, any thoughts or opinions? thanks again

  9. It would be great to combine example with also oposite message flow – from the child iframe to the parent. IMO it is more common problem (passing value to the iframe you can do even with get param of the iframe URL)

  10. Quang Tran on April 13, 2016 at 2:03 am said:

    Thanks Matt, nice and helpful article.

  11. 業界最高峰のブランドコピー 激安、コピーブランド、スーパーコピーブランド(N級品)通販専門店!ブランドコピー,コピーブランド,スーパーコピーブランド,ブランドコピー 激安,偽物ブランド、偽物のバッグ、腕時計、財布など激安で買える!全部のスーパーコピー販売品物のなかで私達のブランド激安が一番有名です
    スーパーコピー商品、ブランドコピ ー財布、偽物バッグコピー財布コピーN 級品、ブ ランドスーパーコピー商 品、グッチ財布コピー,ミュウミュウ 財布激安。ブランドスーパーコ ピー銀座、ランドスーパーコピー財布。ブラ ンドスーパーコピー代引き、ブランドスーパーコピー専門店、ご購入する度、ご安心とご満足の届けることを旨にしておりますよろしくお願いします ありがとうございます http://www.bagkakaku.com/chanel_bag.html

  12. Luke Hansford on September 7, 2015 at 12:54 am said:

    Super helpful article Matt, thanks for writing it!

  13. Nice write up, I’m using postMessage combined with a XHR hooks to create a pure JavaScript CORS polyfil https://github.com/jpillora/xdomain

Leave a Reply

You must be logged in to post a comment.

man working on his laptop

Are you ready to start learning?

Learning with Treehouse for only 30 minutes a day can teach you the skills needed to land the job that you've been dreaming about.

Start a Free Trial
woman working on her laptop