205

The website in the iframe isn't located in the same domain, but both are mine, and I would like to communicate between the iframe and the parent site. Is it possible?

ediblecode
  • 10,724
  • 16
  • 62
  • 111
Danny Fox
  • 31,515
  • 27
  • 62
  • 90

6 Answers6

350

With different domains, it is not possible to call methods or access the iframe's content document directly.

You have to use cross-document messaging.

For example in the top window:

 myIframe.contentWindow.postMessage('hello', '*');

and in the iframe:

window.onmessage = function(e){
    if (e.data == 'hello') {
        alert('It works!');
    }
};

If you are posting message from iframe to parent window

window.top.postMessage('hello', '*')
Wenfang Du
  • 1,884
  • 3
  • 14
  • 33
user123444555621
  • 130,762
  • 25
  • 104
  • 122
  • 2
    thank you, but unfortunately it doesn't works in older browsers. – Danny Fox Feb 06 '12 at 13:25
  • @Pumbaa80 : Can you put a simple example? – Touko Aug 21 '12 at 07:54
  • 113
    In the parent: `window.onmesage = function()...`. In the iframe: `window.top.postMessage('hello', '*')` – user123444555621 Aug 21 '12 at 11:51
  • @Pumbaa80 when I do that, I get two errors in the chrome console, but still, it works. `Unsafe JavaScript attempt to access frame with URL file:///iframe.html from frame with URL file:///parent.html. Domains, protocols and ports must match.` – Zelenova Jun 16 '13 at 22:24
  • @Zelenova That may be due to a bug in Chrome: http://code.google.com/p/chromium/issues/detail?id=94618 – user123444555621 Jun 16 '13 at 22:56
  • 5
    It's not a bug. File urls can be very unsafe and browsers are treating them with ever increasing care. Back in the old days you could put a link to `file://C:/Windows/system32/whatever` on a webpage and make it point right into the user's system folder. These days browsers mostly ignore clicks on links like that. Run a webserver and access your code through that and you'll see the errors diappear. – Stijn de Witt Mar 27 '14 at 20:46
  • Can you provide a demo please. @Pumbaa80 – tvshajeer Mar 21 '15 at 05:32
  • 6
    As a good practice, never use the '*' for your target. In fact, MDN says - "Always provide a specific targetOrigin, not *, if you know where the other window's document should be located. Failing to provide a specific target discloses the data you send to any interested malicious site." – rodiwa Oct 29 '15 at 08:14
  • 2
    We can even use `window.frames[index]` to get child frame (` – phoenisx Oct 08 '17 at 05:34
  • I've done same thing for VSCode, see my blog post https://alfilatov.com/posts/how-to-pass-data-between-iframe-and-parent-window/ – Alex Filatov Sep 08 '20 at 22:57
  • As of this writing, March of 2021, cross-browser support for `window.onmessage` is not complete: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onmessage#browser_compatibility – flyingace Mar 02 '21 at 22:23
70

It must be here, because accepted answer from 2012

In 2018 and modern browsers you can send a custom event from iframe to parent window.

iframe:

var data = { foo: 'bar' }
var event = new CustomEvent('myCustomEvent', { detail: data })
window.parent.document.dispatchEvent(event)

parent:

window.document.addEventListener('myCustomEvent', handleEvent, false)
function handleEvent(e) {
  console.log(e.detail) // outputs: {foo: 'bar'}
}

PS: Of course, you can send events in opposite direction same way.

document.querySelector('#iframe_id').contentDocument.dispatchEvent(event)
Stranger in the Q
  • 2,952
  • 1
  • 15
  • 22
  • 2
    Hello, do I have to be on the same domain to do it ? – Guillaume Harari Dec 13 '18 at 13:07
  • 3
    https://stackoverflow.com/questions/25098021/securityerror-blocked-a-frame-with-origin-from-accessing-a-cross-origin-frame – Stranger in the Q Dec 13 '18 at 13:33
  • 1
    It should be noted that `dispatchEvent` is supported in all major browsers. IE9 was the first version it came in, so most OSs now work with it. https://caniuse.com/#search=dispatchEvent – Dan Atkinson Aug 16 '19 at 12:48
  • 1
    I am not able to communicate from parent to iframe with this method. – Avan Sep 27 '19 at 08:44
  • Yeah I can't get it to work either, the iframe js is loading after the parent window so it is not there to receive the msg when sent. it only works from iframe to parent for me. – radtek Mar 18 '20 at 00:40
  • There is a simple solution to that Avan and @radtek. All you have to do is first dispatch an event from the iframe to the parent that notifies the parent that the iframe is loaded (essentially a "ready message"). The parent will be listening for messages and if it receives the "ready message" event, it can then reply to the iframe with whatever message you want to send. That way it sends the message to the iframe only once the iframe is loaded. And of course the iframe page will only send the message to the parent once it is loaded. – Cannicide Jun 01 '20 at 15:11
  • Already figured it out sometime ago, made a prototype repo - https://github.com/radzhome/django_sso_service – radtek Jun 02 '20 at 14:13
  • 1
    I tested it and it works only for same origin frames. Cross-origin will result in a `SecurityError` when accessing `window.parent` – Javarome Mar 22 '21 at 22:36
15

This library supports HTML5 postMessage and legacy browsers with resize+hash https://github.com/ternarylabs/porthole

Edit: Now in 2014, IE6/7 usage is quite low, IE8 and above all support postMessage so I now suggest to just use that.

https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage

jpillora
  • 4,885
  • 2
  • 41
  • 55
  • With the caveat that IE8/9 only support strings http://caniuse.com/#search=postmessage (See known issues) – Harry Nov 16 '16 at 14:28
  • this can be worked around by encoding your event objects to json and decode them on the other side. – codewandler May 11 '17 at 08:50
3

Use event.source.window.postMessage to send back to sender.

From Iframe

window.top.postMessage('I am Iframe', '*')
window.onmessage = (event) => {
    if (event.data === 'GOT_YOU_IFRAME') {
        console.log('Parent received successfully.')
    }
}

Then from parent say back.

window.onmessage = (event) => {
    event.source.window.postMessage('GOT_YOU_IFRAME', '*')
}
Binh Ho
  • 1,260
  • 1
  • 9
  • 13
  • As of this writing, March of 2021, cross-browser support for `window.onmessage` is not complete: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onmessage#browser_compatibility – flyingace Mar 02 '21 at 22:24
3

the window.top property should be able to give what you need.

E.g.

alert(top.location.href)

See http://cross-browser.com/talk/inter-frame_comm.html

mattsven
  • 19,239
  • 8
  • 62
  • 102
sambomartin
  • 5,892
  • 7
  • 36
  • 59
1

You can also use

postMessage(message, '*');

gonzarodriguezt
  • 183
  • 3
  • 12
  • 1
    not too informative, I've tried to descrive the process in my blog post https://alfilatov.com/posts/how-to-pass-data-between-iframe-and-parent-window/ – Alex Filatov Sep 08 '20 at 22:57