July 10, 2026
Understanding window.postMessage(): How Browsers Safely Communicate Across Origins (PART -2)
If you’ve ever used Google Sign-In, Stripe Checkout, embedded YouTube videos, or OAuth authentication, you’ve already relied on…
By BALAJI
2 min read
If you've ever used Google Sign-In, Stripe Checkout, embedded YouTube videos, or OAuth authentication, you've already relied on window.postMessage(). Yet many developers know how to use it without understanding how it actually works.
In this article, we'll explore the purpose of window.postMessage(), how browsers process messages internally, and why improper implementations often lead to security vulnerabilities.
Why Was postMessage() Introduced?
The web is built on one of the browser's most important security mechanisms: the Same-Origin Policy (SOP).
According to SOP, JavaScript running on one origin cannot directly access the DOM, cookies, or JavaScript objects of another origin.
for example:
https://shop.victim.comhttps://shop.victim.comEmbedding an iframe:
https://payments.victim.comhttps://payments.victim.comTrying to execute:
iframe.contentWindow.document.body.innerHTML;iframe.contentWindow.document.body.innerHTML;results in:
SecurityError:
Blocked by the Same-Origin PolicySecurityError:
Blocked by the Same-Origin PolicyThis restriction prevents malicious websites from stealing sensitive information from other websites.
However, modern web applications still need a secure way for different origins to communicate. That's exactly why window.postMessage() exists.
What Is window.postMessage()?
window.postMessage() is a browser API that enables two different browsing contexts—such as windows, tabs, popups, or iframes—to exchange data securely, even when they belong to different origins.
A typical example looks like this:
const iframe = document.getElementById("payment");
iframe.contentWindow.postMessage(
{
action: "PAYMENT_COMPLETE",
orderId: 12345
},
"https://payments.example.com"
);const iframe = document.getElementById("payment");
iframe.contentWindow.postMessage(
{
action: "PAYMENT_COMPLETE",
orderId: 12345
},
"https://payments.example.com"
);Notice the two parameters:
- Message — Any serializable JavaScript object.
- Target Origin — The origin that is allowed to receive the message.
The browser will only deliver the message if the target window matches the specified origin.
How Does postMessage() Actually Work?
Many developers imagine that JavaScript sends data directly to another page.
That isn't what happens.
Instead, the browser acts as a trusted messenger.
The process looks like this:
Parent Window
│
│ postMessage()
▼
──────────────────────────
Browser
──────────────────────────
│
Validates targetOrigin
│
Creates MessageEvent
│
Places it into Event Queue
▼
Target Window
│
Dispatches "message" event
▼
JavaScript Event ListenerParent Window
│
│ postMessage()
▼
──────────────────────────
Browser
──────────────────────────
│
Validates targetOrigin
│
Creates MessageEvent
│
Places it into Event Queue
▼
Target Window
│
Dispatches "message" event
▼
JavaScript Event ListenerNotice that the browser — not JavaScript — is responsible for transporting the message.
Inside the Browser
When your code executes:
iframe.contentWindow.postMessage(data, origin);iframe.contentWindow.postMessage(data, origin);the browser performs several steps.
Step 1 — Validate the Target
The browser first checks whether the target window still exists.
If the window has already been closed, the message is discarded.
Step 2 — Verify the Origin
Next, the browser compares the supplied targetOrigin against the destination window's current origin.
If they don't match, the message is never delivered.
For example:
postMessage(data, "https://payments.example.com");postMessage(data, "https://payments.example.com");will only reach:
https://payments.example.comhttps://payments.example.comand nowhere else.
Step 3— Create a Message Event
The browser creates an internal MessageEvent object containing information such as:
event.data
event.origin
event.source
event.portsevent.data
event.origin
event.source
event.portsStep 4— Queue the Event
The message is placed into the browser's event queue.
This means postMessage() is asynchronous.
The sender continues executing immediately while the receiver processes the message later through the event loop.
Step 5— Dispatch the Event
When the receiving page's event loop reaches the queued message, the browser dispatches a message event.
window.addEventListener("message", event => {
console.log(event.data);
});window.addEventListener("message", event => {
console.log(event.data);
});At this point, JavaScript regains control.
Understanding the MessageEvent
Every received message arrives inside a MessageEvent.
window.addEventListener("message", event => {
console.log(event.data);
console.log(event.origin);
console.log(event.source);
});window.addEventListener("message", event => {
console.log(event.data);
console.log(event.origin);
console.log(event.source);
});
Where Is postMessage() Used?
Today, window.postMessage() powers many features that users interact with every day.
Some common examples include:
- OAuth authentication (Google, GitHub, Microsoft)
- Payment gateways such as Stripe and PayPal
- Embedded YouTube videos
- Third-party chat widgets
- Advertising iframes
- Browser extensions
- Micro-frontend architectures
- Cross-origin communication between applications
Without postMessage(), many modern web applications would be significantly more difficult to build.