Come fly the funky skies with Khruangbin

Generating a Spotify playlist for any flight

Image for post
Image for post
Ticket design by Ted Angelilli, background by Josh Withers

This month we launched an interactive website for Khruangbin which allows users to generate a Spotify playlist for any flight. I know what you’re thinking.

What the hell is a Khruangbin?

Khruangbin (pronounced crung-bin) is a Texas trio with a Thai name that means “airplane.” It’s the perfect name for a band whose sound feels like it’s on a never ending multi-cultural instrumental journey around the globe. Their sophomore record, Con Todo el Mundo, is the music equivalent to a perfectly crafted Wes Anderson movie.

Some time ago, Khruangbin began doing a series of Facebook Live DJ sets titled in which they shared influences from a particular city. Check out Flight 421 to Los Angeles. I was approached to develop an application which would expand on this concept. The structure we settled on would allow users to input any flight origin and destination along with some flight preferences to receive a custom Spotify playlist.

Take you seats, fasten your seat belts, and read on to learn how we did it.


Before we go flying, we’ll need to build up a pool of tracks. Luckily for me, Khruangbin was eager to do just that. They provided me with a huge list of Spotify track uris and their associated country. I then wrote a Node script which pulled down each track’s set of audio features from Spotify. These audio features range from something practical like the tempo of a track to something a bit more funky like danceability. In the end, each track had a simplified JSON breakdown similar to the following:

artist: "",
country: "",
duration: 0,
features: {
danceability: 0.0,
energy: 0.0,
loudness: 0.0,
tempo: 0.0
id: "",
image: "",
name: "",
preview: ""


The next step was obtaining the origin and destinations from our users so we could calculate the flight duration and figure out which countries the flight likely crosses.

Companies like Kayak, Google Flights, and Airbnb put a ton of engineering resources and years of research into their user inputs but I needed a quick solution. I found a JSON file of airports compiled by James Brooks from Blue Bay Travel which includes both airport codes and coordinates. After dropping a couple of helipads from the dataset, I combined it with jQuery-Autocomplete to create two simple airport code autocompleting inputs.

Calculating the flight duration begins with calculating the distance between the origin and destination cities. Now that I have the coordinates from each, I simply need to use the Turf distance function to obtain the miles between. I then divided the average commercial airliner speed of 500 mph by the total distance and added a generous half hour for taxi to estimate the flight duration. Adjust to your travel experiences:

var duration = (speed / distance) + taxi

Figuring out which countries a flight crosses wasn’t so straight-forward but luckily mapgod Vladimir Agafonkin had a solution. I used Turf’s along function to obtain a list of coordinates along the flight line from our origin and destination. I then obtained a GeoJSON polygon representation of every country in the world. The coordinate list and polygons were then dropped into the query function of which-polygon and in return I received a list of each country that the coordinates landed in. Add in an Underscore _.uniq for good measure.


Image for post
Image for post
Icon set by by Ted Angelilli. background by Scott Webb

Peanuts or pretzels? Window or aisle? We all have our preferences when it comes to flying. In this project, we wanted to map a couple of simple choices to audio features that would change what type of music made it onto your playlist. Using the audio features we obtained from Spotify earlier, we decided on the following preferences:

  • Choosing an aisle seat might mean you’re more inclined to get up and stretch your legs so we connected this preference to the danceability of a track.
  • Some folks like to drink coffee and get work done. Others like a tea, blanket, and book. Choosing between these two will adjust the energy of your tracks.
  • Everybody knows the closer to the engine you’re sitting, the louder your flight is going to be. However, maybe you like being close to the speaker. You do you.
  • Are you always in a rush or do you go with the flow? Adjust the speed of your flight to receive tracks of a similar tempo.

Now that we have the flight countries and user preferences, we can choose which tracks make it onto the playlist. I decided to come up with a scoring methodology to achieve this.

Each track starts with a score of 0. I then use each choice from the preferences above to sort the list of tracks and score them. For example, if the user wanted tracks with a higher danceability, we would sort tracks from the highest to lowest danceability. I then give the track with the highest danceability 1 point, the lowest 0, and everything else a fraction between. This is repeated for each audio preference, after which we give tracks than are from any of the flight countries an additional 1 point.

Every song in the pool now has a unique score which you can again sort from highest to lowest. The final step is simply grabbing enough tracks from the top of the list which fit the total duration of our flight. Luckily Spotify provided us with a duration in milliseconds for each track. Once you have all the tracks you need, go ahead and give it a shuffle to randomize.

Luggage Tag

Image for post
Image for post

A flight without a dope luggage tag is like a Spotify playlist without custom artwork. I know this, and looking at Khruangbin’s original Airkhruang playlists, they know this. As such, we just had to generate custom artwork for each playlist. This process began with a structured design phase executed by Ted Angelilli which involved the creation of five worldly luggage tags. In order to not drive me crazy, he made sure every type layer was in a similar position.

I then executed a random generator in HTML5 canvas via a four step process:

  1. Add a random background image
  2. Add a random luggage tag image
  3. Add the airport codes and flight duration as text
  4. Add some additional texturing on top

Later on this image will be sent to the server for final saving to Spotify.


We now have our playlist and artwork living temporarily in the user’s browser. That’s about as dangerous as arriving to the airport late with luggage to check. Let’s get everything booked to Spotify immediately.

For this we’ll need to roll some simple Spotify authentication. Since I’m already in a Node environment, this excellent Spotify Web API library does the trick. We just need to remember to request the following permissions: playlist-modify-public, playlist-modify-private, ugc-image-upload. Once our users are logged in, I go directly into each step in the saving process.

First, we create a new playlist on Spotify, giving it a custom title based on the user’s flight. We then add all of our tracks to the new playlist. This might take a few calls depending on how many tracks are in your playlist since Spotify limits the endpoint to 100 tracks at a time. Finally, we rejoice in the fact that Spotify allows custom artwork to be added. Just use the toDataURL function on your luggage tag canvas to get a Base64 representation of the image and send it over to Spotify via your server. Pro tip: remove data:image/jpeg;base64, from the beginning of the Base64 string.

If everything went according to plan, you’ll see a Spotify playlist generated just for you and your flight sitting in your playlists. While it might seem like a small thing, the fact that Spotify’s API returns a permalink url to the newly created playlist cannot be understated. You can use this to immediately populate your experience with share buttons and further increase the viral reach of the campaign.


Naturally, fans of the band absolutely loved this gesture but super-serving fans is not the sole goal of a campaign like this. The real reason for building a concept like this is the accessibility of the idea. You don’t need to be a fan of Khruangbin to receive value from this offering and it isn’t necessarily a music led concept. So while the project did get a nice writeup in Billboard, it was also covered on Conde Nast Traveler and Lonely Planet. This allows us to bring non fans into the experience and convert them into Khruangbin listeners.

However, a solid concept is only as good as it’s user experience. We decided to keep things as simple as possible so users could get a lot of value from a little input. I wouldn’t be surprised if we continue to build upon this foundation.


Image for post
Image for post
Khruangbin, Photo by Mary Kang

I am so grateful that Robby Morris from Secretly Group and Laura Lee and her bandmates entrusted me with this beautifully conceived concept. I must also thank Ted Angelilli for providing the pixels so I could focus on the code. Having a designer on a project is a luxury I could get use to. Finally, thanks to Spotify for developing an API that gets more interesting with each project.

To be honest, I didn’t really know much about Khruangbin going into this project and wasn’t expecting much response when sharing it with my friends. Well, I was . These guys obviously have a cult following I wasn’t aware of and I’ll definitely be booking a flight to their Asheville show so I can catch them with my nephew. I know what I’ll be listening to on the flight.

Stream Con Todo el Mundo today on Spotify.

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