Monthly Archives: May 2011

The final part of Beats Per Mile worth mentioning is the Twitter integration.

The application was designed to send automated tweets on Gemma’s behalf from her personal Twitter account giving updates of her progress to those following.

Mainly the tweets would report her current location for the purposes of spectators waiting ahead, others would be sent at intervals of a mile or so to report pace and ongoing form.

Similar to the mechanism for fetching Instagram images at predetermined locations on the course, the application contained a list of agreed points at which to tweet.

These were at landmarks and certain spectator spots too, but also at course milestones — the first mile complete, halfway complete, one mile to go etc, as well as the start and finish.

The application monitored the elapsed distance and updated accordingly, grabbing the latest time and statistics from the RunKeeper data, as well as geolocating the tweet with the latest set of GPS coordinates.

Since Twitter deprecated support of Basic Auth, applications much authenticate users with OAuth to gain write access.

This means rather than handing over your username and password to applications and trust (hope) that they’re friendly — as used to be the only way — OAuth allows applications to request access on your behalf without users ever parting with precious login credentials. You simple give, or deny, permission.

Using TwitterOAuth

Twitter offer a number of links to OAuth libraries for various languages to make the this job a lot easier. There are many Twitter specific OAuth libraries in particular, purposely tailored for the API.

I picked up PHP-based TwitterOAuth by Abraham Williams, which gets you up and running very rapidly.

The OAuth flow is documented at length, but essentially performs three major tasks:

  • Obtains access from Twitter to make requests on behalf of a user
  • Directs a user to Twitter in order to authenticate their account
  • Gains authorisation from the user to make requests on their behalf


This is achieved with a cycle of exchanging authenticating tokens between application and Twitter to verify permission. TwitterOAuth particularly creates a session object in your application and rebuilds itself with each token exchange to remain contained in a single class instance.

In a very abridged manner, something like the following:

// Build TwitterOAuth object with client credentials
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
// Get temporary credentials to allow application to make requests and set callback
$request_token = $connection->getRequestToken(OAUTH_CALLBACK);

This initial call verifies your application has access the Twitter API, basically that it’s registered and good to go. Twitter returns two tokens, if successful, that we store:

$_SESSION['oauth_token'] = $request_token['oauth_token'];
$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];

Then the application sends the user to Twitter to authorise it’s access, using a URL generated with the token received above:

$authoriseURL = $connection->getAuthorizeURL($request_token['oauth_token']);
header(‘Location: ‘ . $authoriseURL);

On successful authorisation Twitter will return the user to your callback URL (set above) with a verification token. TwitterOAuth now rebuilds for the first time with the OAuth tokens in our session and uses the new verification token to get an a new access token which will grant us user account access:

// Create TwitterOAuth object with application tokens
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']);

// Request access tokens from Twitter on behalf of current user with verifier
$access_token = $connection->getAccessToken($_REQUEST['oauth_verifier']);

This final request gets us two OAuth tokens specific to the current user, allowing us to make requests on their behalf, with which TwitterOAuth rebuilds again:

// Rebuild TwitterOAuth object with user granted tokens
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $access_token['oauth_token'], $access_token['oauth_token_secret']);

// Test that everything is working
$connection->get(‘account/verify_credentials’);

The dance made a hell of a lot easier with a library such as this.

Usually applications store these tokens final two tokens, the user generated oauth_token and oauth_token_secret, which saves the need to authorise the user again.

Storing these details (in a session or database) means that a username and password need not be saved. The tokens are good until the user revokes access, no sensitive information is ever released to the application, all the user ever gives is their permission.

With access tokens stored, the connection to Twitter is a lot simpler — just create the TwitterOAuth object with those user-generated codes as in the very last step, without any of the redirecting to and from Twitter.com. Of course, those tokens could only have ever been obtained by carrying out the full process to begin with.

Beats Per Mile is a single-user case application, so Gemma only had to authenticate the application once and then we hard-coded them into the scripts.

Tweet Away

