Open Source

A First Look at OpenSocial

On November 2nd, Google announced its OpenSocial initiative. Amidst the breathless hyperbole there came a prevailing sense of confusion from the world’s web developers (including those around our office). What exactly was this “OpenSocial?” Was it an API? A framework for building web applications? A social network? Was Google invading the Facebook space? All of the above? And – perhaps most importantly – just what the heck are we supposed to learn, exactly?

It turns out that OpenSocial is all of those, and a bit more. It’s also a bit loosely defined, and complete documentation is still a bit scarce. So I’m going to try and fill this understanding gap.

While some good write-ups of OpenSocial have been circulating the web since the announcement (Marc Andreesen’s is particularly fine) none of them really offer a full picture of the OpenSocial initiative, including how it extends current concepts of widgets and the social web. Moreover, none of them really speak to engaged, active web developers about how to “get on track” with it. If you happen to be one of those developers – smart, passionate, and perhaps a little bit late to the party – this should get you going, and quick.

A First Look at OpenSocial: Background

OpenSocial extends out of the rise in popularity of widgets on the web. How am I defining widgets? In the context of the web, widgets are typically HTML, JavaScript and/or Flash, bundled together, into a self-contained mini-applications. Stock tickers, clocks, mini news readers and weather displays are some example of popular types of widgets.

Widgets are not a new concept. The original Macintosh operating system embraced the concept of “desk accessories” – tiny, omnipresent applications, uniquely styled to be recognized at a glance. This continues today in Mac OS X, in the form of the Dashboard. Software programs like Yahoo Desktop Engine (formerly Konfabulator), Google Gadgets (when paired with an environment like Google Desktop) and the Windows Vista sidebar are other examples of widgets at work in the personal computing space.

While these types of widgets are used as productivity enhancers, other types began to gain popularity with the rise of social networking sites like MySpace. Typically built in flash for easy portability, widgets like slideshows, mini games, movie players and scoreboards were meant to be installed in social websites, and to be viewed not by the person installing them, but by others. They are meant to impart information or a sense of style. They are social.

While definitely popular, these widgets are still self-contained. This aspect of widgets makes them portable and easy to install – it’s not difficult for a person to cut and paste a two-line flash embed code – it does limit their utility. Widgets for the web either completely lack customization, or they require a large amount of overhead on the part of the widget creator, to support things like data persistence. Furthermore, widgets don’t know anything about where they’re placed. Finally, not all social websites support the various ways a widget can be delivered (straight HTML, JavaScript, Flash, etc…)

2007: Facebook Applications Up the Ante

In May of 2007, Facebook changed all that, when it officially launched its Facebook Platform: with this, there was one spot in which all Facebook widgets could be listed, and easily added to profiles. Furthermore, the Facebook platform introduced the concept of a “Canvas” page, which gives applications an entire, user-unique view to offer additional functionality, simply when they’re installed by a user. Finally, Facebook applications (in both the widget and canvas view) can access user profile information, interact with the user’s friends, and provide mechanisms for application promotion.

Problems Still Remain

Boy do they ever. While Facebook’s development platform exposes a lot of power, it’s fairly complex, with its own markup language, API and even an abstracted query language to search the Facebook database. Needless to say, these options are completely specific to Facebook, as is 90% of pretty much any application you write for the platform. At this point, developers who want to embrace MySpace, Facebook and traditional websites are stuck writing, at the very least, three completely separate applications. They also must market those applications separately.

Enter OpenSocial

It is against this landscape that OpenSocial arrives. Consumers, web developers and clients all recognize the market for widgets and customizable mini-applications and their spaces. But with a multitude of social networks, how is it feasible for the average developer or development shop to support more than the biggest networks? The best case scenario? Facebook users get the most full-featured application; their app has a fully realized widget, a canvas space with extra full-page functionality, and the ability to tie in to users who also use Facebook. Other websites get a simple widget with little to make it specifically compelling to members of said website. Big win for Facebook. Mixed results for everybody else.

In theory, OpenSocial should change that. According to the OpenSocial initiative: “OpenSocial provides a common set of APIs for social applications across multiple websites. With standard JavaScript and HTML, developers can create apps that access a social network’s friends and update feeds.”

Clearly, Google is positioning OpenSocial as the answer to the Facebook platform, but one in which any widget or application developer can write once, deploy everywhere. That’s the hype. Does OpenSocial deliver? Let’s answer the questions.

Questions about OpenSocial, Answered

What are the components of an OpenSocial application? What are they made out of? When comparing OpenSocial applications to widgets for MySpace or other social networks, the answer to this is simple: OpenSocial widgets are essentially Google Gadgets. Google Gadgets are Google’s own implementation of widgets, built in HTML and JavaScript, and served in an iframe. A public API for Google Gadgets already exists, separate from OpenSocial. Up until now, however, these widgets have faced the same problems as widgets on MySpace.com: they’re self-contained, and know little about the environment in which they’ve been embedded.

OpenSocial adds a new API and JavaScript namespace for use inside Google Gadgets. Since Google Gadgets already use JavaScript, using OpenSocial’s JavaScript API is really a simple way to allow your widget to access friends list and some simple information about those viewing it. For example, the following JavaScript, when added to a Google Gadget, gets information about the friends of the person viewing the Gadget:

function getData() {

    // Creates an Open Social request object. 
    var req = opensocial.newDataRequest();

    // Adds a new request to this object - let's get information about the person viewing 
    // this widget, and store it mapped to the "viewer" attribute in the response object 
    req.add(req.newFetchPersonRequest('VIEWER'), 'viewer');

    // Let's request some more information. Let's get information about the viewer's friends, and store it 
    // mapped to the "viewerFriends" attribute in the response object. 
    req.add( req.newFetchPeopleRequest('VIEWER_FRIENDS'), 'viewerFriends');

    // Let's send the request to the container website, which will load the "onLoadFriends" function when 
    // data is available 
    req.send(onLoadFriends);

}

// this function loads with information from any Open Social requests. 
function onLoadFriends(response) {
    // viewer and viewerFriends are available in the get() method below because that's 
    // what I named them in the req.add() call above 
    var viewer = response.get('viewer'); 
    var viewerFriends = response.get('viewerFriends');
    var data = viewerFriends.getData();
}

While the API documentation explains additional data types available to OpenSocial widgets, at their core they’re just that simple. More adventurous developers can perhaps dispense with the JavaScript API entirely, and use OpenSocial’s REST-based API for getting data about people, activities and data persistence, but for most the simpler JavaScript API will be sufficient.

Where do the assets for these applications live?

OpenSocial widgets can use assets hosted anywhere on the web, and linked to through simple HTML. Additionally, Google will host your assets on its domain gmodules.com; just upload your images and external stylesheets through a menu option in the Google Gadget Editor, and Google will store them and provide you a URL to link to them.

How do customers find these applications – is there a directory?

Google currently hosts a Google Gadgets directory. Since OpenSocial is simply an API that can be included in Google Gadgets, they will likely appear in this directory without much fuss. Unfortunately, there is currently no list in the directory of which sites support OpenSocial, and to be truly effective and compete with Facebook OpenSocial will need to allow these applications to be added directly from within their container websites. There currently isn’t any documentation on this, although to check out what is known, jump to our section on how a social network might include OpenSocial widgets.

Can I store data in them? How much and at what cost?

Yes, you can store data in social gadgets. The Google Gadgets API has support for saving preferences, meaning that when you add that ESPN Scoreboard widget to your profile, you’ll be able to specify it as having a red background with white text; this instance of the ESPN Scoreboard widget – the one tied to your profile page – will continue to exist with these settings until you change them or remove the widget. Everyone who views the widget will also see it with a red background and white text.

Instances of widgets (like the example above) can also have additional data stored against them for those who might view them. For example, the ESPN Scoreboard widget might not only provide the ability for the person embedding it to set its background and foreground text, but might also offer viewers of the widget the ability to override those settings. These are “viewer”-specific settings, just like cookies on a web page. The settings saved for each instance of a widget are bound to the viewer’s profile, by using the OpenSocial Persistent Data API.

