Skip to content
Guides

How to Avoid Getting Blocked When Web Scraping

To avoid getting blocked when web scraping, distribute requests across rotating residential proxies, send realistic browser headers, pace and randomise your requests, target the right location, and handle errors with backoff. Most blocks come from sending too many requests from one IP or looking obviously automated.

seamless Team13 min readJune 20, 2026Updated August 6, 2026
  • anti-bot
  • web scraping
  • fingerprinting
  • captcha
Three layered checkpoint gates with one payload passing cleanly along a lit path and an identical one stopped at the first gate

Blocks feel arbitrary until you understand that detection runs as a pipeline. Each layer is cheaper than the next, so sites evaluate them in order and stop as soon as something looks wrong. Debugging works the same way: fix layer one before touching layer four, or you will spend money on proxies to solve a header problem.

LayerWhat it checksCost to the site
1. IP reputationASN, hosting range, blocklistsNear zero
2. Request shapeHeaders, order, TLS signatureVery low
3. Rate and patternFrequency, regularity, sequenceLow
4. Browser environmentJS execution, canvas, WebGLModerate
5. BehaviourMouse, scroll, timing between actionsHigh
6. ChallengeCAPTCHA, proof of workHighest, and costs real users too

1. Rotate IPs with residential proxies

The single biggest factor is the IP. Use rotating residential proxies so each request, or each small batch, comes from a different real home IP. This prevents the rate limits and bans that hit a single repeating address, and it clears systems that filter datacenter ranges outright.

One caveat that catches people: rotating harder does not always help. If the site is scoring your request *shape* rather than your address, every new IP simply delivers the same suspicious request from somewhere new. If your block rate is unchanged after switching to residential, the problem is layer two.

2. Send realistic headers

This is where most scrapers are identified, and it is free to fix.

  • Set a real, current User-Agent and keep it plausible — a Chrome version from three years ago is a signal in itself.
  • Send the full set. Accept, Accept-Language, Accept-Encoding, Referer, and the Sec-Fetch-* and Sec-CH-UA headers modern browsers include.
  • Match header order. Browsers send headers in a consistent order; most HTTP libraries do not. Order alone can distinguish a real Chrome from a library claiming to be one.
  • Keep the set coherent. A Chrome user-agent paired with headers Chrome never sends is worse than an honest one.
  • Do not rotate user-agents within one session. A browser that changes identity between two requests is more suspicious than one that stays boring.

TLS fingerprinting

The layer beneath headers, and the one that quietly defeats otherwise well-built scrapers. Every TLS client presents a distinctive combination of cipher suites, extensions and ordering — Chrome's differs from Python's requests, which differs from Go's standard library. Sites match against known signatures, so a request can be flagged before a single HTTP header is read.

You cannot fix this with headers. The options are to use a client that mimics a browser's TLS handshake, or to run an actual browser via Playwright or Puppeteer and accept the bandwidth cost.

If your scraper works from a browser and fails from a script against the same IP, stop adjusting headers. You are being identified below HTTP.

3. Pace and randomise requests

Add delays between requests and randomise them. Aggressive, perfectly timed bursts are an obvious bot signal — and so is a perfect two-second interval, because no human is that consistent. Draw from a distribution rather than a constant, and slow down more on error responses than on successes.

Rough starting point: 1–5 seconds between requests to one host, randomised, with concurrency spread across IPs rather than stacked on one. Then tune against the site's actual tolerance rather than against a number from a blog post.

A grid of identical tokens with one subtly different token lifted out and highlighted
Detection is about being the odd one out. Consistency with real traffic matters more than any single setting.

4. Use sessions where needed

For multi-step flows — login, pagination, carts — use sticky sessions to keep the same IP for the whole sequence, then rotate between sequences. For independent page fetches, rotate per request. Getting this backwards produces symptoms that look exactly like detection but are self-inflicted; rotating vs sticky sessions covers the diagnosis.

5. Target the right location

Use country or city targeting so the IP location matches the content you are collecting. This improves accuracy and looks natural — but the stronger reason is consistency. An Accept-Language of de-DE arriving from a Brazilian IP with a New York timezone is three signals that disagree, and disagreement is what gets scored.

Clean IPs, city-level targeting

Residential proxies with country, city and ASN selection across our full location coverage.

See residential proxies

6. Handle errors gracefully

  1. 1Classify the failure. A timeout, a 429, a 403, a challenge page and a genuine 404 need different responses — the error code reference covers which is which.
  2. 2Detect soft blocks by content, not status. A 200 carrying a challenge page is the most common modern block.
  3. 3Back off exponentially and rotate the exit — but back off first. Retrying immediately on a fresh IP teaches the site that its rate limit is being evaded.
  4. 4Cap retries and quarantine problem URLs rather than looping.
  5. 5Log the exit IP with every failure. Without it you cannot tell a bad exit from a bad request.

Reading the symptoms

SymptomMost likely layerFirst thing to try
Blocked from the very first requestIP reputationSwitch to a residential exit
Works in a browser, fails in a scriptTLS or headersMatch the browser's handshake
Success rate decays over a runRate and patternSlow down, spread across more exits
200 with missing fieldsSoft blockAssert on content, validate responses
CAPTCHAs partway throughRate and patternReduce per-IP throughput
Challenged even in a real browserBehaviourReconsider whether to scrape this target

Do proxies stop CAPTCHAs?

They reduce them substantially, because a clean residential IP does not trip the reputation check that triggers most challenges. They do not eliminate them. A CAPTCHA appearing partway through a run is almost always a rate signal, not an IP signal — the answer is to slow down, not to buy better proxies.

Proxies remove the IP bottleneck; clean headers, pacing and good error handling do the rest. Always respect robots.txt and the site's terms.

Sources

Frequently asked questions

Why do I keep getting blocked when scraping?

Usually because too many requests come from one IP, you're using detectable datacenter IPs, or your requests look automated through missing or oddly ordered headers and no delays. Rotating residential proxies plus realistic headers and pacing fix most cases.

Do proxies stop CAPTCHAs?

Clean residential IPs greatly reduce CAPTCHA frequency because they look like real users. Combine them with good request hygiene; for the toughest sites you may still need a CAPTCHA-solving step.

How slow should my scraper be?

A common starting point is 1–5 seconds between requests with randomisation, adjusted to the site's tolerance. Rotating IPs lets you parallelise while keeping per-IP rates low.

What is TLS fingerprinting and how do I get around it?

Every TLS client presents a distinctive combination of cipher suites and extensions, so a site can identify Python's requests or Go's standard library before reading a single HTTP header. Headers cannot fix it. Either use a client that reproduces a browser's TLS handshake, or drive a real browser.

My scraper works in a browser but not in code. Why?

Almost always a request-shape problem rather than an IP problem. The browser sends a different TLS signature, a complete and correctly ordered header set, and executes JavaScript your script does not. Test from the same IP in both to confirm the address is not the variable.

Should I retry immediately after a block?

No. Back off first, then retry on a different exit. Retrying instantly on a fresh IP looks like deliberate evasion and tends to escalate the site's response rather than get you through.

Is rotating my user agent on every request a good idea?

Not within a session. A browser does not change what it is between two requests, so rotation there is itself a signal. Vary the user agent between sessions and keep it fixed and coherent with the rest of your headers inside one.

SE
seamless Team
Proxy infrastructure

The seamless team runs residential, ISP and datacenter proxy infrastructure and writes these guides from day-to-day operational experience.

Ready to try seamless proxies?

Residential, ISP and datacenter proxies with no data expiry.

Browse Plans