How Spotify-Saver Handles YouTube Music Search Rate Limiting and Bot Detection with Cookies

Spotify-Saver employs a dual-layer defense against YouTube Music rate limiting and bot detection by combining retry logic with LRU caching for search operations and authenticated browser cookies with Android client spoofing for downloads.

The open-source Spotify-Saver project (github.com/gabrielbaute/spotify-saver) bridges Spotify and YouTube Music to convert playlists into local audio files. To handle YouTube Music search rate limiting and bot detection with cookies, the architecture separates concerns into distinct layers: a resilient search client that mitigates throttling through retries and caching, and an authenticated downloader that masquerades as legitimate browser traffic using exported session cookies.

Search Resilience Through Retry Logic and Caching

Defensive Retry Mechanism in YoutubeMusicSearcher

In spotifysaver/services/youtube_api.py, the YoutubeMusicSearcher class wraps the ytmusicapi client with robust error handling. The search_track method implements a retry loop with max_retries = 3 that intercepts generic exceptions, AlbumNotFoundError, and InvalidResultError, logging each attempt before gracefully returning None if all retries fail.

While the code does not explicitly catch RateLimitExceeded from spotifysaver/services/errors/errors.py, any HTTP 429 or similar transient errors bubble up as exceptions that trigger this retry logic. This gives YouTube Music's servers time to recover from throttling without aborting the entire operation.

LRU Caching to Prevent API Hammering

To minimize redundant network requests that could trigger rate limiting, the implementation decorates search results with @lru_cache(maxsize=100). This caching layer ensures that repeated lookups for identical tracks—common when processing large playlists with duplicate entries or re-running migration scripts—retrieve results from memory rather than hitting the remote API again.

The YouTubeDownloader class in spotifysaver/downloader/youtube_downloader.py combats bot detection by passing a cookie file to the underlying yt-dlp tool through Config.YTDLP_COOKIES_PATH. When users supply a cookies.txt exported from a logged-in Chrome or Firefox session containing authentication tokens like CONSENT and LOGIN_INFO, the downloader presents these valid session cookies to YouTube's servers.

This authentication state mimics a real browser session, effectively defeating age-restriction blocks and signature-based bot detection that flags requests lacking legitimate session data.

Realistic Headers and Android Client Spoofing

Beyond cookies, the _get_ydl_opts method (lines 31-48) configures yt-dlp with aggressive mimicry parameters:

  • A realistic User-Agent string matching common browsers
  • A Referer header explicitly set to https://music.youtube.com
  • Extractor arguments specifying the Android player client ("player_client": ["android"])

The Android client selection is strategically significant because it reduces the metadata payload Google expects and sidesteps stricter verification protocols employed for web clients, which are more heavily scrutinized for automated scraping patterns.

YTDLP_COOKIES_PATH Environment Variable

In spotifysaver/config/setting_environment.py (lines 40-55), the application defines the optional YTDLP_COOKIES_PATH environment variable. Users can export this variable in their shell or define it in a .env file to point toward a Netscape-format cookies.txt file. When set, the configuration automatically injects this path into the yt-dlp options during downloader initialization, enabling seamless authenticated access without code modifications.

Practical Implementation Examples


# Example 1 – Searching a track with rate-limit tolerance

from spotifysaver.services.youtube_api import YoutubeMusicSearcher
from spotifysaver.models.track import Track

searcher = YoutubeMusicSearcher()

track = Track(
    name="Bad Guy",
    artists=["Billie Eilish"],
    album_name="When We All Fall Asleep, Where Do We Go?",
    release_date="2019-03-29",
)

# Automatically retries up to 3 times on rate limits or errors

yt_url = searcher.search_track(track)
print("Found YouTube Music URL:", yt_url)

# Example 2 – Downloading with cookies for bot-detection mitigation

from spotifysaver.downloader.youtube_downloader import YouTubeDownloader
from spotifysaver.models.track import Track
from spotifysaver.config import Config

# Set the path to an exported cookies.txt (optional)

# export YTDLP_COOKIES_PATH=/home/user/.config/google-chrome/Default/Cookies.txt

# or set it in a .env file under the project root / home folder.

downloader = YouTubeDownloader(base_dir="MyMusic")

track = Track(
    name="Levitating",
    artists=["Dua Lipa"],
    album_name="Future Nostalgia",
    release_date="2020-03-27",
    cover_url="https://i.scdn.co/image/ab...jpg",
)

# Uses cookies, realistic headers, and Android client

path, updated = downloader.download_track(
    track,
    output_format=downloader.string_to_audio_format("mp3"),
    bitrate=downloader.int_to_bitrate(192),
    download_lyrics=True,
)

print(f"Saved to {path}")

Summary

  • The YoutubeMusicSearcher in spotifysaver/services/youtube_api.py implements three-tier retry logic to handle transient failures including implicit rate limits.
  • LRU caching with a 100-entry limit eliminates redundant API calls that could trigger throttling.
  • Cookie authentication through YTDLP_COOKIES_PATH allows the downloader to present valid session tokens, bypassing bot detection and age restrictions.
  • Android client spoofing combined with realistic headers in spotifysaver/downloader/youtube_downloader.py reduces the likelihood of triggering automated traffic filters.

Frequently Asked Questions

What triggers the retry mechanism during YouTube Music searches?

The search_track method catches AlbumNotFoundError, InvalidResultError, and generic exceptions—including HTTP 429 rate limit responses—and automatically retries the operation up to three times with logging between attempts. If all retries fail, the method returns None rather than crashing the application.

How do exported browser cookies prevent bot detection blocks?

Cookies containing CONSENT and LOGIN_INFO tokens exported from Chrome or Firefox are passed to yt-dlp via Config.YTDLP_COOKIES_PATH in spotifysaver/downloader/youtube_downloader.py. These tokens prove the request originates from an authenticated session, allowing the downloader to bypass signature-based detection that flags anonymous or scripted traffic.

Why does the downloader use the Android player client instead of the web interface?

The configuration in spotifysaver/downloader/youtube_downloader.py sets extractor_args to "player_client": ["android"] because Android clients transmit less metadata and use different API endpoints than web clients. This lighter request signature avoids the aggressive bot detection mechanisms Google applies to browser-based scraping attempts.

Set the absolute path to your exported cookies.txt file in the YTDLP_COOKIES_PATH environment variable, defined in spotifysaver/config/setting_environment.py (lines 40-55). You can export this in your shell or add it to a .env file in the project root, and the application will automatically use these cookies for all download operations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →