🎉 Premium Proxies · 3-Day Free TrialClaim Now →
Guides

How to Bypass Imperva (Incapsula) When Web Scraping

Bypass Imperva when web scraping public data: how Incapsula fingerprints via visid_incap, reese84, and ___utmvc, plus real browsers, clean IPs, and API code.

S SparkProxy 5 20 min read
Share
How to Bypass Imperva (Incapsula) When Web Scraping

Trying to bypass Imperva with a plain requests.get() usually returns a 403 carrying the line "Request unsuccessful. Incapsula incident ID," and it happens on the very first call. Imperva, the WAF and bot-protection layer that used to be branded Incapsula, decides whether your traffic looks human before your code ever sees the page HTML. This guide explains how Imperva fingerprints a request, how to read its cookies and block responses, and the practical, ethical ways to collect public data from Incapsula-protected sites without pretending your traffic is something it isn't. There's no permanent bypass and no magic header. What follows are the signals that actually decide the outcome, and how to make honest automated requests look like the real browser sessions they already are.

Scrape responsibly: what "bypass" really means

"Bypass" here means one thing: making legitimate, automated access to public data look like the ordinary browser traffic it already is, so a heuristic doesn't wrongly flag it. It does not mean breaking into anything protected. Set the ground rules before you write a line of code.

  • Public data only. Anything behind a login, a paywall, or that exposes someone's personal information is off-limits without explicit permission. Imperva often guards fraud-sensitive flows too (checkout, account creation, ticketing). Leave those alone.
  • Read robots.txt and the Terms of Service. If a path is disallowed or the ToS prohibits automated collection, respect it. A Crawl-delay directive is a rate the site is asking you to honor, not a suggestion to ignore.
  • Rate-limit yourself. Imperva exists partly because scrapers hammer origins. Slow, considerate crawling is both more ethical and, conveniently, far less detectable.
  • Prefer the official API. If the site publishes a feed or an API, use it. It's faster, cleaner, and it's the access path the site actually sanctions.
  • No guarantees. Imperva ships detection updates continuously, and its reese84 sensor changes shape often. A technique that works today can stop working next week. Anyone selling a "permanent Incapsula bypass" is selling snake oil.

The goal is not to defeat security. It's to stop a bot filter from misclassifying a well-behaved, public-data crawler as an attacker. If a site clearly does not want to be scraped, the correct answer is to stop, not to escalate.

Everything below is about fingerprint realism and good manners, not about defeating authentication or collecting data that was never meant to be public.


How Imperva (Incapsula) detects bots

Imperva is really two products stacked on the same edge. The WAF layer applies signature and rule-based filtering and stamps traffic with an X-Iinfo header and, when it blocks, an "Incapsula incident ID." The Advanced Bot Protection layer (the technology that absorbed Distil Networks) runs client-side JavaScript, collects a device fingerprint, and scores behavior. A request gets checked across several independent layers at once, and one strong mismatch is enough to trip a block. That's why swapping in a "better proxy" rarely fixes anything on its own: the IP is only one row in the table.

Here is the practical map of what Imperva bot detection inspects:

Detection layerWhat Imperva inspectsWhat gives a bot away
IP reputation and ASNAddress history, whether the ASN is a known datacenter (AWS, GCP, Azure, OVH, Hetzner)A clean-looking request from a flagged datacenter range
TLS fingerprint (JA3/JA4)Cipher suites, extensions, curves in the TLS Client HelloPython `urllib3` or Go defaults that match no real browser
HTTP/2 fingerprintFrame settings, header order, pseudo-header order, priorityA Chrome User-Agent over an HTTP/2 profile no Chrome would send
HTTP headers and client hints`User-Agent`, `Accept-*`, `sec-ch-ua`, header order and casingMissing client hints, wrong `Accept`, alphabetized headers
JavaScript sensorThe ___utmvc or reese84 script: canvas, WebGL, audio, fonts, screen, timezone, `navigator.webdriver`Headless flags, `SwiftShader` WebGL, a missing or replayed sensor token
BehaviorMouse and touch events, request cadence, navigation orderZero mouse movement, deep-linking with no homepage visit first

The mental model that matters: Imperva cross-checks these layers against each other. A Chrome User-Agent paired with a Python TLS handshake is more suspicious than an honest Python client, because the inconsistency is the tell. To pass, every layer has to agree on the same story. That principle drives the whole proxy-block avoidance playbook, and it applies double to Imperva because it grades both the network request and the browser that made it.


Free trial

Scraping at scale? Skip the blocks.

Fast, unblockable datacentre proxies with unlimited bandwidth.

Two challenge generations: ___utmvc vs reese84

Sites on Imperva serve one of two client-side challenges depending on how the account is configured, and they need different handling. Knowing which one you're facing saves hours of chasing the wrong fix.

Legacy UTMVCAdvanced Bot Protection (reese84)
Script sourceObfuscated JS from `/_Incapsula_Resource?...`A sensor script loaded on the page, often behind an interstitial
What it collectsBrowser environment: canvas, plugins, navigator props, screen180+ encrypted signals: canvas, WebGL, audio context, fonts, mouse events
How it validatesComputes a token, sets `___utmvc`, then reloads the pagePOSTs an encrypted payload, server returns a `reese84` token as JSON
Cookie set`___utmvc` plus a refreshed `incap_ses``reese84` plus the standard chain
How to clear itA real browser, or a JS engine that runs the scriptA real browser; the payload is heavily obfuscated and rotates
Tell`/_Incapsula_Resource` request in the network logAn interstitial like "This request seems a bit unusual" before content

The legacy UTMVC path is sometimes solvable without a full browser if you can execute the obfuscated script in a JS engine, but it changes often and reverse-engineering it is a moving target. The reese84 sensor is the harder, current-generation layer, and there is no reliable shortcut around running an actual browser or a rendering service that runs one for you. For anything reese84-protected, plan on real rendering from the start rather than burning a day on a solver that breaks at the next update.


Decode the block: incident ID, X-Iinfo, and 403 vs 200

Most scrapers treat "not 200" as one failure. Imperva actually hands you a diagnostic if you read the status code, the headers, and the block body together. Different outcomes need different fixes, and retrying the wrong way just burns IPs.

ResponseWhat you'll seeWhat Imperva decidedCorrect action
**200 (real content)**Your HTML/JSON plus a full, refreshed cookie chainPassed every layerPersist the cookie chain, keep the same exit IP for the session
**200 (interstitial)**A short "please wait" page, a sensor script, no real contentSilent JS challenge issuedRender it in a real browser so the sensor runs and returns a token
**200 (fake block)**A valid-looking page with empty or decoy dataApplication-layer soft block meant to waste your timeCheck your cookie chain and fingerprint; you were quietly flagged
**403 (`incident ID`)**Block page with "Request unsuccessful. Incapsula incident ID" and `X-Iinfo`Hard block: reputation or fingerprint failed outrightRotate IP and fix the fingerprint; do not replay the identical request
**429**Rate-limit response, often with `Retry-After`Too many requests from this IP or sessionBack off, drop concurrency, slow the crawl
**530 / 502**Returned by a scraping API or the edge when upstream retries failThe proxy or render layer exhausted its attemptsRetry with backoff; escalate to premium proxy plus stealth

Two things make Imperva different from most anti-bot vendors. First, the X-Iinfo response header is a giveaway on its own: it carries a four-segment debug code that identifies the Imperva point of presence and which policy handled the request, and its mere presence confirms you're behind Incapsula even on a 200. Second, Imperva sometimes returns a 200 with decoy content instead of an honest 403, specifically to confuse scrapers into thinking they succeeded. If your parser suddenly finds "no results" on a page that clearly has data in a browser, treat that as a soft block, not an empty catalog. Branch on these signals instead of blindly rotating.


Use a real browser, not a bare HTTP client

The reese84 sensor is the layer a plain HTTP library cannot satisfy, because there's no JS runtime to run the script and no way to produce the encrypted token. Satisfying the fingerprint reliably means running an actual browser.

For headless automation, launch Chromium through Playwright or Puppeteer and patch the obvious automation leaks with a stealth layer. Here's Playwright in Python routing through a residential proxy, warming up the homepage so the cookie chain gets set before you request the page you actually want:

from playwright.sync_api import sync_playwright
from playwright_stealth import stealth_sync

with sync_playwright() as p:
    browser = p.chromium.launch(
        headless=True,
        proxy={"server": "http://gate.sparkproxy.io:10000",
               "username": "user", "password": "pass"},
    )
    context = browser.new_context(
        viewport={"width": 1366, "height": 768},
        locale="en-US",
        timezone_id="Europe/London",   # match the proxy's country
    )
    page = context.new_page()
    stealth_sync(page)                 # hides navigator.webdriver and headless tells

    # Homepage first so the reese84 / ___utmvc script runs and sets the cookie chain
    page.goto("https://example.com/", wait_until="networkidle")
    page.goto("https://example.com/catalog", wait_until="networkidle")
    html = page.content()
    browser.close()

Two details matter. The first goto hits the homepage so the sensor can set a legitimate visid_incap / incap_ses / reese84 chain before you request the deep page, exactly as a human's browser would. And the viewport, locale, and timezone are set to consistent, human values instead of the headless defaults (800x600, UTC) that Imperva scores as robotic. If you're on Puppeteer, the same proxy-and-stealth pattern applies.

A real browser is heavier than an HTTP client. Run one only for targets that genuinely challenge you, and reserve lightweight clients for everything else.


Match your TLS and HTTP/2 fingerprint

When a target only serves the legacy UTMVC challenge or scores just the network and header layers, you can sometimes skip the full browser. The request still has to survive TLS fingerprinting. Python's requests rides on urllib3, whose TLS Client Hello matches no browser on earth. Imperva computes a JA3/JA4 hash from that handshake and sees "Python," no matter what User-Agent you set.

The fix is curl_cffi, which impersonates a real browser's TLS stack and HTTP/2 profile:

from curl_cffi import requests as cffi

session = cffi.Session(impersonate="chrome124")   # real Chrome TLS + HTTP/2
session.proxies = {
    "http":  "http://user:pass@gate.sparkproxy.io:10000",
    "https": "http://user:pass@gate.sparkproxy.io:10000",
}

resp = session.get("https://example.com/catalog")
print(resp.status_code)          # 200 only if the fingerprint and IP hold up

impersonate="chrome124" sends Chrome 124's exact cipher suites, extensions, and HTTP/2 settings, so the JA3/JA4 hash and the User-Agent finally tell the same story. That consistency is the whole point. The proxy-block avoidance guide walks the layers one by one, and the async scraping with requests and aiohttp guide covers doing this at volume.

Be honest with yourself about which path a target needs. If Imperva serves a reese84 interstitial, no TLS trick alone will clear it. That's a job for a real browser or a rendering API.


Use residential IPs with clean reputation

IP reputation is the fastest way to earn an instant "Incapsula incident ID" 403. Requests from well-known datacenter ASNs (AWS, GCP, Azure, OVH, Hetzner) start with a heavy suspicion penalty, because almost no ordinary shopper browses from an AWS IP. You can have a perfect browser fingerprint and still get blocked purely on the exit address.

Residential and mobile proxies route through real consumer ISPs and carrier networks, so the exit IP carries the reputation of an ordinary home or phone connection. That single change often turns a reliable 403 into a 200. If you're new to the IP families and when each fits, the residential proxy explainer breaks it down.

Two rules keep a good IP good:

  • One session, one IP. Bind the whole cookie chain to the exit IP that earned it. Don't replay the same reese84 across a rotating pool; that token-to-IP mismatch is exactly what Imperva flags.
  • Geo-match the audience. If you're scraping a UK retailer, exit from a UK residential IP. A Vietnamese IP hitting a UK-only storefront is an easy anomaly.

Residential IPs are not a standalone bypass. They clear the reputation layer, but the fingerprint and behavior layers still have to pass. Pair a clean IP with a real browser or a matched TLS fingerprint, never one alone.


Pace and behave like a human

Behavioral scoring is the layer people forget, and it's the one Advanced Bot Protection leans on hardest. Even with a flawless fingerprint and a residential IP, ten requests per second from one session reads as a machine. Imperva watches cadence and navigation shape, so a scraper that acts like a browsing human survives far longer.

  • Warm up. Load the homepage first and let the sensor set the cookie chain before you request deep pages. Deep-linking straight to a product URL with no cookies is a classic bot pattern.
  • Add jittered delays. Random pauses between requests beat a fixed interval, because a perfectly regular heartbeat is itself robotic.
  • Cap concurrency per IP. A handful of parallel requests per exit IP, not hundreds. Spread load across the pool.
  • Follow a plausible path. Category, then listing, then detail. Real users don't teleport across a hundred unrelated URLs in a minute.
import random, time

def polite_delay(lo=2.0, hi=6.0):
    """Jittered pause so request cadence doesn't read as a machine."""
    time.sleep(random.uniform(lo, hi))

If the site publishes a Crawl-delay in robots.txt, treat it as a hard floor, not a suggestion. Slower crawling costs you throughput today and saves you from a blanket ban tomorrow. It's the cheapest anti-detection technique there is, and the most ethical.


Bypass Imperva with the SparkProxy Scraping API

Maintaining a real browser farm, a residential pool, current TLS fingerprints, a reese84-capable renderer, and behavioral pacing is a standing engineering job, because Imperva keeps moving. A scraping API collapses those layers into request parameters and keeps them current on the provider's side. The scraping API vs self-managed proxies comparison covers when that trade is worth it; for a hard target like Imperva, it usually is.

The SparkProxy Scraping API takes a target URL and handles the proxy, the real browser render, and the anti-bot layers for you. Each parameter maps to one of the detection layers above:

curl -G "https://scrape.sparkproxy.io/api/v1" \
  -H "X-API-Key: YOUR_API_KEY" \
  --data-urlencode "url=https://example.com/catalog" \
  --data-urlencode "render_js=true" \
  --data-urlencode "premium_proxy=true" \
  --data-urlencode "country_code=GB" \
  --data-urlencode "stealth=true" \
  --data-urlencode "wait_for=.product-list" \
  --data-urlencode "json_response=true"

The same request in Python, with each flag annotated by the layer it satisfies:

import requests

def fetch(url):
    r = requests.get(
        "https://scrape.sparkproxy.io/api/v1",
        headers={"X-API-Key": "YOUR_API_KEY"},
        params={
            "url": url,
            "render_js": "true",        # real Chromium runs the reese84 / ___utmvc script
            "premium_proxy": "true",     # residential exit, not a flagged datacenter ASN
            "country_code": "GB",         # geo-match the site's expected audience
            "stealth": "true",            # homepage pre-warm, forced referrer, idle delays
            "wait_for": ".product-list",  # wait past the interstitial until content renders
            "json_response": "true",      # envelope with status_code + metadata
        },
        timeout=120,
    )
    return r.json()

render_js=true runs a genuine browser so the JavaScript sensor executes and any interstitial resolves into a valid cookie chain. premium_proxy=true routes through a residential IP, clearing the reputation layer that produces most "incident ID" blocks. stealth=true adds a homepage pre-warm, a forced Google referrer, and extended idle delays, which is the behavioral layer handled for you. wait_for holds until your real content appears, so you don't capture an Imperva interstitial or a decoy 200 by mistake. With json_response=true, the reply is an envelope carrying status_code, credits_used, and a result_url you fetch for the rendered body. On the SparkProxy price sheet, a residential request with JS rendering costs 25 credits, and stealth plus country_code add 5 credits each, so turn them on for hard targets and leave them off for easy ones.


A retry loop that reads Imperva signals

Tie it together with a loop that branches on the decoded status instead of blindly retrying. With json_response=true, the envelope's status_code mirrors what the target returned, so you can act on a 403, a 429, or a 530 differently.

import time
import requests

API = "https://scrape.sparkproxy.io/api/v1"
KEY = "YOUR_API_KEY"

def scrape(url, max_tries=4):
    params = {
        "url": url,
        "render_js": "true",
        "premium_proxy": "true",
        "country_code": "GB",
        "stealth": "true",
        "json_response": "true",
    }
    for attempt in range(1, max_tries + 1):
        env = requests.get(API, headers={"X-API-Key": KEY},
                           params=params, timeout=120).json()
        code = env.get("status_code")

        if code == 200:
            body = requests.get(env["result_url"], headers={"X-API-Key": KEY})
            return body.text                  # rendered HTML, past Imperva

        if code == 429:                       # rate limited: exponential backoff
            time.sleep(2 ** attempt)
            continue

        if code in (403, 530):                # blocked or scrape failed: retry, already max-stealth
            time.sleep(1.5 * attempt)
            continue

        raise RuntimeError(f"Unexpected Imperva status {code} for {url}")

    raise RuntimeError(f"Gave up on {url} after {max_tries} tries")

The loop already runs with premium proxy and stealth on, so a 403 retry gets a fresh residential IP and a new browser session rather than the same doomed request. A 429 backs off exponentially instead of hammering the origin. A 530 (the API's "all upstream attempts failed" code) gets a short, growing pause. When nothing clears after a few tries, the honest move is to stop, respect the site's signal, and revisit whether the data is worth pursuing at all. Watch for the decoy 200 too: if the returned body has the shape of a block page (an incident ID string, a sensor script, no real records), handle it like a 403 rather than trusting the status line.


Frequently asked questions

FAQ

Scraping public data is broadly permitted in many jurisdictions, but "bypassing Imperva" grants no legal exemption. Legality depends on what you collect and how: stay on public pages, honor robots.txt and the site's Terms of Service, avoid personal data, and never touch content behind a login. When in doubt, get written permission or use the site's official API.

Because two layers give it away at once. Python's requests sends a TLS fingerprint (JA3/JA4) that matches no real browser, and scripts usually run from a datacenter IP that Imperva bot detection already distrusts. The mismatch between a browser-like User-Agent and a Python TLS handshake, combined with a flagged ASN, is enough for an immediate 403 with an Incapsula incident ID.

The visid_incap_ cookie is Imperva's persistent visitor identifier for one protected site, valid for about a year. You can persist it to look like a returning visitor, but don't replay one visid_incap cookie across many exit IPs. The same identifier arriving from dozens of addresses is a pattern Imperva flags, so bind it to the session and IP that earned it.

reese84 is the encrypted token from Imperva's Advanced Bot Protection sensor. A client-side script collects 180+ browser signals, POSTs them, and the server returns the token, which later requests must carry and refresh. It can only be produced by running the sensor in a real browser, so a bare HTTP client cannot mint a valid one.

Sometimes, for targets that only serve the legacy UTMVC challenge or score just the network and header layers. Pairing curl_cffi (with impersonate="chrome124") and a residential IP can pass those. But when Imperva serves the reese84 interstitial, there's no runtime to answer it without a real browser or a rendering API, so a bare HTTP client stalls on the challenge.

Look for three tells. The X-Iinfo response header (a four-segment debug code) is present on Imperva traffic even on successful responses. Blocks return "Request unsuccessful. Incapsula incident ID" in the body. And the cookie set includes visid_incap_ and incap_ses__, with a reese84 cookie when Advanced Bot Protection is on.


Limited-time · 50% off

Get 50% off your first purchase

Premium datacentre proxies with unlimited bandwidth. Use the code at checkout.

Offer ends soon — claim it before it's gone

Claim Discount

About the Author

This guide was written by the SparkProxy Technical Team. SparkProxy builds and operates global datacenter and residential proxy networks plus a managed Scraping API, so we see how anti-bot systems like Imperva score traffic from both sides of the request every day. The patterns here reflect current behavior validated against Playwright, playwright-stealth, curl_cffi 0.7+, and the SparkProxy Scraping API as of July 2026. Our aim is a straight, ethical explanation of how Imperva and Incapsula work and how to collect public data without abusing anyone's infrastructure, not a promise of a permanent bypass, because no such thing exists.

Citations: curl_cffi, browser TLS impersonation for Python · Imperva Advanced Bot Protection · SparkProxy Scraping API documentation

Keep reading

Related articles