Creating playlist covers with the Spotify API

Spotify playlists start with a default cover image of the first four albums in the list. I like this feature, but it’s a shame you can’t customise which albums are used, unless you prioritise that over what you want to listen first. Being a developer, I thought it would be pretty easy to render four albums to a HTML canvas, export as jpeg, and upload that to Spotify.

What I was happy to discover is that Spotify have a great public API that lets you search their whole catalogue, list a user’s playlists, and even upload an image to use as a playlist cover - which would make updating them quick and easy.

So I thought this would be a nice little side project to have some fun with, since I haven’t done any non-work programming since remaking the blog in Astro, or the interactive file mover before that.

I started simple, fetching an API token using the client ID and secret from the Spotify dashboard, a search panel, canvas preview, and a download button. This was originally where I planned to stop, before deciding it wasn’t too much more effort to list the user’s playlists and add an upload button.

An early version An early version

However, to access a user’s playlists I needed a different type of authentication, one that requires passing off to the Spotify website to ask for permission before redirecting back to mine. You’ve probably used something very similar before.

At first I thought this wasn’t going to be possible in a Single-Page App. I’m not paying to host a server somewhere to store my secret key or handle redirects. But as I read deeper into the documentation, it turns out there’s a newer type of auth called PKCE (Proof Key for Code Exchange), which basically allows you to create your own secret key at runtime and handle the whole thing client-side, with all the same permissions a traditional OAuth app could ask for.

How PKCE works How PKCE works

Great! There are a few security features, such as providing a random state string that Spotify returns to you on redirect, which helps to verify that an incoming redirect originally came from your session. I imagine the only thing that prevents your public key from being used on another application is that the redirect URL is whitelisted on Spotify’s back-end, so another site would not be able to finish the authentication process.

Spotify provides a token with a one hour expiry, and a ā€œrefresh tokenā€ that never expires, which allows you to request a new token at any time. I set up a system that will automatically fetch a new token if we receive a 401 Unauthorized error, then retry the previous request, which worked well.

I added tabs for playlists, search, and a third tab that appears when you select a playlist. I also added drag and drop reordering as a separate list, as that seemed much simpler than doing it within the canvas, plus you can show the album name and a delete button on each one.

The finished app The finished app

I used Vite to build the site, which has been a delight to use. Very quick and easy, supporting my go-tos React, TypeScript, and SCSS with no issues. There’s a handy plugin called Vite Plugin CSP Guard that can configure and auto-insert a client-side Content Security Policy easily, that I thought would help make the site a bit more secure as it’s dealing with Spotify user data, and show that I’m not sending data off anywhere else.

connect-src: https://accounts.spotify.com https://api.spotify.com;

There’s also a plugin to easily enable HTTPS on localhost, called Vite Plugin mkcert which was necessary for letting the Spotify auth API redirect to my local Vite dev server.

The upload dialog The upload dialog

I used Bulma CSS framework again, great for side projects. Shout out to the Bulma List extension for making lists really simple to implement.

The Spotify docs were really useful throughout building the site. They provided clear instructions for setting up PKCE auth with JavaScript examples, and their endpoints are all documented well. There’s an SDK you can use, but if you want to roll your own requests like I did, you can just use the TypeScript definitions that the SDK provides, which are nicely standardised with things like a Page<T> type for pagination, and different endpoints share the same types, like search and playlists both return the SimplifiedAlbum type.

Coming to the end of the project, I wanted to put the site up on GitHub Pages with my client ID, so anyone could log in and try it out. But it turns out Spotify puts your app into a limited, invite-only ā€œdevelopment modeā€ and production mode is basically only available to businesses on request, including having at least 250,000 monthly active users 😱. Fair enough, I’m happy I can at least use it personally to spruce up my own playlists.

I have uploaded the site to GitHub Pages anyway, and you can set your own client ID from the Spotify developer dashboard. Try it out here, and thanks for reading!