In this short guide, we will learn how to fix the Yahoo Finance 429 error ("Too Many Requests") when accessing stock data via API. This common issue occurs when Yahoo Finance detects automated requests without proper browser headers, blocking your API calls with rate limit errors.

Problem: 429 Too Many Requests Error

When making direct API requests to Yahoo Finance, you'll encounter the 429 error with the message "Edge: Too Many Requests" because Yahoo's CDN blocks requests without valid User-Agent headers.

Error Example

import requests

url = "https://query1.finance.yahoo.com/v8/finance/chart/AAPL"
params = {"interval": "1m", "range": "1d", "prepost": "true"}

response = requests.get(url, params=params)
print(f"Status Code: {response.status_code}")
print(f"Error Message: {response.text[:100]}")

Output Result:

Status Code: 429
Error Message: Edge: Too Many Requests

Solution: Add User-Agent Headers

1. Simple Fix: Add Browser User-Agent

Add a User-Agent header to make your request appear as a legitimate browser request, bypassing Yahoo's rate limiting.

import requests

symbol = "TSLA"
url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}"

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}

params = {"interval": "1m", "range": "1d", "prepost": "true"}

response = requests.get(url, params=params, headers=headers)
data = response.json()

print(f"Status Code: {response.status_code}")
print(f"Symbol: {data['chart']['result'][0]['meta']['symbol']}")
print(f"Current Price: ${data['chart']['result'][0]['meta']['regularMarketPrice']:.2f}")

Output Result:

Status Code: 200
Symbol: TSLA
Current Price: $245.38

2. Complete Headers Setup for Reliability

For production applications, use a complete set of browser headers to avoid detection and rate limiting.

import requests
import time

def get_stock_data(symbol):
    url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}"
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        'Accept': 'application/json',
        'Accept-Language': 'en-US,en;q=0.9',
        'Referer': 'https://finance.yahoo.com/'
    }
    
    params = {"interval": "1d", "range": "1mo"}
    
    response = requests.get(url, params=params, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    else:
        return None

stocks = ['AAPL', 'MSFT', 'NVDA']
for stock in stocks:
    data = get_stock_data(stock)
    if data:
        price = data['chart']['result'][0]['meta']['regularMarketPrice']
        print(f"{stock}: ${price:.2f}")
    time.sleep(1)

Output Result:

AAPL: $185.64
MSFT: $372.55
NVDA: $738.45

3. Rate Limiting Best Practices

Implement request delays and retry logic to avoid hitting rate limits even with proper headers.

import requests
import time
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_session():
    session = requests.Session()
    retry = Retry(total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504])
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('https://', adapter)
    
    session.headers.update({
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    })
    
    return session

session = create_session()
url = "https://query1.finance.yahoo.com/v8/finance/chart/GOOGL"

response = session.get(url, params={"interval": "1d", "range": "5d"})
print(f"Request successful: {response.status_code == 200}")
print(f"Data received: {len(response.content)} bytes")

Output Result:

Request successful: True
Data received: 15847 bytes