How would we implement this in OpenSocial? Let’s say a widget developer wanted to make it so that a person viewing the widget could save their city and state, so that the next time they viewed the widget they wouldn’t have to re-enter them. This information obviously differs from viewer to viewer, so it couldn’t be saved in the widget’s global preferences. The developer would need to bind this data to the profile of the person viewing the widget. Here’s how he or she would do it:

// city and state that the viewer of this widget has selected is passed to this function
function saveCityAndState(city, state) {
    var req = opensocial.newDataRequest();

    // we use newUpdatePersonAppDataRequest to specify that we're updating data the data saved is
    // bound to the person viewing the widget
    req.add(req.newUpdatePersonAppDataRequest("VIEWER", "AppCity", city));
    req.add(req.newUpdatePersonAppDataRequest("VIEWER", "AppState", state));

    // we pass the function that's run automatically when the request completes
    req.send(function() {alert('Data Saved!')});
}

Reading that data back programmatically is similarly simple:

function getViewerInformation() { 
    var req = opensocial.newDataRequest();

    // define the fields that we're retrieving for the viewer of the widget 
    var fields = ["AppCity", "AppState"];

    // define the request for the fields above, which uses the fetch person data request
    req.add( req.newFetchPersonAppDataRequest( "VIEWER", fields), "viewerData" );

    // send the request to OpenSocial API
    req.send(function(data) { 
        // on completion, this function is run automatically passing the data object to it
        // "viewerData" is populated because that's what we bound these fields to above 
        var viewerData = data.get("viewerData"); 
    });
}

While this example stores strings, I imagine it isn’t too difficult to store complex objects, if you serialize them to JSON first. For more information on how the data returned is structured, check out the Social Google Gadget API documentation.

Do these applications have access to user data?

Short answer, yes. The OpenSocial API gives developers access to a small amount of fixed data (a “display name,” a thumbnail image, a user ID and a profile URL) and a varying amount of data which can be filtered by type, including “BASIC,” “CONTACT,” “FULL,” “MATCHING” and “PERSONAL.” The actual mechanics of using the JavaScript API to retrieve this information are somewhat up in the air, with few examples of applications actually using extended profile data, and no examples of programmatically determining what data is actually available on a container by container basis. Check back soon – or voice your displeasure at incomplete documentation in the Google Group for Open Social.

How does OpenSocial deal with different networks’ design limitations?

This is still a bit of an unknown; while many networks have pledged to support OpenSocial, only a few like Google’s Orkut, Hi5 and Ning actually have environments in which it can be tested, and even in these OpenSocial is only available in the developer sandbox. At a glance it appears that OpenSocial has attempted to gather up some of the most prevalent functionality in the social networking space – an activity stream, basic user information, friends and people in general – and provide access to them. It is up to the container website to determine how much of the OpenSocial API it wants to implement, meaning that the onus is still on the application developer to provide error checking and graceful failure if certain aspects of the OpenSocial API aren’t available. This is too bad, although probably unavoidable.

How does view/edit work?

OpenSocial at its core is really about widgets. In this way, it’s not really concerned about the difference between viewing and editing, beyond giving application developers the ability to save state, and giving the developer a way to specify preferences, which can be exposed and edited easily (this is part of the Google Gadgets framework.)

For these widgets, only one view is ever defined; it is up to the developer to include all necessary view logic within this one context. A widget could present two distinct interfaces – view and edit – to only the owner of the widget, with all other viewers only getting the “View” interface, but this capability must be explicitly included by the developer, including any permissions checks to determine whether certain controls ought to be displayed to someone viewing the widget.

How does Yet Another Social Network (YASN™) take advantage of these widgets?

First, one must become a Google Gadget container, a process which is reasonably well documented, and has been used by many of websites. This, however, is nothing new. To actually make your widgets aware of their container website, and implement the OpenSocial API, a site must implement the OpenSocial Service Provider Interface. As of this writing an official development kit to add these capabilities and expose them via the necessary JavaScript framework is still forthcoming from Google, but they have just released an OpenSocial Container sample.

Do I need to get my applications “blessed” by Google in order to run OpenSocial?

Nope. Although you need to submit your applications for review in order to get them to be included in the official Google Gadgets directory, you may host your gadgets from anywhere and need only a provide a URL to end users who wish to install it.

Why is Google doing this?

