How I built a miniature, year-round available version of Spotify Wrapped
TL;DR
First and foremost, don’t make too much of the headline. I might have clickbaited a little bit here. My version of Spotify Wrapped uses the Spotify API to gather the user’s listening history and presents it in a beautiful & eye-catching way, similar to the original Wrapped. It also allows the user to play all his songs instantly.
So it’s not exactly a clone of Spotify Wrapped. There are no fancy animations, transitions, and auto-generated playlists. I won’t be responsible for these Instagram stories that nobody wants to see (we get it, you like Billie Eilish).
In this article, I will give a step-by-step explanation of how I built Statify. If you aren’t interested in reading the whole thing, check out the outcome on the website right now.
What is Spotify Wrapped?
A couple of years ago, Spotify introduced a new feature: Spotify Wrapped. Every year around Christmas time, users get a summary of their listening trends of the past year:
- Which artist did they stream the most?
- What was their favorite song?
- Which genres did they like?
Spotify Wrapped provides the answer to all these questions. However, this feature is only available in December. It only allows users to see their data of the past year and generally lacks some depth.
But what if the users want to dig deeper? If they want to look at their favorites over the past month? Wouldn’t they be interested in their all time favorites as well?
That’s why I created Statify, a website that provides Spotify users with a more detailed summary of their listening statistics. It also allows the user to play their favorite songs right on the website.
✍ ️ How did I design the tool?
About the design
Spotify itself is known for its beautifully crafted designs. Their UI and famous dark themes are a big reason why users choose them over their competitors. Since my project is using Spotify data and couldn’t exist without it, I decided to make my site look similar to theirs:
- Bright text on dark backgrounds
- Green as a complementary color.
- Similar menus and site structure
I also had to think about the structure. Since users need to log in before they can actually access their data, I decided to split the site into two parts:
- Landing page: to describe the tool and include the login button (might be a little overkill, but I wanted to learn some CSS here 😊)
- Analytics page: to include the actual content of the site
Although it probably isn’t the wisest thing to do, I put my design next to Spotify’s to point out the similarities for you. My design does kind of look like an amateur version of Spotify, nevertheless, I think it’s decent. Have a look below.
⌨️ How did I implement the design?
For the implementation of the design, I decided to use Bootstrap Studio. In theory, BS Studio is a drag-and-drop tool, but it also allows you to write code, which I prefer. It is very easy to use and great for responsive sites. This was important since the desktop and mobile versions look different on my project (as you would expect).
💻 Desktop version:
For the desktop version, I split the site into two vertical parts. The main menu is included in a sidebar on the left (hopefully I can add some points and functions in the future to fill the void) and the site’s content is on the right.
I am sure you’ve heard about Flexbox before. It’s been out for multiple years now and has really transformed the web. If you haven’t heard about it, go check it out!
One example of how to use it are the image boxes on both the landing page and on the analytics page (see figure below). Flexbox automatically scales them to the same size.
📱 Mobile version:
What’s the biggest issue when it comes to mobile design? Lack of space! There simply wasn’t enough space for the sidebar & list menu, that’s why I added a hamburger menu to solve that issue.
Other than that, the structure is pretty much the same as on Desktop. The top artists & tracks are presented in an image box while the rest of the data is gathered in a table.
🎵 Music bar:
Users are able to instantly play their songs on the website. I also wanted to implement some basic control functions. The music bar seen in the image below seemed like a perfect solution. The design is smooth, minimalistic and the overlay makes it stick out. I didn’t write all the CSS myself, but found a snippet on Codepen and adapted it a little bit.
I always struggle to finish designs. They just seem to never be finished, there is always something to add or improve. However, I decided not to spend to much effort on details here and continue with the development.
💻 How did I write the code?
This is where the fun starts! After I’d successfully scribbled some mockups and turned them into static HTML files, it was time to fill the content with life. Although I was tempted to use some fancy new JS frameworks, I decided to keep it simple and just use jQuery. Let’s get into it.
#1 Setting up a Spotify application: 🎬
In order to use Spotify’s API, developers need to register their applications on the platform first. I had to do two things here:
- Copy the Client ID. This is the unique identifier of applications and will be needed for authentication later.
- Set up Redirect URIs. This URI is basically the location that the client will get redirected to after the authorization is successful.
If you want to learn more about it, click here.
#2 Understanding the Authorization: 🔑
Before fetching any data, I had to get the users approval to access their data. The authorization was definitely one of the trickiest things to understand. Spotify provides three different methods of authorization, each one with different pros and cons. You can find a detailed explanation here.
I chose to use the Implicit Grant method, which in my opinion is also the simplest one. The graphic below should answer most questions about it.
#3 Implementing the Authorization: 💾
The implementation wasn’t as hard I thought initially. I took the following approach:
- To start the authorization, users have to click on the login button. Once they clicked the button, they’re getting redirected to the authorization endpoint. I needed to include the Client ID and permission scopes here.
const authEndpoint = 'https://accounts.spotify.com/authorize';
const clientId = '... secret ...';
const scopes = [ 'user-top-read', 'user-follow-read', 'user-read-recently-played', 'streaming' ];
const redirectUri = 'https://burli.biz/statify/analytics';window.location = `${authEndpoint}?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scopes.join('%20')}&response_type=token&show_dialog=true`;
2. The users are now on Spotify’s site while I am waiting for them to approve.
3. After the user has logged in, Spotify adds the access token to the end of the redirect url. I needed to extract the token from the URL to store it for later.
/* Redirect URL:
https://burli.biz/statify/analytics/#access_token=...&token_type=...
*/
const hash = window.location.hash
.substring(1)
.split('&')
.reduce(function(initial, item) {
if (item) {
var parts = item.split('=');
initial[parts[0]]=decodeURIComponent(parts[1]);
}
return initial;
}, {});
window.location.hash = '';
_token = hash.access_token; // store token in variable
4. This last point isn’t really part of the authorization flow. It’s more like a cheap trick to fix a bug for me.
In theory, users access Statify on the landing page, where they are asked to go through the flow to get to the analytics page. Unfortunately, users could still type the path to the analytics-page into the URL and skip the landing page.
Here lies the problem. I had to make sure that users could only access the analytics page after giving permission first. By checking if the token has been set I decide weather the user can continue browing the analytics page or not.
if (! _token) {
window.location = url_landing; // redirect to landing page
} else {
// user logged in, fetch data etc. ...
}
#4 Fetching data using Spotify Web API: 📡
Once the authorization was done, it was time to fetch some data. The main function of the site is to display the user’s top tracks & artists. Depending on the tab the user is on, the site displays their favorite artists or tracks. Spotify allows us to access the user’s data via GET request
As a user’s behavior is likely to shift over time, I also wanted to set a certaintime_range
to access the user’s data over the last week for example. Unfortunately, data is only available over three pre-chosen time spans: one month, six months and all time.
Spotify Web API returns all response data as a JSON object. After fetching the data I extracted the key tags and stored it in arrays to make it re-usable.
Once the requests were finished, I had to load that data into the DOM. For each time range, the top 50 tracks and artists are available. For presentation, I split the content into two parts:
- Highlight section (only the most liked artists/tracks)
- List section, displayed in a table (all artists/tracks)
Luckily, I didn’t have to fetch any other data. All necessary tags like album and cover image were included in the response of the GET-request. After implementing some listeners, I was able to show the right data at the right time.
#5 Adding playback using Spotify Web Playback SDK: 🎛️
Now that all data was on the site and everything looked nice, it was time to add the playback. As I mentioned ealier, users should be able to play their songs right on the website. For this, Spotify offers the Spotify Web Playback SDK. The Web Playback SDK allows you to create a new player in Spotify Connect and play any audio track from Spotify in the browser.
In order to use it, I had to install and initialize the SDK. You can find a great tutorial on how to do that here. You can also just look at the code below:
Since I feel like it’s a lot of code at one time, I will point out a few important points below:
const player = new Spotify.Player() …
I needed to initialize a virtual device that plays the audio, Spotify needs a target device.player.addListener('ready') …
When I call the API to play a song, it’s mandatory to include the device id in the request. Spotify wouldn’t know where to play the song otherwise:device_id_player = device_id;
player.addListener('player_state_changed') …
This event is emitted when the state of the local playback has changed. Whenever the music is paused or played again, the listener registers it and saves the current position of the song in a variable:current_position_ms = state.position;
Once everything was set up, it was time to play some songs. In order to do that, all I needed to make was a PUT-request to Spotify’s API. The parameter uri
is from the track the user wants to play. I received the URI earlier as a result of the GET-request. The implementation of the pause function for the music controls worked similiarly.
Perfect, now I only had to add a few click listener for the highlight- & table sections and I was done.
🏁 Last remarks
This project was really fun to build. I (re)learned a lot of things about Flexbox, authorization flows, and building responsive sites. Going through all these stages, from the design to the final code, was very interesting and instructive.
I hope you enjoyed reading this post. You can try out Statify on the website and on Product Hunt.
#RIPMAMBA 🙏🏽