Multi-platform social voting: how we did it

For the Earth Journalism Awards, we wanted to create as much opportunity as possible for people to vote for the 15 winning climate change pieces, and spread the word about the contest.

Inspired by Mashable's Open Web Awards and other social-voting efforts, we knew we'd take advantage of the viral potential of Twitter and Facebook for users to announce who they voted for, but we wanted to take it a step further, and allow a tweet or a fan action on Facebook to actually count as a vote. To our knowledge, this hasn't been done before, but we hope to see it replicated and improved upon for other worthy causes.

So here, in a nutshell, is how it worked. We welcome feedback and questions, to make the system better for our next awards!

Voting on the Earth Journalism web site, http://awards.earthjournalism.org

Voting via the web site is of course relatively straightforward. We used the great VotingAPI module for Drupal developed by drupal veteran eaton (also the father of the ubiquitous Token module).

We previously used VotingAPI to count the votes for national, regional and international juries - the smaller groups of voters that gave us our finalists, but who were voting remotely, as a virtual jury. Last  year we contributed to allow the Fivestar module to use the multicriteria voting features of VotingApi and it was very easy to use it again this year to differentiate between the different phases of the competition which involved more than 100 jurors reading more than 400 stories all around the planet.

Voting on Twitter

To count as a vote, a tweet had to include three things: the hashtags #ejavote and #cop15, and the bit.ly shortened URL that links to the nominated story. Users were prompted to log in to their twitter account, and messages were pre-created for them, which they could edit (minus the hashtags and link).

To count these votes, we use the twitter search API. Every 10 minutes, we run 15 twitter searches to return the list of tweets that contain the right keywords. This list contains the identifier of the twitter user, so while we record every instance, we only count the last vote for each twitter user's account.

However, for voters who start their tweet from the EJA web site, we want them to see that their vote was counted instantly, not 10 minutes later! So we track when people are on our site and use the twitter voting button, and we count the vote immediately. Later we reconcile the votes from the Twitter search API with the votes in the buffer, and we add the votes that did not happen on the EJA site.

Voting on Facebook

On Facebook we set up Pages for each nominated story, and voters could cast a vote simply by becoming a fan of any given page. This turned out to be very successful:

  • Around 300 visitors casted their vote on facebook by becoming a fan on the EJA website.
  • More than 2300 users became fan of the stories directly from Facebook.

Automatically tabulating the number of fans in real-time is a little harder than in Twitter - there's no simple function in the Facebook API to retrieve the number of fans of a page. So we gently work around this by downloading the Facebook page badges, which displays the number of fans. We then use an OCR (Optical Character Recognition) software, tesseract (developed as proprietary software by HP  from 1985 to 1995 and now open source) to analyse the image and read the numbers back from the image. We then store this numbers in our database and voila: Facebook votes are counted.

Making Facebook votes that start from the EJA site instantaneously recognized was also trickier than in Twitter. We ask people who vote on our site with Facebook to log in via Facebook Connect. When they do, we have access to their Facebook identifier. Then we display the Fan box and we start to poll every 10 seconds and check whether the person who is logged in via Facebook Connect is fan of the story he or she is looking at, because the Facebook API does have a isFan() function, which tells if a given Facebook user is a fan of a given Facebook Page. We also check this when users close the page or navigate away, through the unload() function. So without knowing exactly when the visitors clicks on the Become a Fan button, and without waiting for the next Facebook badge scan, we add +1 to our Facebook vote tally.

Compiling all the votes in real time

All this voting activity...it makes you want to go to the site and watch the gentle stream or raging river of votes coming in from around the planet. All this care and concern for earth is inspiring! So we want to show it on the EJA site, so visitors can watch the total votes tick up.

All the hard work was mainly done with collecting the votes. With Drupal's Views 2 module and a bit of custom XMLHttpRequest magic made easy by Drupal, we look every second if a new vote was casted on any of our 15 winning story and if so we display the vote immediately on the page! That's it, you're seeing the world's aspiration for better journalism on such important issues as climate change.

Putting the EJA voters on the map

As you have seen since December 7th and the official start of COP15, we're now tagging voters to their location to show the global interest in COP15, and of course the importance of reporting around climate change.

We use Drupal's Geo IP API module (using the GeoLite Country database) to map our voters' IP addresses with a city and country. That's not the most precise way to geolocate, but if voters know and care about this then surely they're using the twitter geotagging features that were recently released (http://blog.twitter.com/2009/11/think-globally-tweet-locally.html). And of course, we're tracking that: If you vote through twitter, then it's your geotagging data that will be used. 

Certainly there are cases when we wouldn't be able to map votes:

  • If voters tweeted their vote independently, without logging into twitter via the EJA web site, and don't use geotagging.
  • If a voter became a fan on Facebook, without logging into Facebook Connect via the EJA website.

To render  the map we use the Views 2 module coupled with the drupal module version of openlayers and the OSM tile sets.

Dare I say it? What about Cheating?

Cheating? On such an important issue as climate change? For an award where accuracy and integrity in journalism are celebrated?

We certainly hope our voters won't cheat. But of course, we're watching, and prepared to adjust votes or turn to public humiliation to out the cheaters...should that be necessary. 

  • We collect IPs and we can also tell computers from one another if they're behind a NAT router (not if they're using double NAT though). Yes, we hacked core to do that...
  • When too many votes come from the same IP, red buttons start flashing on our cockpit, and we disengage the auto-pilot.
  • We look at it closely. See if it seems genuine or not. We'll even interact with the voters if needed.

This might seem like a good deal of work, but in fact the system is pretty solid as it is and it's quite a lot of work to cheat. So yes, cheaters could now use double-NAT, distributed bots to post with random dictionary names from different IPs, and add a touch of stochastic noise to fool our human detection processes. But...would they? We're pretty sure we'd find them anyhow.

It's an Open Vote, it's Open Source

When you're developing with open source, you're always standing on the shoulders of giants:

Kudos to dries, eaton, merlinofchaos, fgm, ori, the developmentseed team, Drupal community and to the MySQL, Apache, Debian developer communities.

Leave your comments to tell us how you would have done it, and whether you think some of this efforts could be contributed back to the open source and particularly the drupal community (Social Voting feature? Anyone?)! We also want to hear about your social voting platform projects! If you think that this post has too much English and not enough PHP code, tell us and we'll post some snippets.

Thomas Seropian - Earth Journalism Awards Lead Developer
Jun Julien Matsushita - Earth Journalism Awards Technical Director

You can leave a comment by signing up or logging in.