Choosing between an FBML or IFrame Application
From Facebook Developer Wiki
Note: This article is taken from a blog post by Charlie Cheever, former Facebook Platform Engineering manager.
When you create a Platform application, you need to decide whether you should configure your application to use IFrames or FBML as the default for your application's canvas pages.
There are many factors that can affect your choice. In general, here are some differences you should consider:
FBML
- Lets you quickly start building an application from scratch, which is good for a new Facebook developer.
- Is likely to be faster on first page loads
- Has fewer moving parts and the paradigm is closer to that of the traditional Web
- Gives you easy access to lots of Facebook elements
- Lets your application pages have nice URLs
- Has a sensible authorization mechanism
IFrames
- Are easier and faster if you have an existing application, widget, or website if the application utilizes XFBML
- Are likely to lead to a faster experience for users over the long run
- Let you use the JavaScript, HTML, and CSS that you are used to
- Are faster if you are doing a lot of AJAX in your application, since the requests don't need to go through Facebook proxy
- Debugging regular HTML and JavaScript is easier than for FBML and FBJS given the tools available today
- Allow you to use popular JavaScript libraries like jQuery in your code, but you'd have to modify the library to use it in FBJS, and some things just might not work
Historically, FBML applications had more features than were available to IFrame applications. In the last few months of 2008, Facebook started bringing IFrame applications closer to parity with FBML applications. (For more information, see the original announcement, Enhancing Your IFrame-based Applications.)
This article explains the difference between the two types of canvas pages, and offers some conclusions about what techniques you can use to make the best performing applications.
Contents |
How a Traditional IFrame Canvas Page Works
IFrame canvas pages are pretty straightforward. When the user loads your application's canvas page on Facebook (say http://apps.facebook.com/yourapp/somepage), Facebook renders a Web page that contains the Facebook chrome surrounding your IFrame. The IFrame has a URL to your callback URL, and Facebook appends a number of parameters, like http://www.yourdomain.com/callbackurl/somepage?fb_sig_in_iframe=1&fb_sig_locale=en_US&fb_sig_time=1221720862.9318&fb_sig_api_key=48102584111d14a9c2e41dd28ea637d7&fb_sig=e656792696ae913c1fc34eeff2d79f75
The fb_sig parameters give more information about which user is logged into your application, let you verify that the request is indeed coming through Facebook, and so forth. (For a description of the parameters, see Authorizing Applications.) You can put whatever content you want into the IFrame and it will be rendered inside.
To make your Facebook application a richer social experience, you'll want to include some social content like names and profile pictures, and sometimes you'll want to get some data from the Facebook API to determine which content to show. To show this content without using FBML, you need to use the Platform API and render it yourself.
Here's a simple diagram of how all this works:

Traditional IFrame Canvas Page
How an FBML Canvas Page Works
FBML canvas pages are a little bit different but are still pretty straightforward. When the user requests your canvas page (say http://apps.facebook.com/yourapp/canvaspage), Facebook doesn't send back a response immediately; instead, Facebook sends an HTTP POST to a callback URL on your server (as in http://www.yourserver.com/callbackurl/canvaspage). The fb_sig parameters get sent as part of the POST rather than as part of the URL. Facebook then expects your server to return FBML, and then converts that FBML into HTML and sends it back to the user's browser. FBML is like HTML, but it lets you include social content inline in your markup.
So, if you want to show Facebook data like names and pictures in FBML, you don't need to make calls to the Facebook API; you can just use tags like fb:name and fb:profile-pic to reference the data directly. If you want to use data like birthdays, then you'll still need to use the API, just as you would on an IFrame page.
Here's a diagram of how an FBML canvas page works. Most of the time, you won't need to make any API calls, so those arrows are dotted in the diagram.

FBML Canvas Page
Comparing Various Aspects of Canvas Pages
In general, FBML canvas pages tended to provide a number of advantages over IFrame applications. But over the past few months, Facebook has made a number of enhancements -- mostly as part of Facebook Connect -- that your IFrame canvas pages can use to their advantage. The most important topics are discussed here.
Speed
FBML canvas pages originally tended to be faster for a number of reasons. First, many FBML canvas pages don't need to make any API calls. This means one fewer round trip needs to be made if you are using FBML. Second, Facebook's servers are directly peered with most of the large hosting companies that serve application pages, so the latency on the round trip from Facebook's servers to your application can be much smaller than the latency from the user's browser to your application's server. Finally, there is also some non-trivial overhead from setting up an IFrame on most browsers but this has less impact compared to the first two reasons.
However, Facebook released two features in the last year that really affect the speed of Platform applications: Facebook Chat and XFBML.
Facebook Chat makes it more expensive to set up a page with the Facebook chrome, since the Chat bar involves a lot of JavaScript and CSS that have to get executed and rendered by the browser on each page load -- even if the files are cached on the browser. Both FBML and IFrame applications incur this cost on the first page a user loads from your application. But for every subsequent page load, an FBML application will have to load the Chat bar again, whereas an IFrame application will only be changing the page is inside the IFrame. IFrames always benefited from this, but the effect is more pronounced due to Facebook Chat.
While Facebook Chat makes FBML canvas pages slower, XFBML can make IFrame canvas pages faster. We developed XFBML as part of Facebook Connect as a way to quickly get social content onto any Web page, and since IFrames are just Web pages, XFBML can speed those up as well.
Before XFBML, IFrame applications always had to make API calls to render social content like user names and profile pictures, and those API calls required another round trip communication between your server and Facebook before sending back content to the user's browser. Now, with XFBML, you can embed various FBML tags like fb:name and fb:profile-pic directly into the HTML that your application sends to the user's browser. Then you simply include some Facebook-specific JavaScript, and that code gets executed and scans the DOM for those tags. The JavaScript then determines all the data needed to render that content and batches it up into one API call from the user's browser to Facebook. The rest of the page that isn't social content can render to the user before the API call completes. And in XFBML, we cache data on the browser so that in many cases, it isn't even necessary to make any API call to Facebook at all. This all adds up to making IFrames a faster experience in most cases — though you might still need to make server side API calls to Facebook if you want to do something like show a page with upcoming birthdays.
Here's a diagram of how an IFrame canvas page works using XFBML on the first page a user loads from your app:

IFrame Canvas Page Using XFBML - First Page Load by a User
At a glance, this looks worse than the scenario for IFrame canvas pages that don't use XFBML. But if you use XFBML, then you usually won't need to make an API call to Facebook from your server (which means (4) and (5) don't happen), and the user's browser can start rendering most of the page -- everything except the XFBML content it's waiting to get from Facebook -- right after (6).
On subsequent page loads, the benefits are even greater. Here is a diagram of what that looks like:

IFrame Canvas Page Using XFBML - Subsequent Page Loads by a User
Note that in this case, the original request to Facebook and response to the browser don't need to happen anymore, and the JavaScript API calls will sometimes be unnecessary here as well if the necessary data has been cached on the client. In this scenario, your application should be basically just as fast as a regular website except that the social content will fill in just after the page has rendered, which can result a little flicker on some browsers.
Convenience
We've heard from developers that FBML is simpler than using the API in two ways: batching Facebook data and providing widgets and dialogs.
FBML is really nice when it's important to batch your data access.
It can be pretty difficult to figure out all the data you are going to want on a page up front, and as your pages get more complicated, this problem gets more complicated too. One solution is to produce code that has two sections:
- One that figures out all the data you need, fetches it from the API, and then stores the data in some variables in your program.
- And one that renders all the HTML that you want using the data stored in those variables.
While this technique works, it's a bit tedious and hard to maintain if you want to change anything, since you have to make changes in two places. It's also possible to make mistakes in this scenario, where you remove something from the rendering section but forget to remove the corresponding data access entry. Then you request data you don't need which is hard to notice and inefficient.
This problem gets compounded if you try to build modules that can be reused across different pages. You end up writing two sections of code for each module, which is the same pain as described above but multiplied by the number of modules you have.
The other solution you could use besides a two-pass approach would be to create a system of placeholders that describe the data they need. If you do this, you can have one piece of code that doesn't change that scans all the placeholders, makes a big request for all the necessary data, and then fills it in right before you send your rendered response back. FBML is essentially a series of placeholders, which is why FBML is so convenient -- Facebook does this for you and optimizes it as much as possible so you don't have to build this system or work on it.
FBML is nice for Facebook-provided widgets and dialogs.
Before XFBML, you could render elements like the multi-friend selector and Feed forms when using IFrames, but these methods were often harder to do when compared to doing them with FBML. There are also some useful widgets that are provided as part of FBML like fb:share-button that are difficult to recreate on your own (though certainly possible). The fb:dialog tag is a really nice way to make a pop-up dialog with a few options. If you want to make an application that is consistent with Facebook's look and feel, these tags can make that task much easier.
Now, with XFBML, in addition to being able to embed things like fb:name and fb:profile-pic directly into your HTML, you can render any FBML tag by using server-side FBML. If you wrap your FBML inside fb:serverfbml tags, as in:
...then this opens an IFrame to Facebook on the page being served from your domain, and Facebook will render the FBML in there.
However, a fair amount of overhead is involved in opening the IFrame, and your CSS won't propagate into the FBML IFrame, so you won't want to put too many blocks of server-side FBML on a page. But if you need one or two snippets of FBML to make your application richer, or you want a large chunk of your page to use FBML, this makes that possible and pretty easy.
Appearance
One cosmetic issue that often made IFrames look unattractive is that you had to specify a fixed size for them. Then, if any content exceeded those specified dimensions, scroll bars would appear, or else the overflowing content would be inaccessible to the user. Facebook introduced the ability for your IFrame to resize automatically. You simply need to include some Facebook-specific JavaScript in your code that generates the IFrame, and Facebook resizes the IFrame automatically.
Preload FQL
FQL is a powerful way to get Facebook data easily. Typically, you'll know which FQL queries you need to make to generate a page even before the request comes in from a user. For example, if you want to make a page that shows a calendar of friends' birthdays, then you know you'll need to query the User (FQL) table for all the birthdays of all the friends of the user. Preload FQL lets you do these sorts of queries on both FBML and IFrame canvas pages, though it works differently for each. In general, you specify a few regular expressions that map to lists of FQL queries. If the page being requested matches any of the regular expressions, the corresponding FQL queries will be executed by Facebook when the user's browser sends the request to Facebook.
For FBML applications, the results get sent along to your application's servers when Facebook requests the FBML from you. Most of the time, this makes calls to the Facebook API unnecessary, even when you need fairly complicated data from Facebook to generate the page.
This is what the flow would look like for an FBML canvas page using preload FQL:

FBML Canvas Page Using Preload FQL
In the diagram above, the FQL query is executed after (1) and the results are sent along to your application server with (2).
Preloading FQL works differently with IFrames. In order for Facebook to send data to your server along with the request for the IFrame, it has to encode the data in the URL being requested. Instead of sending the FQL result set to your server, the Facebook server sends the FQL result data down to the user's browser, attached to the outer frame that contains the Facebook chrome on the canvas. You can choose whether you want to have a lightweight redirect occur, which encodes the FQL results in the request made for your IFrame page. Or, if you only want to access that data on the client side, you can use the PreloadFQL_get method from the JavaScript client library and rewrite parts of the page on the fly using the data after it's initially rendered.
Here's a diagram of how this works:

IFrame Canvas Page using Preload FQL
Note that the preload FQL will only work on the first page that loads in your IFrame. If you point your links to apps.facebook.com URLs using target="_top" instead of just linking to different pages within the frame, you could use preload FQL on every page, but this would make all your pages load slowly. If you want to direct the containing frame to make API calls which could then be fetched across pageloads within the IFrame, you should be able to do this by wrapping your IFrame canvas pages within your own extra IFrame.
This paradigm is a bit different from the way the Preload FQL works with FBML canvas pages. And, if you've written AJAX-intensive Web applications before, this should be a familiar method.
Getting Users' Friends Automatically
With Automatic Authentication, Facebook sends the list of the user's friends to the containing IFrame right away, so you won't need to call the friends.get method from the JavaScript API client, saving you a round trip to the server.
URLs
With FBML applications, the URL for each canvas page is always shown in the browser's address bar. Previously, the URL for IFrame canvas pages never changed in the address bar. The URL always was the first URL the user visited, unless you specified target="_top" on your links -- but that meant incurring all the costs of a first page load every time, making IFrame applications much slower. This also made it inconvenient for users who want to bookmark particular pages or copy links to share.
IFrame Url is a mechanism similar to automatic resizing in that you include some Facebook-specific JavaScript that executes in your IFrame. This JavaScript code communicates its location to the embedding Facebook page, which can then manipulate the fragment of the URL (the part of the URL after the #) without causing the browser to reload the page.
Authentication
On FBML canvas pages, the request for FBML that is sent to your application server contains POST data that lets you learn and verify that the request is coming from Facebook on behalf of a particular user. If that user has a session with your application, then the session data you need to make API calls on behalf of the user will be passed along as fb_sig_session_key in the POST. Most client libraries handle this pretty seamlessly, and so you don’t have to think about it.
On IFrame canvas pages, things work differently. Facebook passes fb_sig_session_key to your IFrame as a GET parameter in the querystring of the IFrame's URL. As with FBML canvas pages, most client libraries make this pretty painless and invisible to the developer; but there are two significant flaws with this approach.
- Browsers can leak the session key via the HTTP_REFERRER field. This can be a pretty serious security flaw, and is easily exploitable if you let users post public links or images. You can work around the issue with links by sending all links through a redirect. The only safe way for an IFrame canvas page to reference user-provided images is to proxy or cache those images yourself.
- It's inconvenient to link to pages within your application without losing the session information. While you can make your links point to canvas pages (like http://apps.facebook.com/youriframeapp/nextpage.py) and set target="_top" on the link, this means that you don't lose session information but also means that your application incurs all of the overhead of setting up an initial IFrame canvas page which leads to a pretty clunky feeling application experience. Another technique you can use is to link to other pages that are off your canvas URL (like http://yourdomain.com/appcallback/nextpage.py) and manually append all of the fb_sig parameters to the querystring. The major problems with this approach are that if a user opens that page in a new tab or copies and pastes any of those links, then the Facebook chrome gets lost, and all sorts of problems can happen with the session information (the session may have expired, the session might be for a different user than the person viewing the URL, and so forth), so this isn't a desirable choice either.
Overcoming the Session Key Issue
One possible solution you can try involves the fact that the session information gets sent to the containing frame and is stored in the DOM. The URL for the IFrame doesn't have any fb_sig session information encoded in the querystring. Instead, that information gets stored in a cookie on your application's domain so that the user's browser passes it to your server with every request. If there's no authentication information in the cookies when your server gets a request, then your server can send back a page that is just some JavaScript that communicates with the containing frame to find out the session information, sets the cookie, and then reloads itself.
In this solution, each IFrame page that your server sends to the browser should contain some JavaScript that would verify that the session information in the cookies matched the session information in the containing frame, and if it didn't, then the cookie would be set to the right information and the page reloaded. It is also useful to pass to the first IFrame page that loads some fb_sig parameters that your server can use to verify that the session in the cookies is still valid and for the correct user. This prevents exploits where a malicious user could load a canvas page with stale cookies and capture the contents sent to the browser for another user before the JavaScript reset the cookies and forced the reload.
However, setting cookies doesn't work in some browsers (like Safari) for IFrames of domains other than the one in the location bar, so this solution won't work for all browsers. There may be other solutions, and feel free to share them here.
Using IFrames in FBML Canvas Pages and FBML in IFrames
If you're using FBML for your canvas pages and you decide you want one of your pages to be rendered in an IFrame, don't use fb:iframe for that. Instead, you should use the fb_force_mode querystring parameter to switch modes which will accomplish the same thing without incurring a round trip to your server just to fetch the fb:iframe tag.
Similarly, if you are using IFrames for your application but want some particular page to be an FBML page, you can use fb_force_mode to force a switch to FBML. If you find documentation that advises using fb:iframe for switching from FBML to IFrame mode, it was probably written before fb_force_mode was released; we should have all those instances cleaned up soon.
Setting target="_top" in IFrames
As mentioned earlier, if you're using IFrames for your canvas pages, don't set all the links to have target="_top". This causes a full reload of the Facebook chrome, which includes an extra to request to do so as well as generate a new IFrame, making your application pretty slow. If you're using an IFrame within an IFrame (or even deeper nesting) and so you need to set a link target explicitly, the IFrame that is your canvas is named iframe_canvas so you should just be able to use that as a target.
