[javascript] How to identify if a webpage is being loaded inside an iframe or directly into the browser window?

I am writing an iframe based facebook app. Now I want to use the same html page to render the normal website as well as the canvas page within facebook. I want to know if I can determine whether the page has been loaded inside the iframe or directly in the browser?

This question is related to javascript facebook iframe

The answer is


RoBorg is correct, but I wanted to add a side note.

In IE7/IE8 when Microsoft added Tabs to their browser they broke one thing that will cause havoc with your JS if you are not careful.

Imagine this page layout:

MainPage.html
  IframedPage1.html   (named "foo")
  IframedPage2.html   (named "bar")
    IframedPage3.html (named "baz")

Now in frame "baz" you click a link (no target, loads in the "baz" frame) it works fine.

If the page that gets loaded, lets call it special.html, uses JS to check if "it" has a parent frame named "bar" it will return true (expected).

Now lets say that the special.html page when it loads, checks the parent frame (for existence and its name, and if it is "bar" it reloads itself in the bar frame. e.g.

if(window.parent && window.parent.name == 'bar'){
  window.parent.location = self.location;
}

So far so good. Now comes the bug.

Lets say instead of clicking on the original link like normal, and loading the special.html page in the "baz" frame, you middle-clicked it or chose to open it in a new Tab.

When that new tab loads (with no parent frames at all!) IE will enter an endless loop of page loading! because IE "copies over" the frame structure in JavaScript such that the new tab DOES have a parent, and that parent HAS the name "bar".

The good news, is that checking:

if(self == top){
  //this returns true!
}

in that new tab does return true, and thus you can test for this odd condition.


Following on what @magnoz was saying, here is a code implementation of his answer.

constructor() {
    let windowLen = window.frames.length;
    let parentLen = parent.frames.length;

    if (windowLen == 0 && parentLen >= 1) {
        this.isInIframe = true
        console.log('Is in Iframe!')
    } else {
        console.log('Is in main window!')
    }
}

RoBorg is correct, but I wanted to add a side note.

In IE7/IE8 when Microsoft added Tabs to their browser they broke one thing that will cause havoc with your JS if you are not careful.

Imagine this page layout:

MainPage.html
  IframedPage1.html   (named "foo")
  IframedPage2.html   (named "bar")
    IframedPage3.html (named "baz")

Now in frame "baz" you click a link (no target, loads in the "baz" frame) it works fine.

If the page that gets loaded, lets call it special.html, uses JS to check if "it" has a parent frame named "bar" it will return true (expected).

Now lets say that the special.html page when it loads, checks the parent frame (for existence and its name, and if it is "bar" it reloads itself in the bar frame. e.g.

if(window.parent && window.parent.name == 'bar'){
  window.parent.location = self.location;
}

So far so good. Now comes the bug.

Lets say instead of clicking on the original link like normal, and loading the special.html page in the "baz" frame, you middle-clicked it or chose to open it in a new Tab.

When that new tab loads (with no parent frames at all!) IE will enter an endless loop of page loading! because IE "copies over" the frame structure in JavaScript such that the new tab DOES have a parent, and that parent HAS the name "bar".

The good news, is that checking:

if(self == top){
  //this returns true!
}

in that new tab does return true, and thus you can test for this odd condition.


I'm using this:

var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);

Since you are asking in the context of a facebook app, you might want to consider detecting this at the server when the initial request is made. Facebook will pass along a bunch of querystring data including the fb_sig_user key if it is called from an iframe.

Since you probably need to check and use this data anyway in your app, use it to determine the the appropriate context to render.


When in an iframe on the same origin as the parent, the window.frameElement method returns the element (e.g. iframe or object) in which the window is embedded. Otherwise, if browsing in a top-level context, or if the parent and the child frame have different origins, it will evaluate to null.

window.frameElement
  ? 'embedded in iframe or object'
  : 'not embedded or cross-origin'

This is an HTML Standard with basic support in all modern browsers.


It's an ancient piece of code that I've used a few times:

if (parent.location.href == self.location.href) {
    window.location.href = 'https://www.facebook.com/pagename?v=app_1357902468';
}

The accepted answer didn't work for me inside the content script of a Firefox 6.0 Extension (Addon-SDK 1.0): Firefox executes the content script in each: the top-level window and in all iframes.

Inside the content script I get the following results:

 (window !== window.top) : false 
 (window.self !== window.top) : true

The strange thing about this output is that it's always the same regardless whether the code is run inside an iframe or the top-level window.

On the other hand Google Chrome seems to execute my content script only once within the top-level window, so the above wouldn't work at all.

What finally worked for me in a content script in both browsers is this:

 console.log(window.frames.length + ':' + parent.frames.length);

Without iframes this prints 0:0, in a top-level window containing one frame it prints 1:1, and in the only iframe of a document it prints 0:1.

This allows my extension to determine in both browsers if there are any iframes present, and additionally in Firefox if it is run inside one of the iframes.


When in an iframe on the same origin as the parent, the window.frameElement method returns the element (e.g. iframe or object) in which the window is embedded. Otherwise, if browsing in a top-level context, or if the parent and the child frame have different origins, it will evaluate to null.

window.frameElement
  ? 'embedded in iframe or object'
  : 'not embedded or cross-origin'

This is an HTML Standard with basic support in all modern browsers.


Best-for-now Legacy Browser Frame Breaking Script

The other solutions did not worked for me. This one works on all browsers:

One way to defend against clickjacking is to include a "frame-breaker" script in each page that should not be framed. The following methodology will prevent a webpage from being framed even in legacy browsers, that do not support the X-Frame-Options-Header.

In the document HEAD element, add the following:

<style id="antiClickjack">body{display:none !important;}</style>

First apply an ID to the style element itself:

<script type="text/javascript">
   if (self === top) {
       var antiClickjack = document.getElementById("antiClickjack");
       antiClickjack.parentNode.removeChild(antiClickjack);
   } else {
       top.location = self.location;
   }
</script>

This way, everything can be in the document HEAD and you only need one method/taglib in your API.

Reference: https://www.codemagi.com/blog/post/194


This ended being the simplest solution for me.

    <p id="demofsdfsdfs"></p>

<script>

if(window.self !== window.top) {

//run this code if in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "in frame";

}else{

//run code if not in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "no frame";
}

</script>

if (window.frames.length != parent.frames.length) { page loaded in iframe }

But only if number of iframes differs in your page and page who are loading you in iframe. Make no iframe in your page to have 100% guarantee of result of this code


I actually used to check window.parent and it worked for me, but lately window is a cyclic object and always has a parent key, iframe or no iframe.

As the comments suggest hard comparing with window.parent works. Not sure if this will work if iframe is exactly the same webpage as parent.

window === window.parent;

Use this javascript function as an example on how to accomplish this.

function isNoIframeOrIframeInMyHost() {
// Validation: it must be loaded as the top page, or if it is loaded in an iframe 
// then it must be embedded in my own domain.
// Info: IF top.location.href is not accessible THEN it is embedded in an iframe 
// and the domains are different.
var myresult = true;
try {
    var tophref = top.location.href;
    var tophostname = top.location.hostname.toString();
    var myhref = location.href;
    if (tophref === myhref) {
        myresult = true;
    } else if (tophostname !== "www.yourdomain.com") {
        myresult = false;
    }
} catch (error) { 
  // error is a permission error that top.location.href is not accessible 
  // (which means parent domain <> iframe domain)!
    myresult = false;
}
return myresult;
}

The accepted answer didn't work for me inside the content script of a Firefox 6.0 Extension (Addon-SDK 1.0): Firefox executes the content script in each: the top-level window and in all iframes.

Inside the content script I get the following results:

 (window !== window.top) : false 
 (window.self !== window.top) : true

The strange thing about this output is that it's always the same regardless whether the code is run inside an iframe or the top-level window.

On the other hand Google Chrome seems to execute my content script only once within the top-level window, so the above wouldn't work at all.

What finally worked for me in a content script in both browsers is this:

 console.log(window.frames.length + ':' + parent.frames.length);

Without iframes this prints 0:0, in a top-level window containing one frame it prints 1:1, and in the only iframe of a document it prints 0:1.

This allows my extension to determine in both browsers if there are any iframes present, and additionally in Firefox if it is run inside one of the iframes.


if (window.frames.length != parent.frames.length) { page loaded in iframe }

But only if number of iframes differs in your page and page who are loading you in iframe. Make no iframe in your page to have 100% guarantee of result of this code


Write this javascript in each page

if (self == top)
  { window.location = "Home.aspx"; }

Then it will automatically redirects to home page.


function amiLoadedInIFrame() {
    try {
         // Introduce a new propery in window.top
         window.top.dummyAttribute = true;
         // If window.dummyAttribute is there.. then window and window.top are same intances
         return !window.dummyAttribute;
    } catch(e) {
         // Exception will be raised when the top is in different domain
         return true;
    }
}

I actually used to check window.parent and it worked for me, but lately window is a cyclic object and always has a parent key, iframe or no iframe.

As the comments suggest hard comparing with window.parent works. Not sure if this will work if iframe is exactly the same webpage as parent.

window === window.parent;

If you want to know if the user is accessing your app from facebook page tab or canvas check for the Signed Request. If you don't get it, probably the user is not accessing from facebook. To make sure confirm the signed_request fields structure and fields content.

With the php-sdk you can get the Signed Request like this:

$signed_request = $facebook->getSignedRequest();

You can read more about Signed Request here:

https://developers.facebook.com/docs/reference/php/facebook-getSignedRequest/

and here:

https://developers.facebook.com/docs/reference/login/signed-request/


Since you are asking in the context of a facebook app, you might want to consider detecting this at the server when the initial request is made. Facebook will pass along a bunch of querystring data including the fb_sig_user key if it is called from an iframe.

Since you probably need to check and use this data anyway in your app, use it to determine the the appropriate context to render.


if ( window.location !== window.parent.location ) 
{
      // The page is in an iframe   
} 
else 
{     
      // The page is not in an iframe   
}

If you want to know if the user is accessing your app from facebook page tab or canvas check for the Signed Request. If you don't get it, probably the user is not accessing from facebook. To make sure confirm the signed_request fields structure and fields content.

With the php-sdk you can get the Signed Request like this:

$signed_request = $facebook->getSignedRequest();

You can read more about Signed Request here:

https://developers.facebook.com/docs/reference/php/facebook-getSignedRequest/

and here:

https://developers.facebook.com/docs/reference/login/signed-request/


if ( window.location !== window.parent.location ) 
{
      // The page is in an iframe   
} 
else 
{     
      // The page is not in an iframe   
}

I'm using this:

var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);

