Skip to content

Akamai Bot Manager's _abck cookie: structure, sensor data, and the validation handshake

· 21 min read
Copyright: MIT
The string _abck rendered as a monospace wordmark with one tilde-zero segment highlighted in orange

Open the network panel on almost any large airline, retailer, or ticketing site and you will find a cookie named _abck. It is long, it looks like noise, and it is the single most load-bearing piece of state Akamai Bot Manager keeps in your browser. Strip it out and the next request gets challenged or dropped. Keep a stale one and you get the same result. The cookie is not a session token in the ordinary sense. It is a running summary of what Akamai’s client-side sensor has decided about you, packed into a value the edge can re-check on every hit.

So what is actually inside it? The short answer is that the full byte layout of _abck is not publicly documented by Akamai, and anyone who tells you they have the exact field map is either reading observed traffic or reading a leaked deobfuscation of the sensor script. What is knowable, and what this post sticks to, is the externally observable behaviour: the segments the value is split into, the tilde-delimited markers that flip between a “challenge me” and a “validated” state, the POST of sensor_data that drives those flips, and the order the handshake runs in. Where a claim rests on observed traffic rather than vendor documentation, I say so.

The sections below walk it in order. First the cookie’s place in Akamai’s cookie family and the request that first sets it. Then the visible structure of the value and the tilde markers people key off. Then the sensor_data POST that the cookie is a response to, including what changed between the version 2 and version 3 sensor formats. Then the handshake itself as a state machine, the second-layer sec-cpt and sbsd challenges that sit beside it, and finally what separates a well-formed _abck from one the edge will reject.

Akamai Bot Manager does not rely on one cookie. It sets a small cluster, and _abck only makes sense alongside its neighbours. The two that matter most for the handshake are bm_sz and _abck itself; the others are bookkeeping.

bm_sz is set first, usually on the very first HTML response from a protected origin, before any JavaScript has run. It carries what one write-up calls “initial sizing/configuration data,” and it is the seed the sensor script needs before it can produce a payload. In the version 3 sensor format, a hash derived from the bm_sz value is used to seed the character-substitution step of the encryption, so the value of bm_sz is not just a session label. It is an input to how the next sensor_data blob gets encoded. That coupling is the reason you cannot generate a valid sensor for site A using a bm_sz captured from site B or from an expired session.

_abck is the validation token proper. The Hyper Solutions documentation describes it plainly as Akamai’s “Primary bot detection validation token,” persistent, and typically set to expire after about a year. The long expiry is misleading. The cookie persists for a year, but the validated state encoded inside it lapses far sooner, which is why a browser that sat idle will quietly re-collect and re-POST sensor data when it wakes up. The persistence is the storage envelope; the trust inside it is perishable.

Round it out with the supporting set that shows up in captures: ak_bmsc (HTTP-only, tied to bot scoring), bm_sv, and bm_mi. These appear in observed traffic and in third-party glossaries rather than in published Akamai field documentation, so treat their exact roles as inferred. For the handshake we care about here, bm_sz going in and _abck coming back are the two ends of the wire.

It is worth being precise about the direction of dependence, because it is easy to get backwards. bm_sz is not derived from _abck; the relationship runs the other way. The server seeds bm_sz independently, the client reads it, the client uses it to encode the sensor payload, and only then does the server respond with an updated _abck. So a session that loses or rotates bm_sz mid-flight does not just lose a label, it loses the input the next sensor payload needs to be encoded correctly, and the _abck that comes back will reflect a payload Akamai cannot line up. The two cookies are not interchangeable and they are not symmetric. One is an input to the encoding; the other is the graded output. Keeping that straight is half of understanding why transplanted cookies fail.

First HTML response sets the seed cookie bm_sz seed + config sensor script runs bmak global object POST {"sensor_data": "..."} _abck Set-Cookie on the POST response updates _abck state Supporting cookies seen in traffic: ak_bmsc, bm_sv, bm_mi (roles inferred) *The seed cookie comes down first, the sensor script reads it, the POST goes out, and the response rewrites _abck. The supporting cookies are bookkeeping around this core loop.*

What the value actually looks like

A fresh _abck is a long string of base64-ish characters broken up by tilde (~) separators. The segments before the tildes are opaque: encrypted or signed material the client cannot meaningfully read, carrying timestamps, counters, and a signature over the collected signals. The interesting part for anyone tracing the handshake is the tail, where a handful of tilde-delimited numeric fields encode the cookie’s state in a way that is observable without decrypting anything.

This is where you have to be careful about what is documented and what is folklore. Akamai publishes none of this. The tilde markers are known entirely from people watching the cookie change across a request sequence and correlating the change with whether the next request passed. With that caveat stated once and meant throughout, here is the consensus reading of the markers, drawn from multiple independent reverse-engineering write-ups that agree with each other:

A value whose state tail contains ~-1~ is the unsatisfied state. It means a challenge is outstanding and Akamai is waiting for sensor data it has not received yet. This is what you get on the very first response, before any POST. A value showing ~0~-1~ (a zero where the -1 was, with a trailing -1) is the intermediate state: sensor data has been received but not yet judged sufficient. And a value whose tail settles to a state containing ~0~ without the trailing negative is the satisfied state, the one people shorthand as “the cookie went valid.” Hyper Solutions’ own getting-started notes describe it the same way: “A cookie containing ~0~ indicates you can stop posting additional sensors, though not all sites use this indicator.”

That last clause matters. The ~0~ marker is a convention, not a guarantee. Some site configurations never surface a clean ~0~ and instead expect a fixed number of sensor submissions before the protected action. The practical rule people fall back to is to POST sensor data a small number of times (commonly up to three) and proceed, rather than trusting any single marker. Treat the tilde fields as a strong hint about state, not as a documented API.

There is a reason the markers read as numbers rather than as opaque hashes, and it is worth dwelling on. The state tail is the part of the cookie Akamai’s edge logic needs to act on quickly and repeatedly, on every protected request, without decrypting the signed prefix. A negative number means “I am waiting on you,” a zero means “I have what I need,” and the trailing fields carry counters that track how far through the expected sequence the session has progressed. None of that requires the heavy machinery that protects the prefix. The prefix is what binds the cookie to a specific client and prevents forgery; the tail is the cheap, fast status flag the prefix vouches for. Splitting the value this way is what lets a CDN node at the edge make a keep-or-challenge decision in microseconds while still being able, when it wants to, to fall back on the full signed contents.

This also explains why people who only watch the tail sometimes get surprised. Two cookies can show an identical ~0~ tail and behave completely differently, because the tail is a status flag and the prefix is the substance. The status can say “validated” while the substance describes a browser that no longer matches the connection. Reading the tail tells you what state Akamai thinks the handshake is in; it tells you nothing about whether the signed prefix will survive the cross-check. Keep those two questions separate and the cookie stops being mysterious.

A _abck value, split on the tilde separator 8B4F...signed blob...A1 opaque: signature, timestamps, counters ~ state markers ...trailing fields... State tail, read across the handshake (markers are inferred from traffic): ~-1~ challenge outstanding, no sensor received ~0~-1~ sensor received, not yet judged sufficient ~0~ satisfied; client may stop posting (site permitting) *The value is mostly opaque signed material; only the tilde-delimited state tail is human-readable, and even that is read from observed transitions rather than Akamai documentation.*

The sensor_data POST the cookie is answering

The _abck cookie is best understood as a response, not a request. The thing it responds to is a POST whose body is a single JSON object: {"sensor_data": "..."}. That string is the product of Akamai’s client-side script, which exposes itself on the page through a global object conventionally named bmak. The script wires up listeners and probes, gathers a large set of signals, encodes them, and ships the result to an endpoint that is usually the same script URL the page loaded the sensor from. Common challenge-flow endpoints observed in traffic include paths under /_sec/, for example /_sec/cp_challenge/verify. The response to that POST carries Set-Cookie: _abck=..., advancing the cookie’s state.

What goes into the payload is broad. Across reverse-engineering write-ups the signal set is described consistently as device and browser telemetry plus behavioural data: canvas and WebGL fingerprints, the AudioContext signature, screen metrics, timezone, language, the navigator plugin and property set including the navigator.webdriver flag, the exact shape of the window.chrome object, font enumeration, and then the human-movement layer of mouse paths, click timing, and keystroke cadence. The recurring “100+ signals” figure comes from third-party analyses rather than Akamai, so read it as an order-of-magnitude claim, not a precise count. If you want the field-by-field breakdown, our companion piece on the Akamai sensor_data payload goes deeper on the telemetry sources, and the Bot Manager scoring post follows those signals to the bot-score header the origin sees.

The important structural fact for the cookie handshake is the encoding, and here the version matters. The current widely deployed format is the version 3 sensor. Its encryption runs in two stages over a colon-delimited serialization of the collected data. First the elements are shuffled by a pseudo-random number generator seeded with a hash derived from the sensor JavaScript file itself. Then each character is substituted using a second PRNG, and that second PRNG is seeded with a hash derived from a cookie value, typically bm_sz. On the first payload, before a real cookie exists, the implementation uses a default seed (reported as 8888888); once the server has handed back a real bm_sz, subsequent payloads derive their seed from it.

That design has two consequences worth stating plainly. Because one seed comes from the live JavaScript file’s hash, a statically extracted, deobfuscated copy of the script goes stale the moment Akamai ships a new file, which it does often. And because the other seed comes from the session’s own bm_sz, every payload is bound to its session and cannot be replayed into another. The version 3 scheme exists precisely to make per-session binding and script-freshness mandatory, where version 2 was easier to reduce to a static transform. One practitioner write-up on the version 3 format makes the same point: heavy reliance on real-time file hashes is what “complicat[es] static reverse-engineering efforts.”

Version 3 sensor encoding, two PRNG-driven stages collected signals a:b:c:d ... shuffle (PRNG) seed: script-file hash substitute (PRNG) seed: bm_sz-derived hash POST First payload uses default seed 8888888; later payloads derive the seed from the live bm_sz. New script file ships, file hash changes, a statically extracted transform goes stale. Session-bound seed means a payload cannot be replayed into a different session. *The two seeds are the whole point: one ties the payload to the exact script version, the other ties it to the session's own bm_sz.*

The handshake as a state machine

Put the pieces in order and _abck behaves like a small state machine that the client advances by POSTing sensor data and the edge advances by re-issuing the cookie. The sequence, as it appears in observed traffic, runs in three moves.

The first request to a protected origin returns the page along with Set-Cookie for bm_sz and an initial _abck whose state tail sits in the ~-1~ unsatisfied position. At this point the cookie exists but vouches for nothing. The page also pulls in the sensor script. The second move is the client’s: the bmak agent collects its signals, encodes the version 3 payload using the script hash and the freshly received bm_sz, and POSTs {"sensor_data": "..."} to the challenge endpoint. The response carries a new _abck via Set-Cookie, and its state tail advances, typically to the ~0~-1~ intermediate state on the first POST and to the satisfied ~0~ state once Akamai is content. The third move is the protected request itself, carrying both cookies, which the edge validates before letting it through.

Two details make this more than a linear three-step. First, Akamai may demand more than one sensor POST. The documented pattern distinguishes an initial collection (page load, before the user has done anything), a behavioural collection (after some interaction, carrying real movement), and a conditional re-collection if something looks off. Each POST re-issues _abck and nudges its state. Second, the validated state is short-lived relative to the cookie’s year-long persistence, so a long-lived browser session will loop back into sensor collection on its own when the trust window lapses. The cookie you hold can be structurally perfect and still be treated as stale because the state it encodes has aged out.