There are probably a few reasons.

  • Their motto, “Do No Evil.” I suppose this would qualify.
  • In the minds of some, this is a warning shot fired at Facebook. If Google is indeed in talks with acquiring Facebook, this might be a bargaining tactic.
  • Since OpenSocial gadgets are, by their very definition, Google Gadgets, this increases the profile and number of Google Gadgets available to consumers. This will also increase the number of websites looking to become Google Gadget containers, which promotes their widget platform further. With millions of mini-applications installed across a multitude of social networks, Google gets increasing access to more data – definitely a win for a company whose business is data mining.

Have any “gotchas” been discovered? Anything that us developers might like to know?

There always are. One of the most useful tips I’ve discovered has been this one:

While developing the Hello World widget described below, I found that Orkut would frequently cache my Gadget output, making active development of widgets a painful, painful process. However, if you append “&bpc=1″ to your Orkut application URL, the site will stop doing this. For example, if you’re viewing your in-development widget at

http://sandbox.orkut.com/Application.aspx?uid=x&appId=x

You can keep from ever seeing a cached version of the gadget by making the URL

http://sandbox.orkut.com/Application.aspx?uid=x&appId=x&bpc=1

Another tip? Double-check the data you get back. While checking the Google Group for OpenSocial, I found that certain details of the API haven’t exactly been normalized across service providers. Attempting to retrieve a profile URL for a user record on Orkut returned the following:

/Profile.aspx?uid=xxxxxx

Grabbing the same data on Hi5 returned a fully qualified URL:

http://sandbox.hi5.com/friend/profile/displayProfile.do?userid=xxxxx

Clearly, this is a problem on Orkut’s part, but keep this in mind – this platform is far from stable.

Building Your First OpenSocial Widget

As mentioned before, OpenSocial widgets are really just Google Gadgets that add an extra API, which allows them to get some information from their container websites. So, to build an OpenSocial widget, we really need to start by building a Google Gadget. And Google Gadgets, at their simplest, are self-contained XML files. To give you the simplest example, here’s a “Hello World” Google Gadget I created, using the Google Gadget Editor, an inline, JavaScript-powered editor:

The code for this widget is very, very simple:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
    <ModulePrefs title="Hello World" />
    <Content type="html"><![CDATA[
        <div>
            <div style="text-align: center">
            <img src="/url/to/logo.gif" /></div>
            <div>Hello World!</div>
        </div>
    ]]></Content>
</Module>

(Note: I omitted some miscellaneous style information to make this example easier to read.)

While the Google Gadgets API offers many features for widget creators (including dynamic, styled tab creation, drag and drop, localization, and more) as well as the ability to store information about widgets like their title, author and a link to a thumbnail image, at their core Google Gadgets are really as simple and self-contained as the example above.

Let’s take a look at my widget; sure, it’s fantastic, but it’s a bit static. What if we were to socialize the widget by making it say hello directly to the person viewing it. Wouldn’t that be something? Well, that’s the kind of stuff that OpenSocial can provide.

First, we’ll need to make the Google Gadget include the OpenSocial API. We do this with a simple XML declaration inside the ModulePrefs tag:

<ModulePrefs title="Hello World">
    <Require feature="opensocial-0.5"/>
</ModulePrefs>

Next we replace “Hello World!” in our application with “Hello ,” using the DIV as a placeholder that will eventually be populated by our call to the OpenSocial API. Finally, we add in the necessary JavaScript:

// sets getData() as the function that automatically gets called when the gadget is loaded 
_IG_RegisterOnloadHandler(getData);

function getData() { 
    // Creates an OpenSocial request object. 
    var req = opensocial.newDataRequest();
    // Adds a new request to this object - let's get information about the person viewing 
    // and store it mapped to the "viewer" attribute in the response object 
    req.add(req.newFetchPersonRequest('VIEWER'), 'viewer');

    // Let's send the request to the container website, which will load the "onLoadFriends" 
    // function when data is available 
    req.send(loadViewer); 
}

function loadViewer(response) { 
    var viewer = response.get('viewer').getData(); 
    var vn = document.getElementById("viewer-name"); 
    vn.innerHTML = viewer.getDisplayName(); 
}

