Last week we launched Lanyrd's integration with foursquare. Here's how it works under the hood. (If you aren't fascinated by APIs, HTTP, JSON and web hooks this post probably isn't for you).
When we saw foursquare's new connected apps platform, we knew it would be a great fit for Lanyrd. The platform lets foursquare users connect other apps to their account - then, when they check in on foursquare, those apps can respond to that checkin with additional information. Many of the tens of thousands of events listed on Lanyrd have venue information attached to them - if we could match those venues to foursquare, we could respond to checkins with information about events taking place at that specific place. Our mobile web app already provided pages that would work well within the foursquare app - all we needed to do was hook everything together.
The first step was to start matching our venues up with places listed on foursquare. With thousands of venues to match up, this was a pretty big undertaking. Thankfully foursquare's venues/search API has a mode intended for exactly this purpose - setting the "intent" parameter to "match" allows you to pass in a lat/lon pair and a text string and get back foursquare venues that are the most likely match.
We're sticklers for high quality data, so we built an interface that let us quickly plough through matched venues, checking that each one was accurate. It was still a tall order to go through every venue, but by restricting the tool to only showing venues hosting events that will take place in the future we cut it down to a manageable task. We'll continue to run the tool intermittently to spot newly added venues that need matching, and we've exposed a matching interface to site users as well.
The way foursquare pass checkins to apps is refreshingly straight-forward: once someone has connected your app with their foursquare account, their future checkins are passed to your app via an HTTP POST request (the web hooks pattern) containing JSON and a shared push secret (so you know the POST comes from foursquare). If your app decides that it should respond to a checkin it can do so by making a "reply" API request back to foursquare. Provided you do that while the user is still viewing their checkin within the foursquare app, your reply will be displayed directly to them. It's all asynchronous so the performance of their app isn't affected if your app takes too long to respond.
Foursquare (wisely) insist that these POST requests are delivered over SSL, which lead to some interesting challenges while developing the app (an SSH tunnel to a server running an SSL-enabled nginx proxy did the job). Handily foursquare provide a "re-send last push" button in the developer tools which makes debugging relatively easy.
When a checkin comes in, we first look up the foursquare venue ID to see if it matches one of our own venues. If it does, we check to see if at least one conference is taking place on that day in that particular venue. We have to take the timezone of the venue in to account - if someone is in Australia their absolute definition of what "today" is is very different from someone in London. If either of those steps fail we discard the checkin.
Assuming we got a match, we reply to the checkin in one of two ways. If there is only one event taking place in that venue, we send down a link to information about that event. If there is more than one event, we send down a link to a custom page that lists all events taking place at the foursquare venue listed in the checkin.
Early versions of our code failed to take in to account the existence of checkins that didn't list a venue (which foursquare call "shouts"), leading to some errors showing up in our log files. We've fixed that now to discard any checkin that doesn't include a "venue" key in the JSON.
There are two mechanisms built in to the connected apps platform designed to help promote your app. The first is simple: when one of your friends connects an app to foursquare, you see it in your foursquare activity stream. This provides a handy way for word about your app to start spreading.
The second is a little more involved, but potentially more powerful. When a user checks in, you can optionally make an API request that adds a post to their checkin which will be seen by all of their friends. We figured that announcing the event that a user was attending fitted the spirit of the feature nicely.
As a result, we actually support two kinds of foursquare integration, depending on if you linked foursquare with your Lanyrd account (by signing in to Lanyrd when you connected the two). We only send checkin comments if you have linked your accounts together - if you haven't, have no way of telling if you planned to attend the event or not.
One final twist is that we if you mark yourself as attending an event within ten minutes of checking in to the venue, we still write the comment to your checkin. The quickest flow for doing this is for users to hit the "attend" button within the event page that we link to from the initial foursquare checkin message. This requires an authenticated session, so we include a one-use, time-limited login token in the private URL that we send to the phone. Ideally we wouldn't need to do this, but the web view embedded in the foursquare apps doesn't have access to the system-level browser cookies so any existing session on Lanyrd is ignored when our page opens within foursquare.
I'm really impressed with how foursquare have designed their API. It uses oauth2, which meant that getting authentication up and running was extremely quick (I didn't even need to use a library). Their JSON is self documenting and easy to extract the relevant information from. Sending checkins to us with a simple HTTP POST makes it simple to accept and process them, and securing them with a combination of SSL and a shared push secret is both pragmatic and easy to integrate with. Most importantly, they've clearly thought hard about providing the right debugging tools - aside from the need to get our development environments communicating over HTTPS it was very easy to figure out what was going on.