The edge-side check is cheap by design. The whole reason _abck carries a signed, self-describing state is that the origin’s edge node can validate it without re-running the JavaScript or re-scoring from scratch. A mismatch between what the cookie claims and what the current request’s fingerprint looks like (its TLS signature, its HTTP/2 frame ordering, its IP reputation) is enough to mark the visitor as a bot and demand a fresh challenge. That cross-check is why a valid-looking _abck carried over a mismatched TLS stack fails: the cookie is consistent with itself but not with the connection presenting it. Our TLS fingerprinting piece covers the connection-level half of that comparison.

_abck state transitions (markers inferred from observed traffic) ~-1~ challenge ~0~-1~ received ~0~ validated 1st sensor POST further POST(s) trust window lapses, or fingerprint mismatch, drops back to challenge Edge validates _abck against TLS / HTTP-2 / IP fingerprint on every protected request. *The cookie walks from challenge to validated as sensor POSTs land, and falls back when the trust window ages out or the connection fingerprint stops matching.*

The second layer most clients miss: sec-cpt and sbsd

The clean three-move handshake is the happy path. Akamai also fields harder challenges that sit beside _abck, and a client that handles only the sensor POST will stall on them. The two current ones are the sec-cpt challenge and the newer sbsd.

A sec-cpt challenge announces itself with an HTTP 428 Precondition Required status. The site is saying: solve this before I let you continue. Success is tracked in a separate cookie, sec_cpt, which the documentation describes as reaching a value containing ~3~ once the challenge clears. The response that triggers the 428 carries a provider field naming which of three flows applies. The crypto provider is a proof-of-work with a mandatory, non-skippable wait: the challenge JSON includes fields named chlg_duration, token, nonce, difficulty, and timestamp, and after the wait you submit computed answers and verify at a static /_sec/cp_challenge/verify endpoint. The behavioural provider drops the wait but requires sensor data, posting up to three times to the script endpoint before verifying at a dynamic per-challenge URL. The adaptive provider chains both: wait, submit proof-of-work, then submit sensors. All three converge on the same success signal, sec_cpt carrying ~3~.

sbsd is the more recent addition, described as a challenge built to block scrapers from even reaching the protected HTML. It has its own cookie and its own data generation step, and it sits in front of the content rather than gating a specific action. The relevant point for this post is that _abck does not stand alone. The behavioural and adaptive sec-cpt flows still require _abck to be carried into sensor generation, so the cookie is an input to those challenges even when it is not the thing being graded. If you want the layer that runs before the sensor handshake, the bm_sz cookie and pixel challenge post covers the piece that catches clients which only model _abck.

The takeaway is that “make _abck valid” is necessary but not always sufficient. On a site that has turned on sec-cpt, a perfectly satisfied _abck still meets a 428 until the proof-of-work or behavioural challenge is cleared and sec_cpt shows ~3~. The cookies cooperate; they do not substitute for each other.

Well-formed versus invalid: what the edge actually rejects

Stand back and ask what makes one _abck value acceptable and another not. There are several independent ways to hold an invalid cookie, and they fail for different reasons.

The simplest invalid state is the unsatisfied one. A cookie still showing ~-1~ in its state tail has not been advanced by a sensor POST, so the edge treats it as a pending challenge and re-issues the challenge. There is nothing malformed about it. It just hasn’t done the handshake. Closely related is the deliberately invalidated cookie: a protected endpoint can reset a session by handing back a new _abck whose tail drops back toward the negative state, which is the server’s way of saying “re-prove yourself.” Practitioners note this usually only requires a single fresh sensor POST to recover, because the rest of the session context is intact.

A subtler failure is the structurally well-formed but contextually wrong cookie. The value parses, the state tail says ~0~, and the edge still rejects the request, because the cookie’s signed contents do not match the fingerprint of the connection carrying it. This is the mismatch case: _abck encodes a summary of a browser, and if the TLS ClientHello, the HTTP/2 settings, or the IP reputation of the present request disagree with that summary, the cross-check fails. The cookie is internally valid and externally inconsistent. This is the most common way a replayed or transplanted cookie dies; the value was real once, for a different client. It is also why the version 3 encoding binds the payload to bm_sz and the live script hash in the first place, to make “real once, elsewhere” hard to manufacture.

Then there is the stale-but-persistent cookie. Because the storage envelope lasts a year while the trust inside it lapses in minutes to hours, a long-idle session can present a cookie that is well-formed, was validated, matches its connection, and is still treated as needing re-collection. The structure is fine; the freshness is not. This is the failure mode that confuses people who test by hand: they validate a session, walk away, come back later, replay the exact same cookie, and watch it get challenged. Nothing about the cookie changed. The clock did. The trust window encoded in the prefix aged past its limit, and the edge re-issued the challenge state on the next request, dropping the tail back toward the negative position so the client knows to collect again.

The encoding failure is worth separating out too, because it is specific to the version 3 format. If the sensor payload that produced a given _abck was encoded against the wrong seed, either a bm_sz from a different session or a stale script-file hash from a deobfuscated copy that Akamai has since rotated, the payload itself is malformed from Akamai’s point of view, and the _abck it yields will never advance to a satisfied state no matter how many times it is posted. This is a quieter failure than a mismatch, because there is no obviously wrong fingerprint to point at; the request looks fine and the cookie simply refuses to go valid. The cause is upstream, in the encoding, and it is exactly the failure the v3 design was built to produce when either seed is wrong.

A genuinely well-formed, currently-acceptable _abck therefore has to clear all of those at once. It must have been advanced past the challenge state by a real sensor POST. Its signed contents must describe the same client that is presenting it on the wire. Its validated state must still be inside the trust window. And on sites running the second layer, the companion cookies, bm_sz as a live input and sec_cpt at ~3~ where sec-cpt is active, must line up too. Miss any one and the long opaque string in front of the tildes counts for nothing.

For the version-by-version story of how this machinery got here, from the December 2016 Cyberfend acquisition through the v2 and v3 sensor formats, see the history of Akamai Bot Manager. The detection model on the server side has a close cousin in DataDome’s approach; the DataDome cookie lifecycle post is a useful contrast for how a different vendor handles token issuance and rotation.

The thing to hold onto about _abck is that almost none of its length is doing the work you would expect. The long encrypted prefix is a signature and a snapshot; the part that decides whether your next request lives or dies is a handful of numbers after a tilde, and those numbers only mean anything because a sensor POST put them there and an edge node will cross-check them against the connection in front of it. The cookie is a promise the client made about itself, signed so the server can re-read it cheaply, and dated so the promise expires.

That is also why the honest answer to “what’s the exact layout of _abck” is that the public record stops at the tilde markers. Akamai documents none of the internals, ships the sensor script in a form that changes its own hash on a schedule, and seeds the v3 encoding from a per-session cookie so that yesterday’s captured payload is worthless today. Everything past the observable state tail in this post is inferred from traffic and from practitioners who agree with one another, which is a different kind of confidence than a spec. If you take one concrete thing away, let it be the cross-check: a _abck that says ~0~ over a TLS fingerprint Akamai didn’t expect is not a valid cookie. It is a valid cookie’s ghost, and the edge knows the difference.