The code should be pretty easy to read. First, we initiate a callback function through the use of Google's _IG_RegisterOnloadHandler function; this function automatically runs and causes its function argument to run when the gadget is finished loading. The getData() function then instantiates a new request object to the OpenSocial API, adds a request for information about the viewer, and then sets up the loadViewer() callback, which is run automatically when information returns from the API. This information is then parsed for the viewer attribute (which was set in the req.add() method), and the viewer's display name is inserted into the contents of the viewer-name placeholder DIV.

Limitations of OpenSocial

While the “Hello World” example above should give you an idea of how to build a social gadget, it wasn’t my first choice for a widget. Around our office, while brainstorming ideas for this article, and still somewhat confused about OpenSocial’s exact capabilities, we conceived of a different type of widget. We wanted one that, when placed on someone’s profile page, was able to learn and store that it was placed on a particular social network. That’s not that compelling – obviously an instance of a social gadget on a profile page is able to tell what container website it’s on, whether through the API itself or even inspecting variables like the profile URLs available. However, in addition to this, we wanted every instance of this widget for a particular user, spread across multiple social networks, to be able to share this data. This would create a “My Social Networks” widget, which would list all of a user’s profiles around the web, without the user ever having to modify the widget or tell the widget that they had an account on Flickr, MySpace, Hi5, etc…

On each website, the user would add the “My Social Network” widget, which would then communicate with every other instance of the widget spread across multiple social networks. We had hoped that OpenSocial, in addition to specifying common hooks for widgets to interact socially within a container website, would focus on people with multiple profiles, across multiple websites.

Unfortunately, OpenSocial doesn’t do this. Each instance of a widget on a container website knows only about the profile to which its linked, and that profile’s friends. My profile on LinkedIn and my profile on MySpace are too completely separate profiles, and OpenSocial provides no ability for widgets to actually understand that these profiles belong to the same person. We had hoped that it would. Yes, OpenSocial allows the developers of the ESPN Scoreboard widget to build them once for Orkut.com and once for MySpace.com, and still hook into each site’s social functionality, but that is the extent of its benefits.

Conclusions

When Google first announced its OpenSocial initiative, about the only thing anyone really knew about it was the type of reactions it would provoke. Yes, we would see the initial outpouring of support; the hyperbole over Google’s massive foray into the social space; its shot against the Facebook ship. Almost as predictable as the praise was the condemnation: OpenSocial was not that impressive, not that interesting, and really not even worth talking about.

But as always, the truth is much less polarized, and quite a bit more mundane. Actually, OpenSocial is pretty interesting, and does showcase a new, standardized approach toward building social-website-aware widgets. In a world where every social network joins the OpenSocial initiative, web developers will have to do less work, and be able to support more customers than before. Furthermore, OpenSocial helps Google reassert its presence in the widget space which, honestly I must admit, I’d completely forgotten about. Checking out the OpenSocial API has reminded me of their mature, pretty full-featured Google Gadget offering.

Of course, it’s not perfect. These widgets are really only “social” within their container website; this isn’t an inter-site communication API. Also, while Orkut appears to support different views for its various applications (like Facebook does), this is a decision each social network must make for itself; there’s nothing built into the OpenSocial API to really support or encourage innovations like the Facebook canvas view, which is too bad: our Lemonade Facebook application is fun and informative in widget view, but it really shines when you bring in Facebook platform-specific code, like the ability to invite other users to the application, or the ability to show large-format information in a separate canvas view. Yes, some websites will support these types of views, but unless they’re built into the API, and the API itself is built in such a way that all of its functionality must be enabled on each container website, developers are still stuck writing website-specific code.

I think these are valid criticisms, but I don’t want to let them overshadow the entire initiative; it’s easy to get hung up on what OpenSocial doesn’t do, and miss out on what it it does. No, you won’t be able to stop writing Facebook-specific widgets yet, but the next widget you make will at least be able to say hello to you by name, on multiple websites. While application underpinnings won’t become completely website-agnostic any time soon, developers will be able to write less code. So take the time to explore OpenSocial, and voice concerns about its shortcomings; the more we do this, the more likely OpenSocial 2.0 will really be something to write home about.

Loading Conversation