Is there a way to detect if the Facebook Javascript SDK loaded successfully?

You should load the Javascript Library Asynchronously and put all your FB related functions inside the window.fbAsyncInit method:

<div id="fb-root"></div>
<script>
  window.fbAsyncInit = function() {
    FB.init({
      appId      : 'YOUR_APP_ID', // App ID
      channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File
      status     : true, // check login status
      cookie     : true, // enable cookies to allow the server to access the session
      xfbml      : true  // parse XFBML
    });

    // Additional initialization code here
  };

  // Load the SDK Asynchronously
  (function(d){
     var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
     if (d.getElementById(id)) {return;}
     js = d.createElement('script'); js.id = id; js.async = true;
     js.src = "//connect.facebook.net/en_US/all.js";
     ref.parentNode.insertBefore(js, ref);
   }(document));
</script>

This code loads the SDK asynchronously so it does not block loading other elements of your page. This is particularly important to ensure fast page loads for users and SEO robots.

The URLs in the above code are protocol relative. This lets the browser to load the SDK over the same protocol (HTTP or HTTPS) as the containing page, which will prevent "Insecure Content" warnings.

The function assigned to window.fbAsyncInit is run as soon as the SDK is loaded. Any code that you want to run after the SDK is loaded should be placed within this function and after the call to FB.init. For example, this is where you would test the logged in status of the user or subscribe to any Facebook events in which your application is interested.

A quick example is the following:

<div id="fb-root"></div>
<script>
  var isLoaded = false;
  window.fbAsyncInit = function() {
    FB.init({
      appId      : 'YOUR_APP_ID', // App ID
      channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File
      status     : true, // check login status
      cookie     : true, // enable cookies to allow the server to access the session
      xfbml      : true  // parse XFBML
    });
    isLoaded = true;

    // Additional initialization code here
  };

  function checkIfLoaded() {
    if(isLoaded) console.log("LOADED!");
    else console.log("NOT YET!");

    return false;
  }

  // Load the SDK Asynchronously
  (function(d){
     var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
     if (d.getElementById(id)) {return;}
     js = d.createElement('script'); js.id = id; js.async = true;
     js.src = "//connect.facebook.net/en_US/all.js";
     ref.parentNode.insertBefore(js, ref);
   }(document));
</script>
<a href="#" onclick="checkIfLoaded();">Check</a>

enter image description here
(Just clicked the check link a couple of times)


Please note that you can still construct the Login Link server-side and WITHOUT JavaScript. Example using the PHP-SDK:

$loginUrl = $facebook->getLoginUrl();
...
...
<a href="<?php echo $loginUrl; ?>">
    <img src="http://static.ak.fbcdn.net/rsrc.php/zB6N8/hash/4li2k73z.gif">
</a>

Trigger an event when the SDK is loaded:

window.fbAsyncInit = function() {
  FB.init({appId: "#{KeyManager.facebook_app_id}", status: true, cookie: true, xfbml: true});
  jQuery('#fb-root').trigger('facebook:init');
};

And listen for the event like this:

$("#fb-root").bind("facebook:init", function() {
  ..
});

If you are using jQuery (and you have loaded jQuery prior to the FB initialization) you can use a Deferred to run additional initialization.

<script>
    window.fbLoaded = $.Deferred();

    window.fbAsyncInit = function() {

        FB.init({
            appId      : '----------',
            xfbml      : true,
            status     : true,
            version    : 'v2.7'
        });

        window.fbLoaded.resolve();
    };


    (function(d, s, id){
        var js, fjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) {return;}
        js = d.createElement(s); js.id = id;
        js.src = "//connect.facebook.net/en_US/sdk.js";
        fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));

</script>

Then elsewhere (in a JS file) you can do this (in fact the key of this method is you can put this in as many places as you want and they will all get triggered):

 window.fbLoaded.done(function () { alert('FB initialized'); });

Note: If the initialization completes BEFORE you add the done event it will fire immediately (that is how Deferreds work). So you can put it wherever you want.

Be sure to test what you want the behavior to be if the API is never initializaed (just comment out the (function(d,s,id)... part