I'm not sure how this example works for older Web browsers but I use this for IE, Firefox and Chrome without an issue:

var iFrameDetection = (window === window.parent) ? false : true;

Use this javascript function as an example on how to accomplish this.

function isNoIframeOrIframeInMyHost() {
// Validation: it must be loaded as the top page, or if it is loaded in an iframe 
// then it must be embedded in my own domain.
// Info: IF top.location.href is not accessible THEN it is embedded in an iframe 
// and the domains are different.
var myresult = true;
try {
    var tophref = top.location.href;
    var tophostname = top.location.hostname.toString();
    var myhref = location.href;
    if (tophref === myhref) {
        myresult = true;
    } else if (tophostname !== "www.yourdomain.com") {
        myresult = false;
    }
} catch (error) { 
  // error is a permission error that top.location.href is not accessible 
  // (which means parent domain <> iframe domain)!
    myresult = false;
}
return myresult;
}

Best-for-now Legacy Browser Frame Breaking Script

The other solutions did not worked for me. This one works on all browsers:

One way to defend against clickjacking is to include a "frame-breaker" script in each page that should not be framed. The following methodology will prevent a webpage from being framed even in legacy browsers, that do not support the X-Frame-Options-Header.

In the document HEAD element, add the following:

<style id="antiClickjack">body{display:none !important;}</style>

First apply an ID to the style element itself:

<script type="text/javascript">
   if (self === top) {
       var antiClickjack = document.getElementById("antiClickjack");
       antiClickjack.parentNode.removeChild(antiClickjack);
   } else {
       top.location = self.location;
   }
</script>

This way, everything can be in the document HEAD and you only need one method/taglib in your API.

Reference: https://www.codemagi.com/blog/post/194


RoBorg is correct, but I wanted to add a side note.

In IE7/IE8 when Microsoft added Tabs to their browser they broke one thing that will cause havoc with your JS if you are not careful.

Imagine this page layout:

MainPage.html
  IframedPage1.html   (named "foo")
  IframedPage2.html   (named "bar")
    IframedPage3.html (named "baz")

Now in frame "baz" you click a link (no target, loads in the "baz" frame) it works fine.

If the page that gets loaded, lets call it special.html, uses JS to check if "it" has a parent frame named "bar" it will return true (expected).

Now lets say that the special.html page when it loads, checks the parent frame (for existence and its name, and if it is "bar" it reloads itself in the bar frame. e.g.

if(window.parent && window.parent.name == 'bar'){
  window.parent.location = self.location;
}

So far so good. Now comes the bug.

Lets say instead of clicking on the original link like normal, and loading the special.html page in the "baz" frame, you middle-clicked it or chose to open it in a new Tab.

When that new tab loads (with no parent frames at all!) IE will enter an endless loop of page loading! because IE "copies over" the frame structure in JavaScript such that the new tab DOES have a parent, and that parent HAS the name "bar".

The good news, is that checking:

if(self == top){
  //this returns true!
}

in that new tab does return true, and thus you can test for this odd condition.


Following on what @magnoz was saying, here is a code implementation of his answer.

constructor() {
    let windowLen = window.frames.length;
    let parentLen = parent.frames.length;

    if (windowLen == 0 && parentLen >= 1) {
        this.isInIframe = true
        console.log('Is in Iframe!')
    } else {
        console.log('Is in main window!')
    }
}

This ended being the simplest solution for me.

    <p id="demofsdfsdfs"></p>

<script>

if(window.self !== window.top) {

//run this code if in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "in frame";

}else{

//run code if not in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "no frame";
}

</script>

It's an ancient piece of code that I've used a few times:

if (parent.location.href == self.location.href) {
    window.location.href = 'https://www.facebook.com/pagename?v=app_1357902468';
}

Since you are asking in the context of a facebook app, you might want to consider detecting this at the server when the initial request is made. Facebook will pass along a bunch of querystring data including the fb_sig_user key if it is called from an iframe.

Since you probably need to check and use this data anyway in your app, use it to determine the the appropriate context to render.


I'm not sure how this example works for older Web browsers but I use this for IE, Firefox and Chrome without an issue:

var iFrameDetection = (window === window.parent) ? false : true;

Since you are asking in the context of a facebook app, you might want to consider detecting this at the server when the initial request is made. Facebook will pass along a bunch of querystring data including the fb_sig_user key if it is called from an iframe.

Since you probably need to check and use this data anyway in your app, use it to determine the the appropriate context to render.


function amiLoadedInIFrame() {
    try {
         // Introduce a new propery in window.top
         window.top.dummyAttribute = true;
         // If window.dummyAttribute is there.. then window and window.top are same intances
         return !window.dummyAttribute;
    } catch(e) {
         // Exception will be raised when the top is in different domain
         return true;
    }
}

Write this javascript in each page

if (self == top)
  { window.location = "Home.aspx"; }

Then it will automatically redirects to home page.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to facebook

I am receiving warning in Facebook Application using PHP SDK React-Native: Application has not been registered error Can't Load URL: The domain of this URL isn't included in the app's domains Facebook OAuth "The domain of this URL isn't included in the app's domain" Facebook login message: "URL Blocked: This redirect failed because the redirect URI is not whitelisted in the app’s Client OAuth Settings." Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `ListView` Open Facebook Page in Facebook App (if installed) on Android App not setup: This app is still in development mode IOS - How to segue programmatically using swift Get ALL User Friends Using Facebook Graph API - Android

Examples related to iframe

Getting all files in directory with ajax YouTube Autoplay not working Inserting the iframe into react component How to disable auto-play for local video in iframe iframe refuses to display iFrame onload JavaScript event YouTube iframe embed - full screen Change New Google Recaptcha (v2) Width load iframe in bootstrap modal Responsive iframe using Bootstrap