Getting the URL of an iframe's parent

Dealing with iframes is always a double-edged sword. On the one hand, you get sandboxing of content within another page, ensuring that JavaScript and CSS from one page won’t affect another. If the iframe is displayed a page from a different origin then you can also be assured that the page can’t do anything nefarious to the containing page. On the other hand, iframes and their associated window objects are a mess of permissible and impermissible actions that you need to remember1. Working with iframes is frequently an exercise in frustration as you methodically move through what you’re allowed to do.

I was recently asked if there’s a way to get the URL of an iframe’s parent page, which is to say, the URL of the page with the <iframe> element. This seems like a simple enough task. For a regular page, you typically get the URL by using window.location. There are also parent to get the window object of the parent page and top to get the window object of the outermost page. You can then use parent.location or top.location to get a URL from the containing page depending on your needs. At least, that’s how you do it when both the iframe page and the containing page are from the same origin.

When the iframe page and containing page are from different origins, then you are completely cut off from the parent.location and top.location. This information is considered unsafe to share across origins. However, that doesn’t mean you can’t find out the URL of the containing page. To do so, you simply need to keep in mind what information the iframe owns and what information it does not.

To start, you should double-check that the page is actually in an iframe, which you can do with this code:

var isInIframe = (parent !== window);

When a page is running inside of an iframe, the parent object is different than the window object. You can still access parent from within an iframe even though you can’t access anything useful on it. This code will never cause an error even when crossing origins.

Once you know you’re in an iframe, you can take advantage of a little-known fact: the HTTP Referer header for a page inside of an iframe is always set to the containing page’s URL. That means a page embedded in an iframe on https://humanwhocodes.com will have a Referer header equal to that URL. Knowing this fact, you need only use the oft-forgotten document.referrer property. As the name suggestions, this property contains the value of the Referer header for the given document. So you can get the URL of the iframe’s parent page like this:

function getParentUrl() {
    var isInIframe = (parent !== window),
        parentUrl = null;

    if (isInIframe) {
        parentUrl = document.referrer;
    }

    return parentUrl;
}

While this may look like a security issue, it’s really not. The Referer is already being sent to the server that is serving up the iframe page, so that information is already known by the web application. The document.referrer property is just exposing the information that the server already has. Since the document object is owned by the iframe window, you aren’t crossing the same-origin policy boundary.

Iframes are always a little bit hairy to deal with, especially when you throw JavaScript into the mix. The good news is that there’s usually a way to do something that makes sense and won’t put a user at risk, whether that be through document.referrer cross-document messaging, or some other means.

  1. Iframes, onload, and document.domain by me (NCZOnline)

Comments

  1. Clay

    What about when the parent iframe is created dynamically, when the parent iframe src attribute is about:blank or some javascript:url that is modified later? It seems like in those cases the document.referrer isn't as reliable.

    This came up with when trying to detect what parent iframe opened a child iframe... a terrible problem that I'm patiently waiting for an answer for on stack overflow.

  2. Nicholas C. Zakas

    @Clay - Hmm, I'm a bit confused about the scenario you describe. Do you have an example setup that illustrates the problem?

  3. rosamez

    Oldie but a goodie. Came in handy when we created embeddable players for 3rd party sites.

  4. Clay

    Sure, try out this example in Chrome and Firefox: http://jsfiddle.net/T9WeJ/2/ Link

    In Firefox and IE8, the document.referrer is empty. Chrome seems to return the correct referrer.

  5. Nicholas C. Zakas

    @Clay - ah, since you're not actually making an HTTP request, I think the FF/IE behavior actually makes sense (since document.referrer is meant to read that value).

  6. Szabolcs Toth

    Some points worth mentioning:

    document.referrer is empty, when the window and its parent differs in protocols (http/https)

    document.referrer only reflects the hostname of the window.parent, in multiple embedded iframes,
    where window.top != window.parent you can't query the top hostname

    Webkit implemented the location.ancestorOrigins property, which is just an array of hostnames going upwards through the embedding frames, but ideal for blacklisting or whitelisting your content

  7. Bastian Behrens

    why dont write it shorter?:

    function getParentUrl() {
    return parent !== window ? document.referrer : null;
    }

  8. Kolodny

    @Clay http://jsfiddle.net/T9WeJ/3/ seems to work

  9. Dominykas Blyž?

    One small gotcha: in IE8 (and probably older versions as well), parent is never === window - strict equality does not work for window (and myabe some other objs) - one must use simple equality.

  10. JD

    Wouldn't this only work if the iframe has only just been created?

    I mean, if you create an iframe with example.org and follow a link to example.org/something, shouldn't the referrer be example.org?

  11. Nicholas C. Zakas

    @JD - yes, once you start navigating around in the iframe, the referrer updates to the previous page.

Understanding JavaScript Promises E-book Cover

Demystify JavaScript promises with the e-book that explains not just concepts, but also real-world uses of promises.

Download the Free E-book!

The community edition of Understanding JavaScript Promises is a free download that arrives in minutes.