By the end of this guide you will be able to confirm that a site runs PerimeterX (HUMAN), find the values the task needs, get the _px3 cookies from a PerimeterXCookie task, and replay them from the connection that earned them. It also covers how to tell which layer of the stack is blocking you when a 403 keeps coming back, and where this flow stops.
What PerimeterX checks
PerimeterX is now part of HUMAN Security, but the cookies, endpoints and most documentation still say PerimeterX or PX. The product in front of scrapers is Bot Defender: a JavaScript sensor plus a cloud risk score per request, with models trained for each customer. Enforcement is a block page, or a 403 that carries a PX reference id.
The scoring layers are reported to be TLS, HTTP/2 and header fingerprints, IP reputation, the JavaScript sensor, behaviour and the per-customer model. The fingerprints are scored before any challenge is shown. That is why a correct solve can still fail when it is replayed from the wrong client or the wrong address. The PerimeterX solver page has a shorter overview.
Invisible, press-and-hold or mobile
| Surface | What the visitor sees | What a solve produces |
|---|---|---|
| Invisible sensor | Nothing; silent scoring | _px3 cookie |
| Press and hold | A "Press & Hold to confirm you are human" page, sometimes a slide or image-match variant | _px3 cookie |
| Mobile app | Nothing in a browser | Reportedly an x-px-authorization header set, not cookies |
SurSolver has one task type for PerimeterX, PerimeterXCookie, and its result holds _px3 (the main cookie value) and cookies (every returned cookie as a name-to-value object). userAgent is a required task input, not a result key. No header output is documented for this type, so do not plan around mobile app traffic.
Confirm that a site runs PerimeterX
Page source and cookies take a minute to check; the Network panel takes a few more.
| Marker | Where you see it |
|---|---|
_px3 or _px2 cookie on first load |
Application → Cookies |
_pxvid, sometimes _pxhd |
Application → Cookies |
_pxAppId: PX followed by eight characters |
Page source, window._pxAppId |
//client.perimeterx.net/<id>/main.min.js |
Script tag in the page source |
Requests to *.px-cloud.net, *.px-cdn.net, *.perimeterx.net |
Network panel |
An unexplained POST on every page, or an init.js on a random path of the site's own domain such as /px/PXxxxxxxxx/init.js |
Network panel; first-party deployments hide the PX hosts |
px-captcha, captcha.px-cdn.net, "Please verify you are a human", "Access to this page has been denied" |
Body of a 403 or 429 |
An iframe on iframe.hsprotect.net or *.px-cdn.net |
The challenge itself; never use its URL as websiteURL |
The cookies you get back
| Cookie | Role |
|---|---|
_px3 |
The main clearance cookie; newest and highest priority |
_px2 |
The older equivalent, used when there is no _px3 |
_pxhd |
A hardened-device cookie, reported by some deployments |
_pxvid |
The visitor id; send it as uuid |
The exact names vary by target. _px3 carries the main cookie value; cookies maps every returned cookie name to its value, and you replay every entry, not only _px3.
Published lifetimes for these cookies do not exist, and community reports disagree by orders of magnitude, so treat any figure you read as anecdote. Cache a working set briefly and re-solve when you are blocked again.
The task and its inputs
| Field | Required | Where to find it |
|---|---|---|
websiteURL |
Yes | The parent page URL in the address bar, never the iframe URL |
pxAppId |
Yes | _pxAppId in page source, or the id in the main.min.js URL |
proxy |
Yes | One sticky proxy as an http:// or socks5:// URL; there is no proxyless form. A four-part string is read as user:password:host:port; the proxy guide lists the accepted formats |
uuid |
No | The _pxvid cookie value |
vid |
No | window._pxhc.vid in the console; it often equals uuid |
blockData, blockMode, initCookies |
No | The reference lists the names. Reported uses: blockData is the raw body of the 403 you fetched through your proxy, initCookies the cookies of that response, and blockMode the shape of the block (for example xhr). What they change is not documented, so test them on your target before relying on them |
Send the blocked browser's userAgent in the task and keep it on replay.
Pick the proxy now. Residential, mobile or static ISP addresses pass the IP layer; datacenter addresses fail it. Keep the session sticky for roughly 5 to 10 minutes so fetch, solve and replay share one IP.
Create the task and read the result
Send the values above in one createTask call and poll getTaskResult every few seconds until the status is ready. The request, with the required fields. Values between < and > are placeholders:
{
"clientKey": "sur_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"task": {
"type": "PerimeterXCookie",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/155.0.0.0 Safari/537.36",
"websiteURL": "https://www.example.com/products",
"pxAppId": "PX12345678",
"proxy": "http://<user>:<password>@203.0.113.10:8000"
}
}
Add uuid with the _pxvid value when you have it, and vid when your target needs it. blockData, blockMode and initCookies are undocumented; test them on your target before you rely on them. A task is charged when it is accepted, and a task that finishes as failed automatically returns its original charge once, so confirm the markers before you create one (billing).
A ready result carries the main cookie value, the cookies and the browser identity. Values abbreviated:
{
"errorId": 0,
"status": "ready",
"solution": {
"_px3": "<the main _px3 value>",
"cookies": {
"_px3": "…",
"_pxvid": "…"
}
}
}
_px3 carries the main cookie value and cookies the full set as a name-to-value object. Replay with the userAgent supplied in your task.
Replay the cookies
Replay from the connection that earned them:
- Run the replay through the same sticky proxy as the solve. A real browser (Playwright, or Selenium carrying the same cookies and user agent; see Selenium captcha solving) is the simplest way to also present a browser-accurate TLS fingerprint, which a
requests-style client cannot. - Set every entry of
cookieson the protected domain with path/, not only_px3. - Send the user agent of the blocked request in the task, then replay with that exact same value.
- Open the parent page again and wait for protected content, not just a successful status: a hold the challenge UI accepted does not mean the site's risk check passed, so confirm the content you were actually blocked on.
PX trains per-site models, so a result that works on one app id may fail on another; test on the real deployment.
Which layer is blocking you
| What you observe | Layer | Does a new solve help? | What to do |
|---|---|---|---|
403 block page and no _px3 yet |
Challenge | Yes | Send PerimeterXCookie. Akamai block pages look similar but return cookies instead — Akamai solver API |
| "Press & Hold" page in your own automation | Behaviour | No | Do not click or navigate during the hold; it reads mouse movement and hold timing. The button often sits in a closed Shadow DOM, so Selenium locators miss it. Send the task to the API instead |
| 403 even though the cookie is valid | IP or user agent consistency | Only from the same IP | Replay through the proxy and user agent of the solve |
| The captcha keeps coming back | IP reputation | No | Move to a cleaner IP range; this is a proxy problem |
| 429 | The site's own rate limit | No | Slow down or widen the pool of addresses |
requests-style client is blocked before any challenge |
TLS, HTTP/2, headers | No | Use a client whose fingerprint and header order match a real browser |
ERROR_FAILED from the API |
Solve failed | Submit a new task | The charge is returned automatically; check proxy quality and websiteURL |
ERROR_INVALID_REQUEST |
Request shape | After correcting it | The description names the field; nothing was charged |
Confirm the markers, copy the app id and the parent page URL, and send them with PerimeterXCookie in one createTask call. The accepted parameters are in the public catalog (GET /v1/task-types), and the statuses and failure handling are in the task lifecycle guide. For DataDome, which returns a datadome cookie instead, see DataDome solver API.