MyTop50 Spotify

Full stack app built with the Spotify Web API that displays a user's 50 most played artists and tracks on Spotify over different periods of time and enables adding these charts to their library as a playlist. Used by over 1,000+ Spotify users in 70 countries.

Built with:

Styled Components
Spotify Web API


  • Mobile-first web app built with Next.js, Express.js, and Spotify Web API
  • Over 1000 users and 20k+ page views from over 70 countries
  • I first launched a rough version of in early 2019 and rebuilt it with a modern JS stack in early 2020


Music is a huge part of my life, and after seeing the Spotify Wrapped yearly listening recap, I wanted to go deeper into my most played music over the history of my Spotify listening, but there was no way to view this data. Scratching my own itch, I made use of the Spotify Web API to build


The project began with a rough UI mockup in Sketch to capture the design intent and the overall app concept. I knew that since most users would be viewing the site on a mobile screen, I needed to make mobile-first design a priority from the beginning.

I'm a big fan of Spotify's design system and wanted to maintain consistency with their UI so that MyTop50 felt like a familiar extension of the native Spotify app. This informed the layout and choice of colors, with white text on a dark background (dark mode) providing a beautiful and utilitarian contrast. Spotify's signature green was used for call-to-action buttons and to show the active filter buttons. For typeface, I chose IBM Plex Sans, a personal favorite that I find to be crisp and balanced, similar to Proxima Nova used in the Spotify UI but with a bit of it own sharper character.


I chose to build the site using Next.js. This provided me with a production-ready React frontend and enabled adding a custom Express server to handle user authenitcation with the Spotify Web API.

This app uses Spotify's Authorization Code Flow, which follows the sequence below:

  1. The user is prompted to login and authorize access to the app on a page controlled by Spotify.
  2. If they are successfully authenticated, the user is then redirected back to MyTop50 and an access token and refresh token are provided in the response.
  3. The refresh token is stored in the user's local cookies and can be sent in future requests to obtain a new access token which can then be used to query user data.

On the frontend, I use the React Context API along with the useContext() hook to provide global state. When the page is first loaded (mounted):

  1. The useContext() hook is passed the refresh token from Next's getInitialProps
  2. Then the context provider component makes several async calls in parallel with Promise.all(), passing the refresh token to the Express server to get the user's profile, their listening history, their top tracks and top artists (each over 3 different time intervals).
  3. Each of these calls are routed to the Express server which first POSTs the refresh token to the Spotify API endpoint in exchange for the access token and then uses the access token to perform a GET request for the user's profile and listening data.

Once the listening data is loaded into the context provider component, it is propagated to the visual components which conditionally render the listening data depending on the user input. The MyTop50 UI allows the user to select the time interval and (depending on screen size) the type of listening data (top artists or top tracks).


I made use of styled-components throughout the project to keep the JS, CSS, and HTML for each component organized together.

Using the useDarkMode hook along with styled-components ThemeProvider made it easy to give the app a dark mode toggling functionality. I defined all styles that would be toggled in a central JS file and then referenced these values in each styled-component. Brian Lovin wrote a great tutorial on this approach here.

I also made frequent use of CSS grid and flexbox for UI layout as their alignment properties make building a responsive design a breeze.


I deployed the app using Heroku on a hobby dyno plan to provide users with a fast warm start rather than a slow cold start on their free plan. Heroku makes this super simple and after setting up the Config Variables and configuring the DNS, Heroku automatically manages the SSL certification.