Introducing Highlights: the context that matters

What Is a 521 Status Code?

A 521 status code is a Cloudflare error, "Web server is down", returned when the origin web server refuses the connection from Cloudflare. Either the web server application is offline, or a firewall or security tool on the origin is blocking Cloudflare’s IP addresses. It is a Cloudflare extension, not part of the HTTP standard.

Code
521
Name
Web Server Is Down
Class
Cloudflare extension
Retry?
Yes, with backoff

What causes error 521?

  • →The web server process on the origin is stopped or crashed.
  • →A firewall or security tool on the origin blocking or rate limiting Cloudflare’s IPs.
  • →The origin not listening on the port the SSL mode needs: 80 for Flexible, 443 for Full and Full (strict).

How do you fix error 521 when web scraping?

  • →Retry with backoff. If the site is down for everyone, retries will not help until it recovers.
  • →Check the site from a normal browser. A 521 there confirms the origin is down, not that you are blocked.
  • →Use a cached copy of the page for time-sensitive jobs.

How do you fix error 521 on your own server?

  • →Confirm the web server is running and responding locally.
  • →Allow all Cloudflare IP ranges in your firewall and security software.
  • →If SSL mode is Full or Full (strict), make sure the origin serves HTTPS on port 443.

How do you handle error 521 in a retry loop?

fetch() treats 521 as temporary. It waits for Retry-After when the server sends a number of seconds, otherwise backs off exponentially with jitter, caps every wait at 60 seconds, and gives up after five attempts.

import random
import time

import requests

RETRYABLE = {408, 429, 500, 502, 503, 504, 520, 521, 522, 523, 524}


def fetch(url: str, max_attempts: int = 5) -> requests.Response:
    for attempt in range(max_attempts):
        try:
            response = requests.get(url, timeout=(10, 60))
        except requests.Timeout:
            time.sleep(2**attempt + random.uniform(0, 1))
            continue
        if response.status_code not in RETRYABLE:
            response.raise_for_status()
            return response
        retry_after = response.headers.get("Retry-After", "")
        backoff = 2**attempt + random.uniform(0, 1)
        time.sleep(min(int(retry_after) if retry_after.isdigit() else backoff, 60))
    raise RuntimeError(f"Gave up on {url} after {max_attempts} attempts")

How does Context.dev handle error 521?

Context.dev retries the fetch for you, and by default Scrape can reuse a capture made in the last 3 days (maxAgeMs), so a page that is briefly down may still come back from cache. If no capture is available, the failed output carries an error_code and message inside an HTTP 200 response, and a request where every output fails is not charged.

See what the web scraping API does on every request, or read how to fix HTTP errors in web scraping for a longer walkthrough.

Frequently asked questions about error 521

What does Cloudflare error 521 mean?

Cloudflare tried to connect to the site’s origin server and the connection was refused. The site’s server is down or blocking Cloudflare.

Can a visitor fix a 521 error?

No. Only the site owner or host can restart the server or fix the firewall. Visitors can only wait and retry.

What is the difference between 521 and 522?

A 521 is an active refusal. A 522 is a timeout: Cloudflare got no answer at all.

Which status codes are related to 521?

Sources

Last reviewed

Ship an agent that actually knows things.

Free tier, 10-minute integration, and the same API powering agents at Mintlify, daily.dev, and Propane. No credit card to start.