With access granted the application was free to send out updates, based on the run data we were collecting and posting it directly.

As mentioned, locations translated into distances and that’s when we tweeted.

At mile twenty, it looked back at the mile splits so far and reported which were the fastest:

Relying on the total reported distance alone was flawed. There was a slight hiccup when RunKeeper lost GPS coverage under Blackfriars tunnel and in an attempt to compensate found the nearest location to be the other side of the Thames.

This caused a problem by adding extra distance to her total, so some of the latter tweets (“one mile to go”, for example) posted a little prematurely.

It was more of a problem for Gemma when running, the app announcing in her ear that she’d run further than she had, disheartened to see mile markers on the course thought to have already passed.

This is also why the total distance on the site clocks up to 27.65 miles, the race was long enough as it is!

The final touch to was to drop them on the map, alongside the Instagram images.

Beats Per Mile uses the Instagram API to find pictures taken around the marathon course.

We decided we’d need to find a way to put pictures on the map quite early on, knowing Gemma couldn’t be the one to stop and take them. Rather than try to pin a camera to her vest or strap one to a hat, the simplest solution was to find photos taken by spectators.

The Instagram API is fairly new and the app itself is getting extremely popular. Being mobile-based, we hoped it would be popular among spectators on the day, taking quick snaps and hopefully uploading a good amount of photos to dig around in.

The pictures are geo-tagged as well as captioned, so we could perform location queries and text-based searches (ultimately, a combination).

Firstly we agreed on places around which we’d search for pictures — busy spectator spots and London’s landmarks.

The idea was to look for pictures at these places as Gemma passed them. So we translated them into distances, i.e. determine the elapsed distance that would have been run when reaching each of these places.

Tower Bridge, for example, is at 12.5 miles. Big Ben is at 25 miles and so on — for about 10-15 hotspots.

The application monitored the total distance covered and at each of these key numbers hit the Instagram API for the most recent pictures around the location.

Setting up an Instagram application is instantaneous, though I waited a long time for my API key initially — I did apply when the announcement was first made however, so the turnaround may be a lot faster now.

There’s no moderation or application approval process, when you’re up and running you can start performing queries immediately.

The API is RESTful over HTTPS with a number of endpoints to query images, comments, users, locations, tags and so on. The developer docs are fairly comprehensive.

We’re interested in the media endpoint. Note that the following URLs require an access token or client id, which you will be given, omitted here for brevity.

Get the current most popular photos:

https://api.instagram.com/v1/media/popular

Or to get information about a single image with a media id:

https://api.instagram.com/v1/media/72612696

The search method was our main tool. It takes up to five parameters, lat, lng, max_timestamp, min_timestamp and distance.

https://api.instagram.com/v1/media/search?lat=51.54242&lng=-0.059702&distance=1000

Note only latitude and longitude parameters are required and distance is in meters, default at 1km with a maximum of 5km.

So at each of our key distances, the app took the latest latitude and longitude positions and grabbed the latest photos.

In an attempt to only select images of the marathon, this was backed up by inspecting within the result set for images with a caption containing any one of a set of predefined keywords such as ‘marathon’ or ‘runners’. That way we could almost ensure that we wouldn’t pick up any images not concerned with the race — though would find false positives.

Once we had the JSON data it was simply visualised on the map, Instagram host the images for us.

One thing lacking in the data perhaps, is that the location information only offers the latitude and longitude coordinates, no place or address names unless otherwise nominated by the user. For each image then I ran the data through Google’s Geocoding service to get a street or area name, just for display purposes.

On the whole, it worked well. The API is as straightforward as any and realistically, the biggest worry for us is that most people seem to use Instagram to take pictures of food and little else, we thought we’d have pictures of everyone’s breakfast around various parts of London all day.

Doubtingly, I wrote a simple ‘refresh’ button to rerun any query in case anything untoward or particularly boring popped up when I logged in to check, but between the huge crowds and the caption matching, I only had used it twice and both very early on in the day.

Here’s a handful of the pictures:

I went out for a ride and I never went back.