Introducing ScrapeGraphAI V2 — better, faster, cheaper APIs. Read the blog →
ScrapeGraphAIScrapeGraphAI
Dark

What Is a 403 Error in Web Scraping?

Last updated: Jul 14, 2026

TL;DR

A 403 Forbidden error means the server understood the request but refuses to serve it. In web scraping, 403 is the signature of bot detection: the site flagged your IP address, headers, or TLS fingerprint as automated and blocked the request before any content was returned.

Why Scrapers Get 403s

A browser opening the same URL usually loads it fine, which tells you the block targets how you ask, not what you ask for. The common triggers, roughly in order of frequency:

IP reputation. Datacenter IP ranges are public knowledge, and anti-scraping systems score them harshly. A clean residential or mobile IP often clears a 403 immediately.

Missing or inconsistent headers. Default HTTP client headers (python-requests/2.32) are an instant giveaway. So is a perfect Chrome User-Agent paired with header ordering no Chrome build ever produced.

TLS fingerprinting. Systems like Cloudflare hash the TLS handshake (JA3/JA4). Python's ssl stack handshakes differently from a browser, and no header can hide that.

Missing cookies or tokens. Some sites issue a session cookie on the landing page and return 403 to any deep URL requested without it.

How to Fix a 403

Work through the causes in the same order:

import requests
 
headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Referer": "https://www.example.com/",
}
response = requests.get(url, headers=headers, timeout=(5, 30))

If realistic headers are not enough, rotate to residential proxies. If the block persists, the site is fingerprinting the client itself, and the practical answers are a headless browser with stealth patches or an impersonation HTTP client that replays real browser handshakes.

One caution: hammering a 403 with retries from the same IP trains the anti-bot system on your traffic. Back off, change identity, then retry.

403 vs 401 vs 429

  • 401: credentials required and missing; authentication fixes it.
  • 403: identity known or irrelevant, access denied; changing how you connect fixes it.
  • 429: you asked too fast; slowing down fixes it.

Key Takeaways

  • 403 in scraping almost always means bot detection, not permissions.
  • Escalate in order: realistic headers, residential IPs, browser-grade fingerprints.
  • Never retry a 403 aggressively from the same identity.

How ScrapeGraphAI Handles This

ScrapeGraphAI routes every request through a provider chain with managed proxy rotation, browser-grade fingerprints, and JavaScript rendering, escalating automatically when a target answers 403. You call the scrape endpoint with a URL; the unblocking strategy is not your problem.