Making of Audio Habits

Wed Apr 22 2020

Audio Habits is a simple web app that displays your most played songs and artists on Spotify. Source code can be found on GitHub and the live version can be found here.

This project was the first actual web app I built, so it's not perfect and there are a few problems with it, but it works. This project was a great learning experience for me from making the frontend in React to a simple backend in Express. Since its launch in July 2019, there have been 1.2M+ unique users and 2.9M+ sessions. There are still around 15K new users per week. Initially, most traffic was from Spain and Mexico (thanks to this article). Since then most users were gained from traction on Twitter in Brazil and Turkey.

The functionality of the app itself is quite simple. A user logs in, grants access to their Spotify account, and then can immediately see the stats for their top artists and songs from the last 4 weeks, 6 months, and what Spotify calls "years of data." The web app doesn't actually have to calculate any of these stats, they are available right from the Spotify API which makes this app much simpler.

To get started, I just used Create React App as it is simple to set up and saves a lot of time. And for the backend, there are just two endpoints used for Spotify OAuth. For the frontend, I first added a button that would send a request to the backend. From the backend the OAuth call to Spotify is made, only needing the user-top-read scope and from there the backend sends a request back to the frontend with the access token acquired from Spotify in a cookie.

From there the frontend checks if there is an access token in the cookies (should have stored this in local storage), and then sends six requests to Spotify for all the different stats that are displayed. The front end then cleans this data (sets a maximum length for song titles / artists names) and then displays it. Looking back at this code, I displayed this data pretty terribly. I populate all the different "stats" and then sort them by a hardcoded order, but this crude method does work. That is really most of the features of this simple web app. I added some quality of life features like logging out and decided it was done.

Now came what I found as the hardest part of this app, the deployment. I really made it difficult on myself for deploying this app and definitely could've made it much easier on myself. What I decided on was deploying using an EC2 instance (a t2.micro using the free tier, note that the usage has exceeded the free tier on Route 53). I synced my code to the instance and set up a reverse proxy using Nginx. I spent many hours trying to get the configuration correct but got it to work using this in my nginx.conf:

http {
    ...
    server {
        server_name     audiohabits.co  www.audiohabits.co;
        root            /path/to/build/
        location / {
            try_files $uri /index.html;
        };
        location /api {
            proxy_pass http://127.0.0.1:4000;
        }
    }
    ...
}

The frontend was running on port 3000 and the backend on port 4000. By using a reverse proxy both would be accessible from port 80 (port 443 when HTTPS is set up). I managed both of these services using PM2 and have had perfect uptime since then. Next, I used Certbot to enable HTTPS, and the project was done.

Then I launched on ProductHunt. It didn't do great on ProductHunt but is still the most used web app I've made.

This basic web app was a great learning experience for me and taught me a lot about using React, Express, and deploying. There is definitely room to add new features such as sharing the results generated and providing more analytics. I plan on adding these features at a later time, but I am happy with the app I've made.