How to detect if an iframe is accessible without triggering an error?

Try this:

var $frame = $("#frameId"); // swap with the id of the iframe
try {
    var canAccess = $frame.contents();
    if(!!canAccess) {
       // same domain yay you have access
       // do your thing here
    }
}
catch( e ) {
    // bummer can't do much with it
    return false;
}

EDIT: add a try and catch, no error will return false.


The jQuery approach can also be done with regular JS:

function iframe_accessible(theiframe) {
  var thedoc, debug=true;
  try{
    thedoc = (theiframe.contentWindow || theiframe.contentDocument);
    if (thedoc.document)
        thedoc = thedoc.document;
    if (debug)
        console.log('Accessible');
    return true;
  }
  catch(err) {
    if (debug)
        console.log("Not accessible because of\n" + err);
    return false;
  }
}

var elm = document.querySelector('iframe'); // If it exists, of course
console.log(iframe_accessible(elm));

If you can add a little JavaScript to all of the pages from your domain you'd like to load in the iframe you could use window.postMessage, which is exempt from the Same Origin Policy. Probably the simplest way would be to have the child window post a message to the parent when it loads and use that instead of onload. For example, you could add this to each page:

if (window.parent) document.addEventListener( 'load', function() {
    window.parent.postMessage( "child loaded", "/" );
}, false );

That will post a message to the parent window whenever the page is loaded in a frame with the same origin. You would then listen for it like this:

var iframe = document.getElementById( 'your-iframe' );
var origin = window.location.protocol + '://' + window.location.host;
if (window.location.port != 80) origin += ':' + window.location.port;

window.addEventListener( 'message', function (event) {
    if (event.source != iframe.contentWindow
            || event.origin != origin || event.data != "child loaded")
        return;

    // do here what you used to do on the iframe's load event
}, false );

Note that the examples use the W3C/Netscape event API and thus won't work in Internet Explorer before version 9.