Follow The Emerald Star

Using geolocation to encourage outdoor listening

Image for post
Image for post
The “Emerald Star”

Five years ago, I launched a campaign for Cut Copy which allowed fans to listen to a track off their latest record, “Free Your Mind,” if they visited one of six billboards around the world with a companion web experience in hand. To this day, I do not know how many fans actually engaged in the experience but I always loved the idea of getting people moving in the real world for music. We now live in a post Pokémon Go world and product design will tell us that once user’s understand a UX, they are more likely to engage in it. It’s in that spirit that I’ve developed a new version of this experience for Lord Huron’s Follow The Emerald Star campaign.

Fans are encouraged to visit on their mobile devices. From here, they can share access to their current geo location right from the browser. Our application then figures out which hand picked destination is nearest and encourages the user to make the journey. A visual compass helps the user head in the right direction and informs them of when they have arrived. Once the user arrives within a preset radius of the destination, we unlock a track off the new record “Vide Noir” for them to stream.

The experience is intentionally kept simple due to lack of bandwidth and the importance of safety in real-world situations. I encourage you to fire it up on your mobile device and see which location is nearest you. The band chose obscure nature friendly destinations which act as a backdrop to the listening experience. Let us know if you make the journey! 🌲

This campaign is the perfect example of how a few lines of code can create a seemingly magical experience when it works correctly. Let’s take a look at how it was done.


Image for post
Image for post

The biggest difference between the geolocation Web API five years ago and today is that the feature is only available in secure contexts (HTTPS.) Other than that, it’s mostly the same. 😅 In addition to covering the core functionality, I put a much larger emphasis on detecting errors. You can’t make a promise that your application simply works when so many things can be perceived as an error. This starts by simply detecting if geolocation is available on the device.

return ("geolocation" in  navigator);

If the user has access to geolocation, we’ll want to call the Geolocation.watchPosition() function to, you guessed it, watch the user’s position. I’ll discuss the first function which deals with a successful position reading in a moment but let’s focus on all of these lovely errors first.

watchId = navigator.geolocation.watchPosition(watchPosition, function(error) {
switch(error.code) {
// Permission denied
// Position unavailable
case error.TIMEOUT:
// Position timeout
case error.UNKNOWN_ERROR:
// Unknown error
}, {});

I actually kept track of all of the errors received in our campaign and can share that the PERMISSION_DENIED error was thrown most often. This can occur when the user denies access to their location when prompted. However, it can also occur if the user previously turned off location sharing in their privacy settings. I encouraged our user to check out these settings. POSITION_UNAVAILABLE occurs when the geolocation sensor itself returns an error. I told our users to make sure they weren’t in a bomb shelter and refresh the experience. I did not use the timeout option on watchPosition but TIMEOUT would be thrown if the application was not able to find a location in time. Finally, I did not receive any UNKNOWN_ERROR codes. If an error wasn’t thrown, it means a successful position was found. I then dissect the position and begin to work with the user’s coordinates.

Turf.js is an incredibly well written geospatial analysis library for browsers and it contains several methods we’ll need to power this experience. Let’s start by defining our destinations and user location as points.

var locations = turf.featureCollection([
turf.point([latitude, longitude]),
turf.point([latitude, longitude])
var user = turf.point([latitude, longitude]);

From here, we can easily find the nearest location with Turf’s aptly named nearestPoint function. Once we locate the nearest destination, we’ll want to figure out it’s distance and bearing to our user. Pro tip: use Turf’s bearingToAzimuth function to convert the bearing to a number between 0 and 360. We’ll then be able to inform the user of how close they are and also power the unlock if they’re within a meter radius we specify.

var nearest  = turf.nearestPoint(user, locations);var bearing  = turf.bearingToAzimuth(turf.bearing(user, nearest));var distance = turf.distance(user, nearest, { units: meters });if (distance < 50) {
// Unlock Emerald Star

When our user does make it to their destination, I have chosen to stop listening to their location so there isn’t a chance their GPS might accidentally kick them out. If you’ve ever looked at your current location on a Maps app, you’ll know the returned value can be finicky. Here’s how you stop listening:


I’m simplifying things a bit but the geolocation API and Turf does make things that easy. Once you have this core functionality down, you can spend a bit of time building up the user interface. I’d like to touch on the compass itself a bit.


Image for post
Image for post

If you use the app on an iOS device, you’ll see two independently rotating dials as part of the compass. One shows the user’s current compass heading and another shows the locations bearing to the user. I borrowed this technique from video game interfaces to help direct the user to their destination. It took me a few iterations to realize just how simple this was actually going to be. Don’t be smart! Be smart!

In order to rotate the compass dial, we’ll need to listen to the device’s orientation which returns webkitCompassHeading. This can be easily passed to a CSS transform rotation to rotate the dial. Sadly, Android devices do not currently support this function so you don’t get the groovy interaction on those devices.

window.addEventListener('deviceorientation', function (e) {
"rotate(-" + e.webkitCompassHeading + "deg)"

We can apply the same technique to the Emerald location dial using the bearing variable we defined earlier.

"rotate(" + bearing + "deg)"


In order to secure things a bit, we chose to serve the audio from S3 using pre-signed short-lived streaming URLs. When the user arrives at their destination, we simply request one of these from the server and load it up in a Howler.js sound object which the user can play or pause by clicking the unlocked Emerald Star.

new Howl({
src: S3_URL
}).on("load", function() {
// loading
}).on("loaderror", function() {
// load error

In addition to player functionality, Howler.js provides helpful events we can use to further reinforce the real world experience. Since we’re unsure of the bandwidth at each location, it’s important to let the user know what’s going on when loading the unlocked song and more importantly if something went wrong. You can use Howler’s load and loaderror events to do exactly that. You can’t go wrong with a bit of audio compression as well. If you’re sending your fans to a mountain peak and asking them to download a 20MB file… forget about it.


It’s probably worth addressing the elephant in the room. Location is easily spoofed in digital experiences and user’s could emulate their position to unlock all content. I actually wrote this into my proposal. 🙃 The fact of the matter is, this experience it’s sort of like a video game which requires a high barrier of entry (physical movement) and is only available to some users (near locations.) For those who can’t play, the next logical course of action is to find a workaround and those are readily available.

Building a native application may make cheating a bit harder but even Pokémon Go finds itself constantly the target of exploits. In addition, accessibility is a theme of my work and sending someone a URL vs. getting them to download an app is a no brainer.

I think I would be more worried if fans didn’t try to exploit the campaign. Spoofing location is the new record leaking! You better hope people care and as it turns out, the Lord Huron fans surely did. 😉


Image for post
Image for post
Photo by Pamela Littky

I’m not a big fan of rehashing older concepts but it was quickly obvious Lord Huron was looking for something uniquely crafted for their excellent new upcoming record. The concept is merely the vehicle for the pairing of sound and location that makes this experience special. Thanks to Tim Hrycyshyn and the entire Republic team for helping build this one out in two weeks. Much respect to the LoyalT Management team for entrusting me with their client. I hope they let me work Chromeo next. 🙏🏻 Finally, thanks to Ben and the rest of the band for providing inspiration, feedback, locations, and the tunes!

“Vide Noir” is out April 20th.

Written by

I develop websites for rock 'n' roll bands and get paid in sex and drugs. Previously Silva Artist Management, SoundCloud, and Songkick. Currently: Available

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store