Announcements

Help Wizard

Step 1

NEXT STEP

403 error in building a playlist "Failed to fetch audio features"

Solved!

403 error in building a playlist "Failed to fetch audio features"

Hi, I’m developing a personal app using the Spotify Web API in Development Mode, and I’m encountering a persistent 403 Forbidden error when calling the /v1/audio-features endpoint.

 

Here are the details:

 

  • Scopes Granted: user-top-read, playlist-modify-public, playlist-modify-private, user-library-read, user-read-private

  • Token is retrieved via: SpotifyOAuth from the spotipy library

  • App Status: In Development Mode

  • User is added as a tester: (confirmed via Dashboard under “Users and Access”)

 

Despite proper authorization and the user being correctly added as a tester, I’m getting this response from the audio-features endpoint:

 

{
"error": {
"status": 403
}
}

 

The rest of the API calls (e.g., current_user_top_tracks, user_playlist_create) work as expected, and my access token is valid.

 

My questions:

 

  1. The /v1/audio-features endpoint has any specific restrictions even in Development Mode?

  2. There’s an issue with my user/token combination? (not sure how to speak to someone privately/directly about this)

  3. There are any additional scopes or permissions required that are not documented?

 

I’d appreciate any help in resolving this issue. Thank you!

 

 

The error I'm getting:

 

 {} returned 403 due to None
Failed to fetch audio features for batch 1: http status: 403, code: -1

 

 

 

The script I'm running:

 

import spotipy
from spotipy.oauth2 import SpotifyOAuth

# --- Configuration ---
CLIENT_ID = "my client id is here"
CLIENT_SECRET = "my client secret is here"
SCOPE = "user-top-read playlist-modify-public playlist-modify-private user-library-read user-read-private"
BPM_MIN = 120
BPM_MAX = 160
PLAYLIST_NAME = "Running Vibes"
TIME_RANGE = "long_term"
TRACK_LIMIT = 50

# --- Authenticate with Spotify ---
auth_manager = SpotifyOAuth(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
redirect_uri=REDIRECT_URI,
scope=SCOPE,
cache_path=".cache"
)

sp = spotipy.Spotify(auth_manager=auth_manager)

# --- Get User Info ---
user_info = sp.current_user()
print("Current user info:", user_info)
print("Logged in as:", user_info.get("email", "[no email in scope]"))
print("Granted scopes:", auth_manager.scope)

# --- Fetch Top Tracks ---
print("Fetching top tracks...")
top_tracks = sp.current_user_top_tracks(limit=TRACK_LIMIT, time_range=TIME_RANGE)
valid_tracks = [track for track in top_tracks["items"] if track["id"] and track["type"] == "track"]
track_ids = [track["id"] for track in valid_tracks]

# --- Analyze BPM ---
print("Analyzing BPM...")
audio_features = []

for i in range(0, len(track_ids), 100😞
batch = track_ids[i:i + 100]
try:
print(f"Requesting audio features for batch {i // 100 + 1}: {batch}")
features = sp.audio_features(batch)
if features:
audio_features.extend(features)
else:
print(f"No features returned for batch {i // 100 + 1}")
except spotipy.exceptions.SpotifyException as e:
print(f"Failed to fetch audio features for batch {i // 100 + 1}: {e}")

print(f"Audio features fetched: {len(audio_features)} items")
for feat in audio_features:
if not feat:
print("⚠️ Missing feature (None)")
else:
print(f"🎵 {feat['id']} - Tempo: {feat.get('tempo', 'N/A')}")

# --- Filter Tracks by BPM ---
running_tracks = [track_ids[i] for i, feat in enumerate(audio_features)
if feat and BPM_MIN <= feat["tempo"] <= BPM_MAX]

print(f"Found {len(running_tracks)} tracks in BPM range {BPM_MIN}-{BPM_MAX}")

# --- Create or Get Playlist ---
user_id = user_info["id"]
playlists = sp.current_user_playlists()["items"]
playlist_id = next((pl["id"] for pl in playlists if pl["name"] == PLAYLIST_NAME), None)

if not playlist_id:
print(f"Creating new playlist: {PLAYLIST_NAME}")
playlist = sp.user_playlist_create(user=user_id, name=PLAYLIST_NAME, public=False)
playlist_id = playlist["id"]
else:
print(f"Updating existing playlist: {PLAYLIST_NAME}")
sp.playlist_replace_items(playlist_id, [])

# --- Add Tracks to Playlist ---
if running_tracks:
print("Adding tracks to playlist...")
sp.playlist_add_items(playlist_id, running_tracks)
else:
print("No tracks matched your BPM range.")

print("Done! Check your Spotify playlists.")

 

 

 

Reply

Accepted Solutions
Marked as solution

Hi @morgan_wills 

 

Documentation about that endpoint says its Deprecated.

On November 27th of 2024, Spotify announced following:

"New Web API use cases will no longer be able to access or use the following endpoints and functionality in their third-party applications. Applications with existing extended mode Web API access that were relying on these endpoints remain unaffected by this change."

 

And endpoint you are referring to is in this list. If you are now writing an app, you most likely do not have "existing extended mode Web API access" so, thats why the endpoint is not and won't work.

XimzendSpotify Star
Help others find this answer and click "Accept as Solution".
If you appreciate my answer, maybe give me a Like.
Note: I'm not a Spotify employee.

View solution in original post

2 Replies
Marked as solution

Hi @morgan_wills 

 

Documentation about that endpoint says its Deprecated.

On November 27th of 2024, Spotify announced following:

"New Web API use cases will no longer be able to access or use the following endpoints and functionality in their third-party applications. Applications with existing extended mode Web API access that were relying on these endpoints remain unaffected by this change."

 

And endpoint you are referring to is in this list. If you are now writing an app, you most likely do not have "existing extended mode Web API access" so, thats why the endpoint is not and won't work.

XimzendSpotify Star
Help others find this answer and click "Accept as Solution".
If you appreciate my answer, maybe give me a Like.
Note: I'm not a Spotify employee.

thank you!

Suggested posts

Let's introduce ourselves!

Hey there you,   Yeah, you! 😁   Welcome - we're glad you joined the Spotify Community!   While you here, let's have a fun game and get…

ModeratorStaff / Moderator/ 4 years ago  in Social & Random