To integrate the Spotify API with Lovable, create a Spotify Developer App to get your client ID and secret, implement OAuth2 PKCE flow for user authorization, and proxy all Spotify API calls through Edge Functions. Edge Functions handle the token exchange and keep your client secret server-side. You can then fetch playlists, top tracks, and artist data, or control playback via the Spotify Web Playback SDK in your React frontend.
Add music data and playback features to your Lovable app with Spotify API
Spotify's Web API enables a wide range of music-powered features: displaying a user's top tracks and artists, building custom playlist viewers, showing recently played history, fetching music recommendations based on seed tracks, or controlling Spotify playback from your app's interface. These features are what make apps like music taste matchers, workout playlist generators, collaborative DJ tools, and artist fan pages possible.
Spotify's API uses OAuth2 with the PKCE (Proof Key for Code Exchange) flow for user-authorized access. PKCE is the modern, secure OAuth2 variant designed for apps that cannot safely store a client secret on the client side (which includes both mobile apps and browser-based apps). The flow works as follows: your Lovable frontend generates a code verifier and code challenge, redirects the user to Spotify's authorization page, Spotify redirects back to your app with an authorization code, and your Edge Function exchanges that code (plus the code verifier) for access and refresh tokens.
The key security consideration is that your Spotify client secret must stay in Edge Functions via Cloud → Secrets — not in your React code. While PKCE technically allows the token exchange to happen without a client secret (that is its security benefit), storing the secret server-side adds an additional layer of protection and is the pattern Spotify recommends for production apps.
Spotify's API has rate limits: approximately 1 request per second for most endpoints, with specific endpoints having stricter limits. For apps with many concurrent users, implement caching of non-personalized data (like artist information, track details) in Supabase to reduce API calls.
Integration method
Spotify API requires OAuth2 PKCE flow for user-authorized access. The Lovable frontend initiates the PKCE flow and redirects the user to Spotify's authorization page. An Edge Function handles the token exchange callback, storing the access and refresh tokens. Subsequent API calls are proxied through Edge Functions with the client secret stored in Cloud → Secrets via Deno.env.get().
Prerequisites
- A Lovable project deployed to a live URL (Edge Functions and OAuth callbacks require a deployed app, not just the preview)
- A Spotify Developer account at developer.spotify.com (free — uses your regular Spotify account)
- A Spotify App created in the Spotify Developer Dashboard with your Lovable app's deployed URL as a redirect URI
- Understanding that Spotify's Web API requires users to log in with their own Spotify account (you cannot use a service account to access others' data)
- For playback control features: users must have Spotify Premium — the Web Playback SDK and playback API only work for Premium subscribers
Step-by-step guide
Create a Spotify Developer App and configure redirect URIs
Create a Spotify Developer App and configure redirect URIs
Before writing any code in Lovable, you need a Spotify App registered in the Spotify Developer Dashboard. The Spotify App defines your client ID, client secret, allowed redirect URIs, and the API scopes your app can request. Go to developer.spotify.com and log in with your Spotify account. Click 'Create app'. Fill in: - App name: your Lovable app's name (shown to users during authorization) - App description: a brief description of what your app does - Redirect URIs: this is critical. Add your Lovable app's deployed URL + /spotify-callback (e.g., https://myapp.lovable.app/spotify-callback). Also add https://localhost:3000/spotify-callback for local development. The redirect URI must match exactly what your app sends in the OAuth request — any mismatch results in an error. - APIs used: check 'Web API' (and 'Web Playback SDK' if you want in-browser playback) Click Save. On the app's settings page, find and copy the Client ID. Click 'View client secret' and copy that too. Think through the OAuth scopes your app will need. Common scopes: user-top-read (top tracks/artists), user-read-recently-played, playlist-read-private, playlist-modify-public, user-library-read, user-read-playback-state, user-modify-playback-state (for playback control). Only request scopes your app actually uses — users see a list of requested permissions during authorization.
Pro tip: In development mode, your Spotify App is limited to 25 users unless you apply for extended quota access. Add your own account and collaborators as 'Users' in the Spotify Developer Dashboard → your app → User Management for testing.
Expected result: A Spotify Developer App exists with your Lovable app's redirect URI configured. You have the Client ID and Client Secret copied and ready to add to Lovable Secrets.
Add Spotify credentials to Lovable Cloud Secrets
Add Spotify credentials to Lovable Cloud Secrets
Store your Spotify credentials in Lovable's Cloud Secrets panel. The client secret is sensitive — it is used to verify that token exchange requests come from your app, not from an impersonator. In Lovable, click '+' → Cloud panel → Secrets tab. Add these secrets: SPOTIFY_CLIENT_ID: your Spotify App's client ID (a 32-character hex string) SPOTIFY_CLIENT_SECRET: your Spotify App's client secret (also a 32-character hex string). This should always stay server-side in your Edge Function. SPOTIFY_REDIRECT_URI: your deployed app's callback URL (e.g., https://myapp.lovable.app/spotify-callback). This must match exactly one of the URIs registered in your Spotify App. With these secrets set, your Edge Function can handle the OAuth token exchange securely.
Pro tip: The client ID is technically public-safe (it appears in the OAuth URL your frontend generates), but storing it as a secret alongside the client secret keeps all Spotify configuration in one place and makes environment switching cleaner.
Expected result: SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, and SPOTIFY_REDIRECT_URI appear in Cloud → Secrets with masked values.
Implement the OAuth2 PKCE flow with a callback Edge Function
Implement the OAuth2 PKCE flow with a callback Edge Function
The Spotify OAuth2 PKCE flow has two parts: the frontend generates the PKCE code challenge and redirects the user to Spotify, and the Edge Function handles the callback by exchanging the authorization code for tokens. For the frontend: generate a cryptographically random code verifier (43-128 characters), compute its SHA-256 hash, base64url-encode the hash to create the code challenge, store the code verifier in sessionStorage (not localStorage — it should only last the session), and redirect the user to Spotify's authorization endpoint with your client ID, redirect URI, scopes, code challenge, and code_challenge_method=S256. For the Edge Function callback: receive the authorization code from Spotify's redirect, retrieve the code verifier from the request (your frontend should include it in the request to the callback Edge Function), POST to Spotify's token endpoint with the code, code verifier, client ID, client secret, and redirect URI, and store the returned access token and refresh token in Supabase for the current user. The code below shows the Edge Function callback handler. The React component that initiates the flow (PKCE code generation and Spotify redirect) is generated by Lovable's chat interface.
Create the Spotify OAuth2 PKCE flow for my app. Create an Edge Function at supabase/functions/spotify-callback/index.ts that receives the authorization code and code_verifier, exchanges them for tokens using SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, and SPOTIFY_REDIRECT_URI from secrets, stores the tokens in a spotify_tokens table in Supabase (create this table with user_id, access_token, refresh_token, expires_at), and redirects to /dashboard. Also create the React component that generates the PKCE code challenge and initiates the Spotify authorization redirect.
Paste this in Lovable chat
1import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'2import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'34const corsHeaders = {5 'Access-Control-Allow-Origin': '*',6 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',7}89serve(async (req) => {10 if (req.method === 'OPTIONS') {11 return new Response('ok', { headers: corsHeaders })12 }1314 try {15 const { code, codeVerifier, userId } = await req.json()1617 const clientId = Deno.env.get('SPOTIFY_CLIENT_ID')!18 const clientSecret = Deno.env.get('SPOTIFY_CLIENT_SECRET')!19 const redirectUri = Deno.env.get('SPOTIFY_REDIRECT_URI')!2021 // Exchange authorization code for tokens22 const tokenResponse = await fetch('https://accounts.spotify.com/api/token', {23 method: 'POST',24 headers: {25 'Content-Type': 'application/x-www-form-urlencoded',26 Authorization: 'Basic ' + btoa(`${clientId}:${clientSecret}`),27 },28 body: new URLSearchParams({29 grant_type: 'authorization_code',30 code,31 redirect_uri: redirectUri,32 code_verifier: codeVerifier,33 }),34 })3536 const tokenData = await tokenResponse.json()37 if (!tokenResponse.ok) {38 throw new Error(`Spotify token exchange failed: ${tokenData.error}: ${tokenData.error_description}`)39 }4041 // Store tokens in Supabase42 const supabase = createClient(43 Deno.env.get('SUPABASE_URL')!,44 Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!45 )4647 const expiresAt = new Date(Date.now() + tokenData.expires_in * 1000).toISOString()4849 await supabase.from('spotify_tokens').upsert({50 user_id: userId,51 access_token: tokenData.access_token,52 refresh_token: tokenData.refresh_token,53 expires_at: expiresAt,54 }, { onConflict: 'user_id' })5556 return new Response(57 JSON.stringify({ success: true }),58 { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }59 )60 } catch (error) {61 return new Response(62 JSON.stringify({ error: error.message }),63 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }64 )65 }66})Pro tip: Spotify access tokens expire after 1 hour. Build a token refresh Edge Function that uses the stored refresh_token to get a new access_token before the expiry. The refresh endpoint is POST to https://accounts.spotify.com/api/token with grant_type=refresh_token.
Expected result: The OAuth2 PKCE flow works end-to-end: clicking 'Connect Spotify' redirects to Spotify, the user approves permissions, Spotify redirects back to your app, the callback Edge Function exchanges the code for tokens, and tokens are stored in Supabase.
Create Spotify API proxy Edge Functions for music data
Create Spotify API proxy Edge Functions for music data
With tokens stored, create Edge Functions that retrieve the user's stored access token from Supabase and proxy Spotify API calls. Each music feature (top tracks, playlists, recommendations) can use a shared helper that fetches the token, handles expiry-triggered refresh, and makes the Spotify API call. Spotify API endpoints return rich data objects. For top tracks, the response includes track name, artists array, album name, album art URLs at multiple sizes, duration, preview_url (30-second clip), and external_urls for linking to Spotify. Your Edge Functions should normalize this data to the shape your React components need rather than passing the raw Spotify response through. For rate limit handling: Spotify returns 429 Too Many Requests when limits are exceeded, with a Retry-After header indicating how many seconds to wait. For production apps with many users, implement per-user caching — store recently fetched top tracks in Supabase with a timestamp and only re-fetch from Spotify if the cached data is older than 24 hours.
Create an Edge Function called spotify-top-tracks that fetches the current user's top 20 tracks from Spotify. It should look up the user's access token from the spotify_tokens table by user_id, check if it is expired and refresh it if needed using the refresh_token, then call GET https://api.spotify.com/v1/me/top/tracks?limit=20&time_range=medium_term. Return normalized track objects with id, name, artistNames, albumName, albumArt, previewUrl, and spotifyUrl. Create a 'My Top Tracks' page in React that displays this data after the user has connected Spotify.
Paste this in Lovable chat
Pro tip: The Spotify recommendations endpoint (/v1/recommendations) requires either seed_tracks, seed_artists, or seed_genres. Passing 2-3 of the user's top tracks as seed_tracks produces highly relevant recommendations without requiring the user to make any manual selections.
Expected result: The top tracks page displays the user's real Spotify top tracks with album art, track names, and artists. Preview URLs enable 30-second audio playback in the browser without requiring the Web Playback SDK.
Common use cases
Build a music taste analyzer showing users their top artists and tracks
Let users connect their Spotify account and see a visualization of their top artists, top tracks, and favorite genres over different time ranges (short, medium, and long term). The Edge Function fetches data from Spotify's /me/top/artists and /me/top/tracks endpoints after OAuth authorization, and the React component renders it as an engaging stats dashboard.
Create the full Spotify OAuth2 PKCE flow for my Lovable app. The user clicks 'Connect Spotify', gets redirected to Spotify authorization, and after approving comes back to my app. Create an Edge Function at /functions/v1/spotify-callback to handle the token exchange using SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET from secrets. Store the access and refresh tokens in Supabase. Then create a 'My Music Taste' page that fetches the user's top 10 artists and top 10 tracks from the Spotify API and displays them in a styled grid.
Copy this prompt to try it in Lovable
Create a playlist viewer with track previews
Build a page that displays a user's Spotify playlists with track listings, album art, and 30-second preview clips. The Edge Function fetches the user's playlists and track details from Spotify, and the React component uses HTML5 audio to play the 30-second preview URLs that Spotify includes in track objects (no SDK required for previews).
Create a playlist viewer page in my Lovable app. After the user connects Spotify with OAuth, fetch their playlists using the Spotify API via an Edge Function. Display each playlist with cover art and track count. When a playlist is clicked, fetch its tracks and display them with album art, track name, artist, and duration. Add a play button for each track that plays the 30-second preview_url using an HTML5 audio element.
Copy this prompt to try it in Lovable
Generate music recommendations based on seed tracks
Allow users to pick a few favorite tracks and receive Spotify-powered music recommendations tailored to their seeds. The Edge Function calls Spotify's recommendations endpoint with seed track IDs, target energy and danceability parameters, and returns a list of suggested tracks the user may not know but would likely enjoy.
Create an Edge Function called spotify-recommendations that accepts { seedTrackIds, targetEnergy, targetDanceability } and calls the Spotify recommendations API using a stored access token. Return 20 recommended tracks with name, artist, album art, and preview URL. Create a recommendation UI where users can adjust energy and danceability sliders and see recommendations update. Require Spotify connection (OAuth PKCE flow) before showing this page.
Copy this prompt to try it in Lovable
Troubleshooting
Spotify OAuth redirect fails with 'INVALID_CLIENT: Invalid redirect URI'
Cause: The redirect URI in the OAuth request does not exactly match one of the URIs registered in your Spotify Developer App. Even a trailing slash difference or HTTP vs HTTPS mismatch causes this error.
Solution: In your Spotify Developer App settings (developer.spotify.com → your app → Edit Settings → Redirect URIs), verify the exact URI stored as SPOTIFY_REDIRECT_URI in your secrets matches one of the registered URIs. The match is case-sensitive and must be character-perfect. If your app is deployed at https://myapp.lovable.app, the redirect URI must be exactly https://myapp.lovable.app/spotify-callback — not http://, not with a trailing slash unless registered that way.
Token exchange Edge Function returns 'invalid_grant' error
Cause: The authorization code has already been used (codes are single-use), or the code_verifier does not match the code_challenge that was used to initiate the authorization flow.
Solution: Ensure the code_verifier stored in sessionStorage is passed correctly to the Edge Function callback. Common issues: the code verifier is cleared from sessionStorage before it is read (e.g., by a page refresh during the OAuth flow), or the PKCE code generation uses a different algorithm than expected. Verify the code_challenge is created as base64url(sha256(code_verifier)) exactly. Also note that authorization codes expire quickly (around 10 minutes) — if the user takes too long on the Spotify consent screen, restart the flow.
Spotify API calls return 401 Unauthorized even with a valid stored access token
Cause: The access token has expired (Spotify tokens last 1 hour). The Edge Function needs to check expiry and use the refresh token to obtain a new access token before calling the API.
Solution: Add expiry checking to your token retrieval logic: compare the stored expires_at timestamp with the current time. If the token expires within the next 5 minutes, call Spotify's token refresh endpoint (POST to https://accounts.spotify.com/api/token with grant_type=refresh_token and your refresh_token) before making the API call. Update the stored tokens in Supabase with the new access_token and expires_at.
1// Add this expiry check before using the stored token:2const now = new Date()3const expiresAt = new Date(tokenData.expires_at)4if (expiresAt.getTime() - now.getTime() < 5 * 60 * 1000) {5 // Token expires in less than 5 minutes — refresh it6 const refreshed = await refreshSpotifyToken(tokenData.refresh_token, clientId, clientSecret)7 // Use refreshed.access_token for the API call8}Spotify Web API returns 403 Forbidden for specific endpoints despite successful authentication
Cause: The OAuth scope required for the endpoint was not requested during the initial authorization. For example, accessing /me/player requires user-read-playback-state scope, and /me/top/tracks requires user-top-read scope.
Solution: Check Spotify's API documentation for the required scope of the endpoint you are calling. If the required scope was not included in the original OAuth request, the user needs to re-authorize with the additional scope. Update your OAuth initiation code to include all necessary scopes, then prompt the user to disconnect and reconnect their Spotify account. Note that once a user has authorized, Spotify caches their consent — adding new scopes requires the user to re-authorize.
Best practices
- Always use PKCE for Spotify OAuth flows in Lovable apps — never implement the implicit grant flow (deprecated by Spotify) or send the client secret from the browser.
- Store Spotify tokens in Supabase with a user_id foreign key so each user's tokens are isolated and you can revoke them independently.
- Implement proactive token refresh — check if the token expires within 5 minutes before each API call, and refresh it preemptively rather than waiting for a 401 error.
- Cache non-personalized Spotify data (artist profiles, album metadata, track details) in Supabase with a TTL — this data changes infrequently and caching reduces API calls significantly.
- Always check for the preview_url field in track objects before rendering a play button — Spotify only provides 30-second previews for some tracks, and the field is null for tracks without available previews.
- Handle Spotify rate limits gracefully: check for 429 responses, read the Retry-After header, and either wait and retry or show the user a 'Too many requests, please try again shortly' message.
- Request only the minimum OAuth scopes your app needs during authorization — users see the full list of requested permissions, and requesting unnecessary scopes reduces user trust and authorization rates.
Alternatives
Choose SoundCloud if your app focuses on indie and user-uploaded audio content with simpler client_id authentication, rather than Spotify's mainstream catalog with complex OAuth2 requirements.
Choose Twitch if your app targets live streaming audiences and gaming communities rather than recorded music and playlist management.
Choose ElevenLabs if your use case is AI-generated audio content like text-to-speech and voice synthesis, rather than streaming existing music from Spotify's catalog.
Frequently asked questions
Can I use the Spotify API without requiring users to log in with their Spotify account?
Yes — for non-personalized data like searching tracks, fetching album details, or getting artist information, Spotify offers a Client Credentials flow that uses your app credentials without user authorization. However, for personalized features (user's top tracks, playlists, listening history, playback control), users must authorize with their own Spotify account. The Client Credentials flow is handled entirely server-side in an Edge Function — no redirect or user interaction required.
Do users need a Spotify Premium account to use my Lovable app?
Only for playback control features. The Spotify Web Playback SDK (which enables in-browser music playback) and the Player API endpoints (/me/player/*) require Premium. All read-only data features — top tracks, playlists, search, recommendations, artist/album data — work with both free and Premium Spotify accounts. If your app only uses data and previews (30-second preview_url clips), free-tier Spotify users can use it fully.
How many users can my Lovable app serve with the Spotify API?
Spotify Developer Apps start in 'Development Mode' limited to 25 users. To serve more users, apply for 'Extended Quota Mode' in the Spotify Developer Dashboard — this removes the 25-user cap. Additionally, if your app reaches commercial scale or has specific use cases (like music app or education), you may need to apply for specific Spotify platform quotas. Spotify's rate limits are per-access-token and generally comfortable for typical apps.
Can I play full Spotify tracks in my Lovable app, not just 30-second previews?
Yes — full track playback requires implementing the Spotify Web Playback SDK in your React frontend alongside your Edge Function proxy. The SDK registers your app as a Spotify Connect device, and users can control playback using the Spotify Player API. The SDK is loaded via a script tag in your HTML, initialized with the user's access token, and then your React components interact with the SDK's JavaScript API. This requires Spotify Premium and users must authorize the user-read-playback-state and user-modify-playback-state scopes.
How do I search the Spotify catalog for tracks and artists?
Spotify's search endpoint (GET /v1/search?q=search+term&type=track,artist&limit=20) works with either a user access token or a client credentials token. For public search features (users search without logging in), use client credentials — your Edge Function calls the token endpoint with grant_type=client_credentials, uses the token for the search query, and returns results. No user OAuth flow is needed. The search results include track IDs, artist IDs, album IDs, and preview URLs that you can use in your React components.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation