Imperva Incapsula bot detection: the ___utmvc cookie and reese84 token
Load a protected ticketing site through a fresh browser profile and watch the cookie jar fill. Within a second or two you have a visid_incap_… cookie, one or more incap_ses_… cookies, sometimes an nlbi_…, and depending on which generation of the defense the site runs, either a reese84 value or a short-lived ___utmvc. None of them are session cookies in the way a login cookie is. They are the externally visible residue of a decision Imperva’s edge has been making about you since the connection’s first byte: human, good bot, or something to challenge.
The interesting question is not what these cookies are called. It is what each one is responsible for, which layer of the defense issues it, and why removing or transplanting any single one tends to collapse the whole chain. The honest caveat up front: Imperva does not publish the byte layout of these values. The ___utmvc cookie is RC4-encrypted with a key pulled from the page’s own script, and the reese84 token is an opaque signed blob. Anyone claiming an exact field map is reading deobfuscated script or observed traffic, not vendor documentation. This post sticks to what is knowable from primary sources and says “inferred” wherever a claim rests on traffic rather than docs.
The sections below walk it roughly in chronological order of how the product grew. First the company history, because “Incapsula” and “Imperva” and “Distil” are three names for overlapping things and the naming matters. Then the session cookies that predate any bot logic. Then the older ___utmvc JavaScript challenge and its RC4 cookie. Then the reese84 sensor that replaced it on the harder sites. Then how the layers stack, and what a well-formed cookie chain looks like versus one the edge rejects.
Incapsula, Imperva, Distil: who is who
The naming confuses people for a reason. Incapsula started as a standalone cloud security and CDN company. Imperva, a web application firewall vendor, acquired it and folded the cloud WAF into its product line, so “Incapsula” became “Imperva Cloud WAF” while the underlying cookie names and edge behavior carried forward unchanged. That is why you still see incap_ses and visid_incap (the incap is Incapsula) on sites that have never heard the word Incapsula in years. The prefixes are archaeological.
The bot-specific machinery has a separate lineage. On June 4, 2019, Imperva announced it would acquire Distil Networks, which it described as “the global leader in Bot Management,” a company Forrester had named a leader in its 2018 New Wave on bot management. Distil’s classification engine, the part that sorts traffic into human, desirable bot like a search crawler, and malicious bot like a credential stuffer or scalper, became the core of what Imperva now sells as Advanced Bot Protection. So the modern stack is two acquisitions deep: a CDN and WAF edge inherited from Incapsula, with a bot-classification brain inherited from Distil bolted onto it.
This history is not trivia. It explains why the defense has layers that feel like they were designed by different teams, because they were. The cookie-and-session layer is old Incapsula plumbing. The fingerprinting and behavioral scoring is the Distil lineage. The ___utmvc challenge is the older interrogation; the reese84 sensor is the newer one. When you see all of them on one site, you are looking at strata.
The session cookies that come before any bot logic
Before any challenge runs, the Imperva edge plants a couple of cookies just to track the connection. These are the oldest part of the stack and the least secret. You will see them on protected sites that run no JavaScript challenge at all.
visid_incap_<siteID> is the visitor identifier. The <siteID> suffix is the numeric Incapsula site ID for the protected origin, so a visitor hitting two protected properties carries two distinct visid_incap cookies, one per site. It persists across sessions, which is what makes it a visitor ID rather than a session ID. Treat its internal encoding as opaque; the value is base64-looking but Imperva does not document what is packed inside it, and any decode you see online is reverse-engineered.
incap_ses_<num>_<siteID> is the session cookie. The <siteID> again binds it to one protected site; the <num> segment is an internal session-slot index that varies. This one is not persistent. It tracks a single browsing session and is the cookie most likely to be rotated mid-flight by the edge. When people report that an Imperva session “expired and started re-challenging,” the incap_ses value rotating out from under them is usually what they are seeing.
Two more show up in captures. nlbi_<siteID> is a load-balancer cookie; the nlbi is widely read as “network load balancing info,” used by the edge to pin a session to a backend. And incap_sh_<…> cookies appear specifically after the ___utmvc challenge flow completes, which is a useful tell for which challenge generation a site is running. The precise role of nlbi and incap_sh is not in Imperva’s published documentation, so take those descriptions as inferred from observed traffic and third-party glossaries rather than vendor-confirmed.
The thing to hold onto: all of these cookies carry the site ID. They are scoped to one protected property. You cannot lift a visid_incap from site A and present it to site B; the suffix alone makes it nonsense to the edge, and that is before any signature check. The session layer is per-site by construction.
There is a second reason the site ID matters, and it is operational rather than cryptographic. Imperva runs these cookies as first-party state from the protected origin’s own domain, not from a third-party tracking domain. The point came up publicly when Chromium changed its default handling of the SameSite cookie attribute and Imperva had to publish guidance on how its own cookies behaved under the new default. That episode is a small confirmation of something easy to forget: the incap cookies are not analytics. They are the edge’s working memory about your session, set first-party so they ride along on every same-site request without a cross-site exemption. A browser configured to block third-party cookies does not lose them, which is exactly what a defense wants from its session state.
It is worth separating the two jobs these cookies do, because people collapse them. visid_incap answers “have I seen this visitor before, across sessions and over time.” incap_ses answers “is this the same continuous session I was just talking to.” The first is the anchor the behavioral scoring hangs history on; a visitor who shows up clean for a week and then starts hammering an endpoint is legible only because the visitor ID tied the two phases together. The second is the freshness check; a session cookie that has rotated means the conversation restarted and the edge wants to re-confirm. Lose the visitor cookie and you throw away your reputation. Lose or desync the session cookie and you trigger a re-handshake. They fail differently, and recognizing which one is gone tells you which part of the system just stopped trusting you.
The ___utmvc cookie: an RC4-encrypted interrogation
The ___utmvc cookie (three leading underscores) is the visible output of Imperva’s older JavaScript interrogation challenge. The pattern is the one every JS anti-bot uses. The server withholds the real page, ships an obfuscated script instead, the script runs and collects a fingerprint, and the result gets posted back. Pass, and you are let through with a fresh cookie. Fail or never run the script, and you loop.
What makes ___utmvc worth studying is how its production is wired. The script arrives via a GET to a path under /_Incapsula_Resource, delivered as an immediately-invoked function expression wrapping a hex-encoded payload that decodes itself with String.fromCharCode and base-16 parseInt. Underneath that first layer is a script obfuscated in the obfuscator.io style: hex \x string escapes, mangled hex variable names, and a shuffled string array whose entries are RC4-encrypted. The script reconstitutes its own strings at runtime by calling an RC4 decoder, keyed on a value embedded in the script itself, after a base64 decode step. The deobfuscation write-up that documents this calls out the decoder being reached through a generated accessor function and an array-rotation IIFE seeded with a magic number that restores the array’s order before any string can be read.
The fingerprint the script gathers is the usual interrogation surface: properties off window, navigator, and document, run through encodeURIComponent before transport. The collected blob is RC4-encrypted and that ciphertext becomes the ___utmvc cookie value. The decryption key is short, a five-character value extracted from the obfuscated script itself, which is the detail that makes the whole thing tractable to analysts. Because the key ships in the page, the cookie is not really “encrypted” in any secrecy sense; the RC4 layer is obfuscation to raise the cost of casual inspection, not a cryptographic secret. The cookie is then submitted in a POST back to the _Incapsula_Resource endpoint, and a passing response sets the ___utmvc along with the incap_sh_<…> markers that flag the challenge as solved.
Worth being precise about what RC4 buys the defender here. Nothing cryptographic. The key is in the script, so anyone who deobfuscates the script can both produce and read the cookie. What RC4 plus the shuffled-array obfuscation buys is time: it raises the per-site cost of figuring out which collected fields go where and in what order, and Imperva rotates the script and its keys, so the work is perishable. This is the same logic behind every obfuscated client agent. The mechanism is documented in deobfuscation write-ups precisely because the secret is not the algorithm, it is the constantly-moving layout. For the cousin systems that take obfuscation further into a bytecode VM rather than plain RC4 strings, the Kasada KPSDK breakdown is a useful contrast.
It helps to be concrete about why the obfuscation is layered the way it is. The outer hex-encoded IIFE exists to defeat a casual reader and any static scanner that greps for plaintext strings; nothing meaningful is readable until that layer self-decodes at runtime. The inner obfuscator.io pass exists to defeat the next reader, the one who got past the first layer and now faces variables named in hex and strings that are not where they appear to be. The shuffled string array is the clever part: the array literal as it ships is in the wrong order, and an immediately-invoked function rotates it a fixed number of times before any code reads from it, so an analyst who dumps the array statically gets garbage indices. Only after the rotation runs do the index lookups line up with the right ciphertexts, and only then does the RC4 decoder turn those ciphertexts into the method and property names the script actually uses. Each layer is cheap for the browser to undo and expensive for a human to undo by hand. That asymmetry, cheap to execute and costly to read, is the entire point of client-side obfuscation, and it is why the analysis has to be redone every time Imperva reships the script.
A subtle consequence: because the script collects from window, navigator, and document and then runs the result through encodeURIComponent before encryption, the order and exact set of properties read is itself part of what the server can check. The server is not only verifying that you produced a decryptable cookie. It is verifying that the cookie decrypts to a fingerprint shaped the way a real run of this exact script on a real browser would produce. A reimplementation that collects the right fields but in the wrong order, or that fills in a property the real browser would have left undefined, produces a cookie that decrypts cleanly and still fails the grade. This is why “I RC4-encrypted some plausible fields” never works for long. The encryption is the easy half; matching the precise collected shape is the hard half, and it is the half Imperva keeps moving.
The reese84 token: the newer sensor
On the harder sites, the ticketing and high-value retail properties where Distil’s lineage earns its keep, you will not see ___utmvc. You will see reese84. This is the newer interrogation, and it behaves differently enough to be worth treating as its own system.
The reese84 script lives at a per-site path, a path unique to each domain rather than the shared /_Incapsula_Resource route, which is the first thing that distinguishes it. The path is stable for a given site once you find it. The flow has a recognizable signature: the client POSTs its collected sensor to that path with a ?d=<domain> query parameter appended, sending the body as Content-Type: text/plain; charset=utf-8. That ?d= POST is the single most reliable on-the-wire tell that you are looking at reese84 rather than the older challenge.
The response is not a cookie directly. It is JSON. The documented shape carries a token field, a renewInSec field, and a cookieDomain field. The token is the long opaque string, with a leading version-like prefix (write-ups show values shaped like 3:...). The client then stores that token in the reese84 cookie, scoped to the cookieDomain the server named. The renewInSec value is the lifetime in seconds, after which the token must be regenerated, so a long-lived session is not “get one cookie and keep it,” it is “re-run the sensor before renewInSec elapses or get re-challenged.” That renewal cadence is structurally different from the one-shot ___utmvc pass, and it is why naive automation that grabs a cookie once tends to die a few minutes in.
What does the sensor collect before it posts? Imperva does not publish the field list, and the documentation I could verify is explicit that the sensor body is opaque, you submit the collected blob and get a token. What is consistently reported across analyses is that the interrogation surface is the standard high-entropy browser set: canvas rendering, WebGL parameters, AudioContext, the navigator object, font enumeration, and screen properties, gathered into a large set of encrypted values. I will not put a precise count on it because the numbers floating around (often cited as 100-plus or 180-plus values) come from third-party reverse-engineering rather than vendor docs, and they drift as Imperva updates the sensor. The honest statement is that the sensor collects a broad device fingerprint plus environment checks, encrypts it, and the server grades it. The exact field layout is not public. For what the obfuscated reese84 payload is understood to collect in more depth, see the reese84 sensor write-up.
The server side is where the Distil lineage shows. Imperva markets Advanced Bot Protection as combining direct client interrogation (the sensor) with behavior analysis, machine learning, connection characteristics, and threat-intelligence feeds, claiming to read “over 700 dimensions” to build a fingerprint and to cover “all OWASP Automated Threats,” the OWASP set of 21 automated-threat categories. So the reese84 token you carry is not the whole verdict. It is the client-interrogation slice of a score the edge also feeds with how you connected and how you behave over time.
The renewal clock deserves a second look, because it changes the shape of the problem from a one-time puzzle into a sustained one. With ___utmvc, the model is roughly “prove yourself once, then carry the cookie.” With reese84 and its renewInSec, the model is “prove yourself, and keep proving yourself on a clock.” Every renewal is a fresh sensor run, which means a fresh, current fingerprint and a fresh chance for the server to notice that the environment minting the token does not behave like a browser kept alive across that interval. A real browser session accumulates small, consistent changes between renewals: timers advance, the page has been scrolled, focus and blur events have fired. A headless or reimplemented client that snapshots the same static fingerprint at each renewal is presenting a session that never aged, and a session that never ages is itself a signal. The clock is not just an expiry. It is a periodic re-interrogation that the defender gets for free.
Imperva also offers the reese84 sensor on native mobile, not only in the browser, which is a useful reminder that the token is not fundamentally tied to a DOM. The collection surface differs (a mobile SDK reads device and OS signals rather than canvas and WebGL), but the contract is the same: collect an environment fingerprint, post it, receive a signed token, present the token on subsequent requests. The shared shape across web and mobile is the clearest sign that the token is a verdict envelope, not a browser artifact. The browser specifics are inputs to the grade, not the grade itself.
How the network layer feeds the verdict
The cookies are the top of the stack, but Imperva starts scoring you before any JavaScript runs, before the first cookie is even set. The connection itself is a signal. The TLS ClientHello, the HTTP/2 settings, the ordering of headers, all of it is fingerprinted at the edge and folds into the same verdict the sensor later refines. This is the “connection characteristics” line in Imperva’s own description of the product, and it is the layer that catches a client whose cookies are immaculate but whose TLS stack screams “this is a Go HTTP client” or “this is requests behind a proxy.”
This matters for understanding the cookie chain because it sets a constraint the cookies cannot fix. A transplanted, perfectly valid reese84 presented over a TLS fingerprint that does not match the browser that minted it is a contradiction the edge can see. The token says “I am Chrome 124 on macOS”; the ClientHello says otherwise. The Distil-lineage scoring is built to notice exactly that kind of mismatch across layers. If you want the mechanics of how a ClientHello becomes a stable hash, the JA3-to-JA4 walkthrough covers the fingerprinting side that sits underneath all of this.
So the practical model is a funnel. Network fingerprint first, cheaply, on every connection. Then the cookie chain, checked on every request. Then, where the chain is missing or stale, the JavaScript interrogation that mints ___utmvc or reese84. Then behavioral scoring layered over the session’s lifetime. Each layer can demote you. Passing one does not clear the others.
The chain, and why one stale cookie breaks it
Put the pieces in order and the design intent is clear: Imperva wants several independent things to agree about you, and it issues a cookie at each checkpoint so the edge can re-verify cheaply on every subsequent hit rather than re-running expensive interrogation each time.
The chain on a hard site looks roughly like this. The network fingerprint is taken at connect. The session pair, visid_incap and incap_ses, is set early and pins you to a visitor and a session, both suffixed with the site ID. The nlbi load-balancer cookie keeps you on a consistent backend. Then the interrogation cookie, ___utmvc on older sites or reese84 on newer ones, carries the client-fingerprint verdict. On the reese84 path the cookie even has a built-in expiry via renewInSec, so the freshness of the verdict is enforced, not assumed.
The reason a single bad cookie collapses the whole thing is consistency checking across the set, not the value of any one cookie in isolation. The cookies are bound together: each carries the site ID, the session cookie is tied to the visitor cookie, and the interrogation cookie is supposed to have been minted within that same session context. A reese84 that is valid but was generated in a different session, or a ___utmvc present while the incap_ses it should belong to is missing, is an internal contradiction. The edge does not need to crack the cookie to reject it; it just needs to notice the set does not cohere. Manually editing any of these values produces the same result for the same reason, you turn a coherent set into an incoherent one.
This is the same structural lesson that shows up across the whole anti-bot category. The defense does not bet on one secret. It distributes the verdict across the network fingerprint, the session cookies, the interrogation cookie, and the behavioral score, and then checks that they all tell the same story. Akamai does it with _abck and bm_sz (covered here); DataDome does it with its cookie lifecycle; Imperva does it with the incap/reese84 chain. The cookie names differ. The architecture rhymes.
The tells: headers and the block page
There is a layer beneath the cookies that is easy to read and worth knowing, because it is how you confirm a site is Imperva at all. Protected responses tend to carry an X-Iinfo header, an Imperva-specific value, and an X-CDN header whose value names Incapsula or Imperva. The HTML of a challenge or block page references the _Incapsula_Resource path. None of these are secrets and none of them are the defense; they are just the fingerprint of the edge itself. If you are diagnosing a failing request and you see X-Iinfo on a 403, you know which system is talking to you and which cookie chain it expects.
The block experience itself escalates. The mildest response is a silent re-challenge: the edge withholds the page and serves the interrogation script again, betting you simply lack a current cookie. Above that is an interactive challenge. On the harder configurations, particularly the ticketing properties, the reese84 and ___utmvc flows can be paired with a third-party visual CAPTCHA, and on the variants documented by integration vendors the challenge demands a solved GeeTest token before it will issue cookies. That pairing matters for the mental model: the cookie chain is the steady-state proof, and the CAPTCHA is the escalation Imperva reaches for when the steady-state proof is missing or the behavioral score has soured. For the broader history of how visual challenges got bolted onto bot defenses like this, the history of CAPTCHA gives the long view.
Behavioral scoring is the part that has no cookie of its own and is therefore the hardest to reason about from the outside. Imperva’s own description of the product names “behavior analysis” alongside the interrogation, and the Distil lineage was built precisely on watching sessions over time rather than judging single requests. What this means in practice is that two clients can carry an identical, valid cookie chain and be scored differently because of what they did with it: request rate, the order pages are fetched in, whether mouse and keyboard and scroll events accompany the navigations, whether the timing between actions has the jitter of a human or the metronome of a loop. None of this is in the cookies. It accumulates server-side, anchored to the persistent visid_incap visitor ID, which is why that cookie is the one you least want to rotate. Rotate it and you discard the very history that might have been vouching for you, and you start over as an unknown.
What this looks like in 2026
The current state worth pinning down. The Incapsula name is fully retired into “Imperva Cloud WAF,” and after Imperva itself moved under Thales, the documentation now lives on Thales-hosted portals, which is why the old docs.imperva.com links redirect to docs-cybersec.thalesgroup.com. The cookie prefixes have not changed; visid_incap and incap_ses still carry the Incapsula heritage in their names a decade on. On the bot side, Imperva positions Advanced Bot Protection around the Distil-lineage multi-layer model and has been extending it toward classifying agentic-AI traffic, the newer line of “is this an LLM agent” on top of the older “is this a scraper” question.
The two interrogation cookies still coexist by site. Older or lower-risk properties run the ___utmvc RC4 challenge through /_Incapsula_Resource; the harder targets run the reese84 sensor on a per-site path with the ?d= POST and the renewInSec renewal clock. If you are trying to tell at a glance which generation a site runs, the cookie name is the answer, and the request signature confirms it: a POST to /_Incapsula_Resource versus a text/plain POST to a site-specific path with a domain query parameter.
None of the encryption here is a real secret, and that is the part most worth sitting with. The ___utmvc cookie’s RC4 key ships in the page; the reese84 sensor is obfuscated but observable. What the system actually leans on is not cryptographic secrecy but cross-layer consistency: a network fingerprint, a per-site session pair, and a freshly-minted interrogation verdict that all have to describe the same browser in the same session at the same moment. The cookies are cheap to read and expensive to fake in agreement. That is the whole design, and it is why a stolen cookie that looks perfect in isolation is usually the easiest kind of request for the edge to throw away.
Sources & further reading
- Imperva (2019), Imperva to Acquire Distil Networks, the Leader in Bot Management — the June 4, 2019 announcement, with Forrester’s 2018 bot-management leader citation; the origin of the modern bot-classification engine.
- Imperva (2026), Advanced Bot Protection — vendor product page describing the multi-layer model: client interrogation, behavior analysis, ML, connection characteristics, the “700 dimensions” claim, and OWASP-21 coverage.
- yoghurtbot (2023), Deobfuscating Incapsula’s ___utmvc Anti-Bot Script, Part 1 — researcher walkthrough of the obfuscator.io layering, the RC4 string decoder, the array-rotation IIFE, and the
_Incapsula_Resourcedelivery. - glizzykingdreko (n.d.), incapsula-___utmvc-cookie-decryptor — tool and notes documenting the RC4 encryption of
___utmvcand the five-character key extracted from the page script. - Hyper Solutions (2026), Reese84 — API documentation describing the per-site script path, the
?d=sensor POST, thetext/plainbody, and the JSON response fieldstoken,renewInSec, andcookieDomain. - Scrapfly (2026), How to Bypass Imperva Incapsula when Web Scraping — overview confirming the
incap_ses/visid_incapcookies, theX-IinfoandX-CDNheaders, the_Incapsula_Resourcekeyword, and the JS-fingerprinting surface (canvas, WebGL, audio). - TakionAPI (2026), Incapsula / Imperva — notes distinguishing the
reese84and___utmvcchallenge variants and theincap_sh_xxxcookies set by the___utmvcflow. - Imperva Cyber Community (2020), Imperva Product Updates: Chromium SameSite Cookie Attribute Update — vendor post on how the SameSite change affected Imperva’s own cookies, confirming the cookie family is first-party edge state.
- MSSP Alert (2019), Imperva Acquires Distil to Battle Bot Network Cyberattacks — independent coverage of the acquisition and Distil’s bot-management positioning.
- Thales / Imperva (2026), Cloud WAF / Advanced Bot Protection documentation — current documentation home after the Thales transition, where the former
docs.imperva.comcontent now redirects.
Further reading
The DataDome cookie lifecycle: token issuance, rotation, and validation
Traces the datadome cookie end to end: how it is issued after a challenge, what the 128-byte token encodes, when it rotates, how long it lives, and how the edge validates it on every request through the Protection API.
·22 min readAkamai's bm_sz cookie and pixel challenge: the second layer most clients miss
Traces the bm_sz cookie, the pixel challenge that mints ak_bmsc, and the sec-cpt proof-of-work interstitial that sits alongside _abck, and why a client that only validates _abck still gets challenged or dropped.
·22 min readCloudflare's cf_clearance cookie: issuance, scope, and lifetime
A reference on Cloudflare's cf_clearance cookie: when a passed challenge issues it, what it is bound to, its zone scope and partitioned cross-site behaviour, its configurable lifetime, and why a stolen copy does not travel.
·18 min read