Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 164

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 167

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 170

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 173

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 176

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 178

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 180

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 202

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 206

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 224

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 225

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 227

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 321

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 321

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 321

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/includes/class.layout.php on line 321

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/admin/class.options.metapanel.php on line 56

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/admin/class.options.metapanel.php on line 56

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/admin/class.options.metapanel.php on line 56

Warning: Creating default object from empty value in /home/ibrfao/masteringapi.com/blog/wp-content/themes/platform/admin/class.options.metapanel.php on line 49
Facebook Javascript SDK Best Practices | MasteringAPI

Using the Facebook Javascript SDK is almost essential for interactive applications as it enables your application to access the Graph API via Javascript.

And to provide the best experience possible to your users, here are some tips:

 

Use Asynchronous Loading of the SDK

While you can simply include the JS-SDK, asynchronous loading can give your website a performance boost and helps loading your pages faster:

The most efficient way to load the SDK in your site is to load it 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/spiders.

<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
      oauth      : true, // enable OAuth 2.0
      xfbml      : true  // parse XFBML
    });

    // Additional initialization code here
  };

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

Placement of the SDK

UPDATE: Facebook is recommending adding the SDK snippet after the opening <body> tag. But this is really the developer call. Depending on your application, you may choose having all your scripts before the closing </body> tag.

<div id="fb-root"></div>
<script src="path/to/other/js/libraries/jquery.js"></script>
<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
      oauth      : true, // enable OAuth 2.0
      xfbml      : true  // parse XFBML
    });

    // Additional initialization code here
  };

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

If you are not sure what to do, just follow Facebook advise and add it directly after the opening tag.

Back to top
 

Delay Facebook related tasks till the SDK is loaded

Using the asynchronous method and placing all your Facebook related code within the window.fbAsyncInit function would be enough but if you have some methods (that needs to call Facebook) outside this function then you can have a flag to insure that any call is performed only when the library is loaded, something like:

<div id="fb-root"></div>
<script>
	var isLoaded = false; // Our flag
	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
		  oauth      : true, // enable OAuth 2.0
		  xfbml      : true  // parse XFBML
		});

		// Additional initialization code here
		isLoaded = true;
	};
	// A function that requires calling Facebook
	function myFunc(text) {
		// your tasks here

		// Facebook call
		if(isLoaded) {
			 FB.ui(
			   {
				 method: 'feed',
				 name: 'Test Dialogs',
				 message: text
			   },
			   function(response) {
				 if (response && response.post_id) {
				   alert('Post was published.');
				 } else {
				   alert('Post was not published.');
				 }
			   }
			 );
		}
	}

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

Or you can use the following approach with normal library loading (also possible with asynchronous but not recommended!):

<div id="fb-root"></div>
<script src="//connect.facebook.net/en_US/all.js"></script>
<script>
  FB.init({
    appId  : 'YOUR APP ID',
    status : true, // check login status
    cookie : true, // enable cookies to allow the server to access the session
    xfbml  : true,  // parse XFBML
    oauth: true, // enable OAuth 2.0
    channelUrl: '//www.yourdomain.com/channel.html' //custom channel
  });
  
  function myFunc(text) {
	// your tasks here
	
	// Facebook call
	if(typeof FB != 'undefined') {
		 FB.ui(
		   {
			 method: 'feed',
			 name: 'Test Dialogs',
			 message: text
		   },
		   function(response) {
			 if (response && response.post_id) {
			   alert('Post was published.');
			 } else {
			   alert('Post was not published.');
			 }
		   }
		 );
	}
  }  
</script>

But you need to make sure you don’t define FB in your own JS code or libraries!

Back to top
 

User Auto-size option and the FB.Canvas.setSize() method

While this is up to the developer’s preferences, developers are already limited in width inside Facebook (canvas or page tabs) which means another annoying scrollbar would hurt the user experience not to mention that scrollbars within pages may scare some users.

So to avoid scrollbars, set the “IFrame Size” option in your “Facebook Integration” tab inside your application settings to “Auto-resize” then use the FB.Canvas.setSize() whenever needed:

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
	  oauth      : true, // enable OAuth 2.0
	  xfbml      : true  // parse XFBML
	});
	FB.Canvas.setSize();
};

// Do things that will sometimes call sizeChangeCallback()

function sizeChangeCallback() {
	FB.Canvas.setSize();
}

UPDATE: A good place to put your FB.Canvas.setSize(); call is when the “window” finishes loading!
Why, you ask? Well, today I had to place an image in a Facebook Page Tab. Seems obvious enough, but the thing is having the FB.Canvas.setSize(); call inside the window.fbAsyncInit wasn’t enough!
Because this would fire even if images haven’t loaded fully yet. And this caused the ugly scrollbars!
So the solution was:

window.onload = function () {
  FB.Canvas.setSize();
}

Please note that this would override other onload events! so it’s adviced to search online for a better solution (1 2). Also note that jQuery and most well-known JS libraries support this.
Also note that you may use the approach described in the previous step just in case something went wrong and the SDK didn’t load!

Back to top
 

Avoid including the library more than once

People that want to include more than one XFBML version of the Like Plugin mostly “copy/paste” the code generated by Facebook, which would result on multiple inclusion of the fb-root DIV and the JS-SDK. Instead you can do something like:

<fb:like href="" send="true" width="450" show_faces="true" font=""></fb:like>

<!-- content here -->

<fb:like href="" send="true" width="450" show_faces="true" font=""></fb:like>

<!-- content here -->

<div id="fb-root"></div>
<script src="//connect.facebook.net/en_US/all.js#appId=APP_ID&amp;xfbml=1"></script>
Back to top
 

Custom Channel URL