Sources & further reading

  • Akamai (2016), Akamai Acquires Cyberfend — the December 18, 2016 press release naming Cyberfend’s founders and the machine-learning detection that fed Bot Manager Premier.
  • Hyper Solutions (2026), Akamai Web — Getting Started — vendor-style documentation describing _abck as the primary validation token, the {"sensor_data": "..."} POST body, and the ~0~ stop-posting indicator.
  • Hyper Solutions (2026), Handling 428 Status Code (SEC-CPT) — the sec_cpt cookie reaching ~3~, the crypto/behavioural/adaptive providers, and fields like chlg_duration, nonce, and difficulty.
  • glizzykingdreko (2024), Akamai v3 Sensor Data: Deep Dive into Encryption, Decryption, and Bypass Tools — the two-stage shuffle-then-substitute encoding, the script-file-hash and bm_sz-derived seeds, and the default 8888888 seed on the first payload.
  • Edioff (2026), akamai-analysis — a reverse-engineering write-up of the _abck and bm_sz cookie flow, the ~-1~ / ~0~-1~ / ~0~ state progression, and the /_sec/cp_challenge/verify endpoint.
  • Kameleo (2026), Akamai _abck Cookie (glossary) — a plain-language description of _abck as a stateful fingerprint token that lets the edge make trust decisions without re-running the full detection script.
  • Scrapfly (2026), Bypass Akamai Bot Manager — describes the _abck-after-sensor chain and the failure mode where a mismatch between the cookie and the observed request fingerprint flags the visitor.
  • Dima Kynal (2026), The Hidden Fingerprints of Bot Protection — the bmak global object as the telemetry agent and the x-akamai-request-id / akamai-grn response-header tells.
  • The Register (2016), Akamai buys bot-sniffing startup Cyberfend — independent press confirmation of the acquisition and its place in Akamai’s bot strategy.
  • Scrappey (2026), How Akamai Bot Manager detects bots and scrapers — the four-input trust model (IP reputation, the _abck JS sensor, TLS/HTTP-2 fingerprints, cross-session behaviour) and the canvas/WebGL/audio signal list feeding sensor_data.

Frequently asked questions

what do the tilde markers in the _abck cookie value mean

The state tail uses tilde-delimited numeric fields to encode the cookie's status. A tail containing ~-1~ is the unsatisfied state, meaning a challenge is outstanding and no sensor data has arrived. A value showing ~0~-1~ is intermediate: sensor data was received but not yet judged sufficient. A tail that settles to ~0~ without a trailing negative is the satisfied state people call validated. These markers come from observed traffic rather than Akamai documentation, so they are a strong hint about state, not a documented API.

why does a captured _abck cookie fail when replayed on a different connection

The signed prefix of _abck describes a specific browser, and the edge cross-checks that summary against the connection presenting it. If the TLS ClientHello, the HTTP/2 settings, or the IP reputation of the current request disagree with what the cookie encodes, the check fails even when the state tail reads ~0~. The cookie is internally consistent but externally wrong, which is the most common way a transplanted or replayed cookie dies. It was real once, for a different client.

how is the version 3 Akamai sensor_data payload encoded before it is posted

The version 3 sensor encrypts a colon-delimited serialization in two stages. First the elements are shuffled by a pseudo-random number generator seeded with a hash derived from the sensor JavaScript file itself. Then each character is substituted using a second PRNG seeded with a hash derived from a cookie value, typically bm_sz. On the first payload, before a real cookie exists, the implementation uses a default seed reported as 8888888, and later payloads derive the seed from the live bm_sz.

what is the relationship between bm_sz and _abck during the handshake

The dependence runs from bm_sz to _abck, not the other way. The server seeds bm_sz independently on the first HTML response, the client reads it and uses it to encode the sensor payload, and only then does the server return an updated _abck. So bm_sz is an input to the encoding while _abck is the graded output. A session that loses or rotates bm_sz mid-flight loses the input the next payload needs, and the returned _abck will reflect a payload Akamai cannot line up.

why does a long-idle session get challenged even though the _abck cookie has not changed

The _abck cookie persists for about a year, but the validated state encoded inside it lapses far sooner, in minutes to hours. A session that sat idle can present a cookie that is well-formed, was validated, and matches its connection, yet is still treated as needing re-collection because the trust window aged out. Nothing about the cookie changed; the clock did. The edge re-issues the challenge state on the next request, dropping the tail back toward the negative position so the client knows to collect sensor data again.

Further reading