An application that connects to the Spotify Web API to display your top artists, tracks, and genres across different time ranges and generates personalised track recommendations.
Built as a portfolio project to demonstrate OAuth 2.0 implementation, REST API design, and modern React architecture.
⚠️ A Note on Spotify API Deprecations
In November 2024, Spotify silently deprecated several of the most useful endpoints for projects like this one including Audio Features, Audio Analysis, Related Artists, and Recommendations. If you're exploring this project and want to extend it with audio analysis or mood features, the Spotify API is no longer the right tool for that. Some directions worth investigating:
- ReccoBeats : free audio feature extraction API; accepts audio file uploads and returns energy, valence, danceability, tempo etc. Works well if you can source audio files independently.
- Last.fm API : free, no audio features but rich metadata: play counts, tags, similar artists, artist bios. Good for social and discovery features.
- AcousticBrainz : officially discontinued but still queryable; uses MusicBrainz IDs rather than Spotify IDs so requires a lookup step. Local audio analysis :libraries like essentia.js (WebAssembly port of a professional audio analysis library) can run in the browser or Node.js directly on audio files if you have access to them.
The architecture of this project (decoupled React frontend + Express REST API) is intentionally set up to make swapping or adding data sources straightforward.
- Dashboard - top artists and tracks across three time ranges (4 weeks, 6 months, all time)
- Genre insights - top genres derived from listening history
- Track recommendations - Spotify-powered recommendations seeded from your liked tracks (deprecated)
- React 18 with Vite
- React Router v6 - client-side routing with protected routes
- CSS Modules - scoped component styling, no CSS-in-JS dependency
- Custom design system with CSS variables
- Node.js with Express
- express-session - server-side session management
- dotenv - environment variable management
- node-fetch - HTTP requests to the Spotify Web API
- RESTful API design with separated route and middleware layers
├── backend/ # Express REST API
│ ├── server.js # App entry point, middleware config
│ ├── middleware/
│ │ └── auth.js # requireAuth middleware
│ └── routes/
│ ├── auth.js # OAuth flow: /login /callback /logout /status /refresh
│ └── spotify.js # Spotify data: /dashboard /recommendations
│
└── frontend/ # React SPA (Vite)
└── src/
├── App.jsx # Router + auth guard
├── api/
│ └── spotify.js # All fetch calls, auto token refresh logic
├── pages/
│ ├── Home.jsx
│ ├── Dashboard.jsx
│ └── Recommendations.jsx
└── components/
├── Navbar.jsx
├── ArtistList.jsx
├── TrackTable.jsx
└── TimeRangeTabs.jsx
The frontend and backend are fully decoupled. The React app communicates with the Express API exclusively through JSON - no server-side rendering. During development, Vite proxies /auth and /api requests to the backend so the entire session lives on one origin, avoiding cross-origin cookie issues.
User clicks "Connect with Spotify"
│
▼
GET /auth/login ──► Redirects to accounts.spotify.com/authorize
│
▼ (user approves)
GET /auth/callback?code=... ──► Exchanges code for access + refresh tokens
Stores tokens in server-side session
Redirects browser to /dashboard
│
▼
React calls GET /auth/status ──► { authenticated: true }
React renders dashboard
The authorization code never touches the frontend. The client secret never leaves the server.
- Node.js v18+
- A Spotify Developer account and app
git clone https://github.com/KayeJD/statify.gitFill in your .env:
SPOTIFY_CLIENT_ID=your_client_id
SPOTIFY_CLIENT_SECRET=your_client_secret
REDIRECT_URI=http://127.0.0.1:5173/auth/callback
FRONTEND_URL=http://127.0.0.1:5173
CLIENT_URL=http://127.0.0.1:5173
SESSION_SECRET=any-long-random-string
NODE_ENV=development
PORT=3000In your Spotify Developer Dashboard, add the redirect to your created app:
http://127.0.0.1:5173/auth/callback
Spotify requires explicit IPv4/IPv6 loopback addresses -
localhostis not permitted as a redirect URI.
Terminal 1 - Backend:
cd backend
npm install
npm run dev
# Running at http://127.0.0.1:3000Terminal 2 - Frontend:
cd frontend
npm install
npm run dev
# Running at http://127.0.0.1:5173Open http://127.0.0.1:5173 in your browser.
- Access tokens are stored in
httpOnlyserver-side sessions (inaccessible to JavaScript) - CORS is locked to the frontend origin only