Facebook has further explained the importance of the channel file:

This is an option that can help address three specific known issues. First, when auto playing audio/video is involved, the user may hear two streams of audio because the page has been loaded a second time in the background for cross domain communication. Second, if you have frame busting code, then you would see a blank page. Third, this will prevent inclusion of extra hits in your server-side logs.

<div id="fb-root"></div>
 <script src="//connect.facebook.net/en_US/all.js"></script>
 <script>
	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
	  oauth      : true, // enable OAuth 2.0
	  xfbml      : true  // parse XFBML
	});
 </script>

The content of the channel.html file is just a single line (the JS Library):

<script src="//connect.facebook.net/en_US/all.js"></script>

Facebook also suggest to cache the file if you have a server-side access:

 <?php
 $cache_expire = 60*60*24*365;
 header("Pragma: public");
 header("Cache-Control: max-age=".$cache_expire);
 header('Expires: ' . gmdate('D, d M Y H:i:s', time()+$cache_expire) . ' GMT');
 ?>
 <script src="//connect.facebook.net/en_US/all.js"></script>

Do you have more tips? share them in the comment section!

Back to top
Tagged with:
 
  • Brunoguic

    I use a php include ( permission.php ) and put a list with the permission. If I use in other  page is more useful..
    Sorry , my english it’s so poor! hahah

    • http://www.masteringapi.com Ibrahim Faour

       I’m not sure what you mean here man. :-)

  • http://twitter.com/markmd619 MarkyMark

    I’m not sure which one to use :o PHP or Javascript. I need one where I can pass user’s logged in or logged out status through other pages.

  • http://www.facebook.com/people/Abdallah-Mustafa/669630352 Abdallah Mustafa

    I like this

  • yanipan

    excellent data mate, thanks alot :)

  • Jesse Kocher

    Do you know a best practice around replacing or reloading a FB widget on the page.  

    We’re using the comments widget, and want to be able to replace the initially displayed set of comments with a different set after certain user actions.

    initially we write some FBML:

    We include facebook’s “all.js” script, the comments show, and all is good.

    Then after some user action we want to show a different set of comments.  So we clear out the existing comments and write some new FBML

    Now, if we can’t include the script again, is there some other way to tell Facebook to re-scan our page for new FBML, or some other way to tell it to activate just this one targeted addition?  

    I’m sure we could wrap their comments in our own iframe, but since their iframe resizes itself when new comments are added we’d prefer to keep their iframe directly on our page.  (if we wrapped it in another iframe we’d have to detect when Facebook resizes their iframe and then propagate that size change out of our iframe up to the top level of our page).

    Any ideas?

    • http://www.facebook.com/timrnicholson Tim Nicholson

      You should be able to use the code snippet in the comment directly above this one to get Facebook to re-parse the XFBML:

      FB.XFBML.parse(document.getElementById(‘COMMENT-DIV-NAME’));

  • Jesse Kocher

    Aah, found it:

    FB.XFBML.parse(document.getElementById(‘content’));

    And you can branch your code like this:

    if (typeof FB == ‘undefined’) {
      //load the script for the first time
      …
    }
      else {
      //use the above code to update only targeted content
      FB.XFBML.parse(document.getElementById(‘myNewFBContentDiv’));
    }

  • Pingback: Programmers’ / Webmasters’ Corner: Real-life problems of the Windows Phone 7 browser and fixing them | SEARCH ALL

  • http://www.facebook.com/timrnicholson Tim Nicholson

    Thanks for writing this article. I’ve been rewriting all of my Facebook PHP apps into Javascript and am looking to optimize the code. I was just reading the Facebook Developer Documentation about the channel.html file. I noticed that you used http:// in your example, but what about when user’s are in SSL mode? The FB Documentation says that for performance reasons you should be sure to serve up http:// or https://, depending on the user’s setting. For testing, I left the protocol off altogether (i.e. “domainname.com/channel.php” instead of “http://domainname.com/channel.php”) and it seems to work, but I can’t tell if I’m getting the performance benefits from specifying one that way.

    • http://www.masteringapi.com Ibrahim Faour

      Thanks for the heads up! it seems (from Facebook Documentation) that you just need to leave double slash and the browser will take care of the rest.

  • Guest

    You may want to verify your spelling of
    channelUrl, you have written it a few times with differing cases of letters. JavaScript is case sensitive, and according to the official documentation it’s written as channelUrl and not channelURL .

  • Dharric

    Both the channel file and the async sdk load load the all.js file. Isn’t this loading it twice?

  • http://www.facebook.com/artdias Arthur Dos Santos Dias

    I use the comments plugin( and app) in my website, but I’m not recieving notifications of when a user comment on a post. I am the admin of the applicaion but still no ‘new comment notifications, the only way to check this is going to a specific URL. any ideas?’

  • http://hsmoore.com hsmoore.com

    Anyway to re-request authentication if a user has disconnected from their apps, so as to not have to recreate their local account?

  • Martin Sjåstad

    “Delay Facebook related tasks till the SDK is loaded” section isn’t working for me, how would you make the function that you want to run will be run? If the SDK is still loading then the function won’t run unless you run it again right?Is there a way to run a function multiple times? Maybe I could use a while loop?

    • Martin Sjåstad

      I found another article on how to do this with jquery, where it triggers an event one can listen to. http://pivotallabs.com/users/jdean/blog/articles/1400-working-with-asynchronously-loaded-javascript

      It didn’t work with a while loop obviously because the Maximum call stack size was exceeded :O

  • QB HE

    very nice

  • Oray Pyaaa

    Every thing is just bullshit. I am trying to share something via an ajax (xss). But not working. I lossed $2000 due to this.

  • Alisson

    nice work.