Connect Bubble to Spotify's Web API using the client credentials flow — no user login needed for catalog search, artist data, and audio features. A Backend Workflow acquires an access token and saves it to App Data, a Scheduled API Workflow refreshes it every 55 minutes before expiry, and all API Connector calls use a Private Authorization header so credentials stay server-side. Wire a search call to a repeating group for a Spotify-powered music discovery feature.
| Fact | Value |
|---|---|
| Tool | Spotify API |
| Category | Media & Content |
| Method | Bubble API Connector |
| Difficulty | Intermediate |
| Time required | 1.5–2 hours |
| Last updated | July 2026 |
Spotify Web API + Bubble: music discovery features without user login
Spotify's Web API has two modes: public catalog access (no user login) and user-specific access (playlists, liked tracks, listening history). For most Bubble music apps — a 'search Spotify' feature, an audio analysis tool, an artist stats dashboard — the public catalog via client credentials is all you need. The flow works like this: a Bubble Backend Workflow sends your Client ID and Client Secret to Spotify's token endpoint and gets back a time-limited access_token. Every API call from Bubble then uses that token in a header marked Private, so it never reaches the browser. The catch: Spotify access tokens expire after exactly 3,600 seconds (1 hour). Without a refresh mechanism, your Bubble app silently stops returning Spotify data after the first hour. The solution is a Scheduled API Workflow that runs every 55 minutes and calls the token endpoint again — keeping a fresh token in App Data at all times. For user-specific features (playlists, saved tracks), you would add a user OAuth flow similar to the Canva tutorial — but for most music Bubble apps, the client credentials pattern covers 90% of use-cases.
Integration method
Uses Bubble's API Connector with a Private Authorization Bearer header backed by a stored access token, acquired via a Backend Workflow that posts to Spotify's token endpoint and refreshed automatically by a Scheduled API Workflow every 55 minutes.
Prerequisites
- A Spotify account (free or premium) and a registered app at developer.spotify.com/dashboard — the Web API is free to use for public catalog data
- A Bubble paid plan — Scheduled API Workflows (needed for automatic token refresh) and Backend Workflows (needed for server-side token acquisition) both require a paid Bubble plan
- The API Connector plugin installed in your Bubble app — available from Plugins tab → Add plugins → API Connector (by Bubble)
- A basic understanding of Bubble's App Data concept — you will create a Settings data type to store the shared Spotify access token
Step-by-step guide
Register a Spotify Developer app and get credentials
Go to developer.spotify.com/dashboard and log in with your Spotify account. Click 'Create app.' Enter a name (e.g., 'My Bubble App'), a description, and a redirect URI. For the client credentials flow used in this tutorial, the redirect URI is not used — you can enter your Bubble app URL as a placeholder (e.g., `https://yourapp.bubbleapps.io`). Under 'APIs used,' select 'Web API.' Click Save. On your new app's dashboard page, click 'Settings.' You will see your Client ID immediately. Click 'View client secret' to reveal and copy the Client Secret. Keep both values handy — they go into your Bubble Backend Workflow as Private parameters. Note: the Spotify Developer agreement prohibits certain commercial uses. Review the Spotify Developer Terms of Service at developer.spotify.com/terms before launching a public-facing app, particularly around displaying streaming content or making Spotify data the primary feature of a competing music service.
Pro tip: In the Spotify app dashboard, set the redirect URI to a real page in your Bubble app — even if you are only using client credentials now. If you later add user OAuth for playlists, you will need a valid redirect URI already configured.
Expected result: You have a Spotify Developer app with Client ID and Client Secret copied and ready to use.
Create the App Data Settings type and Backend Workflow for token acquisition
First, create a Bubble data type to store the shared Spotify access token. Go to Data tab → Data types → click '+ Add a new type,' name it 'Settings.' Add a field: `spotify_access_token` (text) and `spotify_token_expiry` (date). You will use a single Settings record shared across the app (not per-user). Now create the token-acquisition Backend Workflow. Go to Settings → API tab → enable 'This app exposes a Workflow API.' Open the Backend Workflows editor and click 'New API Workflow,' name it 'Refresh Spotify Token.' Note: Backend Workflows require a Bubble paid plan. Inside the workflow, add an API call step using the API Connector (you will configure the API Connector in the next step, but you can pre-set the step). The workflow will POST to `https://accounts.spotify.com/api/token` with: Content-Type header `application/x-www-form-urlencoded`, body fields `grant_type=client_credentials`, `client_id=[your Client ID]` (Private), `client_secret=[your Client Secret]` (Private). After the API call returns, add a 'Create or make changes to a Thing' step: if a Settings record exists, update it; otherwise create one. Set `spotify_access_token` to the `access_token` from the response, and `spotify_token_expiry` to Current date/time + 3600 seconds (use Bubble's `:plus seconds` expression).
1{2 "endpoint": "POST https://accounts.spotify.com/api/token",3 "headers": [4 { "key": "Content-Type", "value": "application/x-www-form-urlencoded" }5 ],6 "body": {7 "grant_type": "client_credentials",8 "client_id": "<private: your_spotify_client_id>",9 "client_secret": "<private: your_spotify_client_secret>"10 },11 "response_fields": [12 "access_token",13 "token_type",14 "expires_in"15 ]16}Pro tip: Create a single 'Settings' record when your Bubble app first launches (add a workflow to your index page's 'Page is loaded' event that checks if a Settings record exists and creates one if not). This avoids errors in the token workflow when no Settings record exists yet.
Expected result: The 'Refresh Spotify Token' Backend Workflow is created, configured to POST to Spotify's token endpoint, and set to save the returned access_token and expiry time to your App Data Settings record.
Set up a Scheduled API Workflow for automatic token refresh
Spotify access tokens expire after exactly 3,600 seconds (1 hour). Without automatic refresh, your Bubble app will silently stop returning Spotify data after the first hour — no error message, just empty repeating groups. The cleanest solution is a Scheduled API Workflow that runs every 55 minutes. In the Backend Workflows editor, look at the top-right area for 'Recurring events' or find the scheduling option for your 'Refresh Spotify Token' workflow. In Bubble, you can schedule an API Workflow to recur by using the 'Schedule API Workflow' step at the end of the workflow itself — this creates a self-scheduling pattern: after refreshing the token, the workflow schedules itself to run again in 55 minutes. Add a 'Schedule API Workflow' step at the bottom of 'Refresh Spotify Token,' set the workflow to 'Refresh Spotify Token,' and set the scheduled date to 'Current date/time + 55 minutes.' Also trigger the 'Refresh Spotify Token' Backend Workflow on your app's index page load (as an on-page-load workflow step) so a fresh token is always available when the first user visits. Scheduled API Workflows require a Bubble paid plan. On the free plan workaround: call the Backend Workflow on every page load and check expiry before making API calls — less efficient but functional.
Pro tip: RapidDev's team has built Spotify-integrated Bubble apps with this exact self-scheduling token refresh pattern. If token management is getting complex, reach out at rapidevelopers.com/contact for a free scoping call.
Expected result: The Refresh Spotify Token Backend Workflow self-schedules 55 minutes into the future after each run, ensuring a valid Spotify access token is always available in App Data without any manual intervention.
Add the Spotify API Connector with a Private Authorization header
Go to Plugins tab → add the API Connector (by Bubble) if not already installed. Click 'API Connector' → 'Add another API.' Name it 'Spotify.' Set the base URL to `https://api.spotify.com/v1`. Under 'Shared headers,' add: key `Authorization`, value `Bearer [Settings's First Item's spotify_access_token]` — this dynamic expression reads the stored token from App Data. Check the 'Private' checkbox. Bubble will substitute the dynamic value server-side, keeping the token out of browser requests. Now add individual calls. Click 'Add a call,' name it 'Search Tracks.' Method: GET. Path: `/search`. Add URL parameters: `q` (dynamic, the search query), `type` (value `track`), `limit` (value `20`), `market` (value `US`, or make dynamic for multi-market apps). Set 'Use as' to 'Data.' Click 'Initialize call' — enter a real search term in the `q` field (e.g., `Beatles`) and click Initialize. Bubble sends a live request and auto-detects the response structure: `tracks.items[]`, with fields including `tracks items name`, `tracks items artists 0 name`, `tracks items album images 0 url`, `tracks items preview_url`, `tracks items id`, `tracks items duration_ms`. Expand the `tracks` object and mark `items` as your list type.
1{2 "api_name": "Spotify",3 "base_url": "https://api.spotify.com/v1",4 "shared_headers": [5 {6 "key": "Authorization",7 "value": "Bearer <dynamic: Settings's First Item's spotify_access_token>",8 "private": true9 }10 ],11 "calls": [12 {13 "name": "Search Tracks",14 "method": "GET",15 "path": "/search",16 "parameters": [17 { "key": "q", "value": "<dynamic>" },18 { "key": "type", "value": "track" },19 { "key": "limit", "value": "20" },20 { "key": "market", "value": "US" }21 ],22 "use_as": "Data"23 },24 {25 "name": "Get Audio Features",26 "method": "GET",27 "path": "/audio-features",28 "parameters": [29 { "key": "ids", "value": "<dynamic: comma-separated track IDs>" }30 ],31 "use_as": "Data"32 }33 ]34}Pro tip: If 'Initialize call' returns 'There was an issue setting up your call,' your App Data has no Settings record yet, or the stored access_token is expired. Manually run the 'Refresh Spotify Token' Backend Workflow once from the Bubble editor to populate the Settings record, then re-initialize.
Expected result: The Spotify API Connector is configured with a Private Authorization header and at least one initialized call. Bubble shows the detected response fields from the Spotify search response.
Build the music search repeating group with preview player
Add a Search Input element and a Button to your Bubble page. Add a Repeating Group below — set its data type to 'Spotify Search Tracks' and its data source to 'Search Tracks from Spotify — tracks items' (the items list from your initialized call). Wire the q parameter to the Search Input's value. Add a workflow to the Button: run the 'Search Tracks' API call with the current input value and refresh the repeating group. Inside each repeating group cell, add: an Image element (source: `Current cell's Spotify Search Tracks tracks items — album images 0 url` — this is the first album art thumbnail), a Text element for track name (`tracks items — name`), a Text element for artist name (`tracks items — artists 0 name`). For the preview player: `preview_url` is the direct URL of a 30-second MP3 preview. Note that approximately 30% of Spotify tracks have a null `preview_url` — these have no free preview. Conditionally show an Audio element (add via the audio plugin or HTML element) only when `preview_url` is not empty. Use a Bubble Custom State to hold the selected track ID when a user clicks a row, then trigger the Get Audio Features call to show danceability, energy, and other attributes in a detail panel.
Pro tip: Spotify's `/audio-features` endpoint accepts up to 100 comma-separated track IDs in a single call. If you want to display audio features for all 20 search results at once, concatenate the IDs using Bubble's ':join with' expression (separator: comma) on the list of track IDs from the search response.
Expected result: The music search page works end-to-end: typing a search term and clicking the button loads matching Spotify tracks with album art, artist names, and conditional preview players for tracks that have a preview URL.
Set up Data Privacy rules and test token refresh
Go to Data tab → Privacy. Click on the 'Settings' data type you created for storing the Spotify token. By default, Bubble makes all records searchable by anyone — you need to restrict this. Add a privacy rule: 'When: Current User is logged in AND Current User's role is admin' (adjust for your app's access model) to allow reading and modifying the Settings record. Without a privacy rule, any visitor to your app could query the Settings table through Bubble's API and potentially read the access_token field. Since the token is used server-side in Private headers, exposure through Bubble's data API is the real risk. Also add a 'Check expiry' step to your main search workflow: before calling Search Tracks, check if Settings's First Item's spotify_token_expiry is less than Current date/time. If so, call the Refresh Spotify Token Backend Workflow as a first step. This ensures fresh tokens even if the scheduled refresh missed a cycle. Finally, test the full flow: run the app, search for a track, verify results load, wait (or manually set the expiry to a past date) to test token refresh, and verify results continue to load after refresh.
Pro tip: Use Bubble's Logs tab → Workflow logs to verify each Spotify API call is succeeding. You can see the WU cost per API call and spot any 429 rate-limit responses if your app traffic is high.
Expected result: Data Privacy rules protect the Settings record. The token refresh mechanism works correctly — after expiry, the app automatically acquires a new token and continues returning Spotify search results without any user action.
Common use cases
Music Discovery and Search Feature
Add a Spotify search bar to any Bubble app — users type a song or artist name and see results in a repeating group showing track title, artist, album art, and a 30-second preview player. The API's GET /search endpoint supports filtering by type (track, artist, album, playlist) and by market.
Build a Bubble page with a search input and a repeating group that queries Spotify GET /search with the user's input, displays each track's name, artist, and album thumbnail, and plays a 30-second preview when the user clicks a row.
Copy this prompt to try it in Bubble
Audio Feature Analysis Dashboard
Let users input a Spotify track ID or URL and see detailed audio features: energy, danceability, valence (positivity), tempo (BPM), acousticness, and more. Use GET /audio-features with up to 100 track IDs at once and visualize the float values (0.0–1.0 range) as progress bars in Bubble.
Create a Bubble dashboard where a user pastes a Spotify track URL, the app extracts the track ID and calls GET /audio-features, then displays danceability, energy, valence, and tempo as labeled progress bars.
Copy this prompt to try it in Bubble
Artist Portfolio and Top Tracks Page
For music-focused Bubble apps, fetch an artist's top tracks by country using GET /artists/{id}/top-tracks and display a branded artist profile with bio, follower count, genre tags, and a top-10 track list with preview links.
Build a Bubble artist profile page that fetches artist details (GET /artists/{id}) and their top tracks (GET /artists/{id}/top-tracks?market=US), displaying a bio section and a ranked list of top-10 tracks with album art and preview player.
Copy this prompt to try it in Bubble
Troubleshooting
Repeating group shows no results after working fine — stops returning Spotify data silently
Cause: The Spotify access token has expired (3,600 seconds after acquisition). If the Scheduled API Workflow is not set up or has failed, the token in App Data is stale and all API calls return 401.
Solution: Manually run the 'Refresh Spotify Token' Backend Workflow from the Bubble editor to get a fresh token immediately. Then verify the Scheduled API Workflow is active — check Logs tab → Scheduled events to confirm the next run is queued. Also add an expiry check to the search workflow: before calling Spotify, verify the token expiry is in the future.
Initialize call returns 'There was an issue setting up your call' or 401 Unauthorized
Cause: No Settings record exists yet (first-time setup), or the stored access_token is expired or empty. The dynamic expression referencing 'Settings's First Item's spotify_access_token' returns empty if no Settings record has been created.
Solution: Go to Bubble editor → Data tab → App Data → Settings type and check whether a record exists. If not, manually create one or run the 'Refresh Spotify Token' Backend Workflow once from the editor. Then re-initialize the API Connector call.
Scheduled API Workflow for token refresh is not available in the workflow editor
Cause: Scheduled API Workflows are a Bubble paid-plan feature. The free Bubble plan does not include the ability to schedule recurring server-side workflows.
Solution: Upgrade to a Bubble paid plan to use Scheduled API Workflows. As a free-plan workaround, add a token-expiry check to every page load: if the token is expired or expiring in the next 5 minutes, call the Refresh Spotify Token Backend Workflow before running any Spotify API call. This is less efficient but works without scheduling.
preview_url is null for many tracks — the audio player shows nothing
Cause: Approximately 30% of Spotify tracks do not have a 30-second preview available. The preview_url field is null (not an empty string) for those tracks, and it is not an error.
Solution: Add a conditional to the Audio element or play button inside the repeating group: 'This element is visible when Current cell's tracks items preview_url is not empty.' This hides the player for tracks with no preview and shows it only when a URL is available.
GET /audio-features returns a 400 Bad Request when passing multiple track IDs
Cause: The ids parameter must be a comma-separated string with no spaces. If Bubble's Join With expression adds spaces after commas, or if the track IDs list contains duplicates or invalid IDs, Spotify rejects the request.
Solution: Use Bubble's ':joined with' expression on the list of track IDs with a comma (no space) as the separator. Verify the resulting string looks like 'id1,id2,id3' with no spaces. The endpoint accepts up to 100 IDs per request.
Best practices
- Store the Spotify access token in a shared App Data Settings record (not per-user) when using client credentials flow — this way one Backend Workflow keeps the token fresh for all users simultaneously, rather than each user triggering their own refresh.
- Add a Data Privacy rule to the Settings data type restricting read/write access — without it, any visitor can query the Settings table through Bubble's built-in API and read the access_token field.
- Always include an expiry check before Spotify API calls — if the token in App Data is expired, call the Refresh Backend Workflow first. This catches edge cases where the scheduled refresh fails.
- Use the preview_url conditional pattern for audio players — never assume all tracks have a preview. A conditional visibility check prevents broken player elements in the repeating group.
- Prefer the /artists/{id}/top-tracks and /playlistItems approaches over /search for known content — /search uses more API quota and returns broader results. If you know the artist ID or playlist ID, fetch directly.
- Monitor WU consumption in Bubble's Logs tab — each Spotify API call (including the token refresh) costs WU on Bubble's post-2023 pricing. Heavy search usage on a public app can accumulate significant WU costs.
- For user-specific features (playlists, saved tracks, personalized recommendations), you will need a separate user-delegated OAuth flow. The client credentials token cannot access any user data — plan this architecture distinction early.
Alternatives
SoundCloud uses a stable client_id URL parameter with no token expiry — much simpler auth than Spotify's time-limited Bearer tokens. SoundCloud is better for independent artist content; Spotify covers mainstream streaming with richer audio feature data.
YouTube Data API uses a permanent API key (no token expiry) and covers music videos and audio content. YouTube is better for video-first music apps; Spotify is better for audio-first apps with audio feature analysis.
Vimeo is a professional video platform with a permanent personal access token — simpler auth than Spotify and no token expiry. Vimeo is better for video portfolios and course platforms; not suitable for music discovery.
Frequently asked questions
Do I need a paid Spotify account to use the Web API?
No. The Spotify Web API for public catalog data (search, track info, audio features, artist data) is free to use with any Spotify account — even a free account. You need a Spotify Developer account at developer.spotify.com/dashboard, but that is also free. Premium subscription is only needed if your app controls Spotify playback (the Playback SDK requires users to have Spotify Premium).
Why do I need a paid Bubble plan for this integration?
Backend Workflows (for server-side token acquisition) and Scheduled API Workflows (for automatic token refresh every 55 minutes) both require a Bubble paid plan. Without them, the access token expires after 1 hour with no automatic renewal. As a free-plan workaround, you can trigger token refresh on page load, but this is less efficient and may cause delays.
Can Bubble control Spotify playback (play, pause, skip)?
Not directly. Spotify Playback control requires the Spotify Playback SDK, which runs in the browser as JavaScript and requires users to have Spotify Premium. You can embed the Spotify web player using an iframe with a Spotify URI or link, but Bubble cannot natively control the Spotify player through the Web API alone — the Playback API is separate.
How do I handle the 30% of tracks with no preview_url?
The preview_url field is null for approximately 30% of Spotify tracks. Add a conditional visibility rule to your audio player element: show it only when the current cell's preview_url is not empty. For tracks without a preview, show a 'No preview available' text or a link to the full track on Spotify using the external_urls.spotify field.
Can I access Spotify playlist data and user listening history without user OAuth?
No. Playlists marked private and any user-specific data (saved tracks, listening history, top artists) require user-delegated OAuth with the authorization code flow and user permissions. Client credentials only access publicly available catalog data. For playlist data, you can access any public playlist by its playlist ID using GET /playlists/{id} — no user OAuth needed for public playlists.
What happens if my Bubble app gets a 429 rate limit from Spotify?
Spotify returns a 429 Too Many Requests response with a Retry-After header specifying how many seconds to wait. Bubble does not automatically retry on 429. Add error-handling in your workflow: check the API call result for error status and display a user-friendly message like 'Please wait a moment and try again.' Avoid search-on-every-keystroke patterns — trigger the search only on button click or after a 500ms typing pause to reduce request frequency.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation