Exploring the Sound - Getting Started With the Spotify API

Once a year, when the personalized "Wrapped" stories are published, Spotify gives us insight into our music library. If you don't want to wait until December to explore your listening habits, the Spotify API is there for you year-round. This post explains some of the whys and hows of the demo I made to download my Spotify library.

I don't care, take me to the demo!

Authorization flow

The easiest way to authorize a user and get access to their Spotify data is via the implicit grant flow (a.k.a "temporary user authorization").

Implicit grant flow is for clients that are implemented entirely using JavaScript and running in the resource ownerā€™s browser. You do not need any server-side code to use it. Rate limits for requests are improved but there is no refresh token provided

This method is perfect to get started with the Spotify API and suitable for small applications that don't depend on too much computing power. The demo app, written in React.js, implements this flow as following:

  1. App registers a global callback in the window object
  2. On click, a popup is opened to authenticate the user
  3. After the user grants the app permission to access their data, Spotify redirects to the starting page
  4. The resulting URL will contain a hash fragment with the data encoded in a query string
  5. A first effect reads the token (or error) from the URL and stores it in Redux for subsequent requests
  6. A follow up effect fetches the library data from Spotify

Popup vs same-site authentication

Doing popup authentication was a deliberate choice. Alternatively, and as demonstrated in Spotify's official implicit grant example, the user could be forwarded to authenticate in the same window. Popup forms, on the other hand, are a popular choice for 3rd party logins and most users are used to them thanks to Facebook, Twitter and co. Instead of Login with Facebook, it's simply Login with Spotify.

Getting the user library

When a user clicks "download my library" in the demo app, their songs are fetched recursively. This is due to the fact that Spotify returns a maximum of 50 songs per request. As a little bonus, their current favorite songs based on calculated affinity are shown as well.
top.JPG

Update as of March 20, 2021: The demo now also displays a user's recently played tracks! šŸŽ‰šŸŽ‰šŸŽ‰

In between each of these requests, follow-up requests are made to get extra information for each track. The reason for these additional requests is that a lot of interesting data is not provided on the basic track object. Music genres, for example, are not provided.

Getting the track genres

Since a single track doesn't come with any genres, its album sure does, right? Well, technically, when asking for the details of a specific album, Spotify does include a list of genres, but I found these to be empty for all the albums in my library. Thousands of tested albums - not a single genre.

Here are two gists showing what I mean. Just search for "genres"

The second, even less accurate approach to figuring out what genres a song is associated with is via the corresponding artists. Luckily, Spotify assigns most artists at least one music genre! This is why in the demo, after each library request, another request is made to fetch the artists details of a track. The data is stored in Redux along with the "basic" track data, and a selector enriches the existing track data with the genres of its main artist.

Getting the track genres... almost right

Genre data is super exciting. With millions of different sounds, I have no clue how Spotify assigns genres to artists. But thanks to the demo, I know now that Tame Impala's music classifies as "australian psych, neo-psychedelic". Nice.
Capture.JPG

Linking track genres based on their artists works but has some drawbacks. The demo currently assigns track genres based on the first artist of a track. This may not always be accurate. The underlying assumption is simply that the first artist is the main artist of a track and thus has the most influence on a song, but who knows.

A track's personality: Audio features

Another very interesting aspect of a track are its audio features. Spotify assigns each of their over 70 million tracks various properties that describe the song's character. Here's the example from the docs.

{
  "danceability": 0.808,
  "energy": 0.626,
  "key": 7,
  "loudness": -12.733,
  "mode": 1,
  "speechiness": 0.168,
  "acousticness": 0.00187,
  "instrumentalness": 0.159,
  "liveness": 0.376,
  "valence": 0.369,
  "tempo": 123.99,
  "type": "audio_features",
  "id": "4JpKVNYnVcJ8tuMKjAj50A",
  "uri": "spotify:track:4JpKVNYnVcJ8tuMKjAj50A",
  "track_href": "https://api.spotify.com/v1/tracks/4JpKVNYnVcJ8tuMKjAj50A",
  "duration_ms": 535223,
  "time_signature": 4
}

The audio features for each track in a user's library are downloaded as part of the "extra information" downloads mentioned earlier and available in Redux. Unlike the derived genres, they are not mapped to the original track object due to performance reasons. Each time new genres are fetched for a track, a selector (re)computes a derived/enriched track object with the genres. Doing the same for the audio features would further slow down the process. Since everything happens 100% client-side, doing resource intensive mapping may not be the best idea.

The audio features for each track in a user's library can still be downloaded as a separate file.

Download your Spotify library

The demo includes an option to export a user's library as JSON file in different formats.

  1. Light. All tracks but reduced to the max. Only some interesting properties are included. Title, artist[s], album, popularity and derived genres
  2. Full. All tracks as they come from Spotify, enriched with their artist's genre
  3. Flat. Since the full track download cannot easily be used for further processing, the flat option flattens each track into a 2-dimensional object. This export comes in handy when you want to further explore your library and can be read into a pandas.DataFrame
  4. Audio Features. Explained above. Tracks from this export and tracks from the other exports can be linked via the common song id property

The light, flat and audio features exports are suitable for further processing and are tested to work with pandas.read_json. Here's how the light option may look like after downloading.
demo.JPG

Nothing of this is new

If you've searched Google for "organize spotify" before, you've most likely already come across Spotify's own Paul Lamere with his brilliant, open-source Music Library Organizer. Although not nearly as feature-rich as Paul's Swiss Army Knife, this demo provides a guideline in a state-of-the-art setup with React.js, Redux and Typescript - A stack most web developers are familiar with. With this demo, I hope I can give others a guideline on how to talk to Spotify in a slightly more modern way and offer anyone the possibility to easily download their library data.

Source and readme

The whole demo is open source. Here's the code along with a readme that includes some important notes regarding privacy and what happens with your data. If you don't trust the public demo, that's totally fine. Just grab a copy of the source and run your own Spotify app locally.

Originally published in February 2021 on my personal website and blog, eric.film.

17