A Realistic Guide to Kasada Bypass

TL;DR

  • Three checks, not one. Kasada is a bot-management platform that tests the browser itself instead of showing a CAPTCHA, so a Kasada bypass has to get past a proof-of-work puzzle, a token built from it that can't be replayed, and server-side checks that keep scoring the session.
  • Copied headers expire. Part of Kasada's token is single-use, so replayed headers fail, and patched headless builds only last until Kasada rotates its checks.
  • Real sessions last longest. A stealth browser behind a sticky residential proxy gives Kasada a genuine environment to score, and hybrid automation, where a person clears the checkpoint through a live URL, covers the tiers automation can't clear.

Introduction

A Kasada bypass usually comes up after something breaks. A scraper that ran fine last week starts getting 429 responses or blank pages, and nothing in your code has changed. What changed is that the site now sits behind Kasada's bot detection.

Kasada doesn't hand you a CAPTCHA to solve and move past. It checks whether a real browser is on the other end for as long as you're on the site, and it keeps changing what it looks for, so a setup that passes today can stop working without warning. In this guide, you'll learn how Kasada's checks work, why common workarounds expire, and how to set up a session that holds up.

What makes Kasada harder to get past than a CAPTCHA

Kasada is a bot-management platform that sits in front of a site and decides, request by request, whether a real browser is on the other end.

With a CAPTCHA, you solve one thing and you're in. Kasada doesn't work that way. Nothing shows up on screen, so there's no checkbox or image grid for your script to click. Kasada tests the browser itself instead, starting with the very first request.

Any one of those tests can block you, so fixing one rarely gets you through. It helps to picture who's involved. Your browser makes the requests and runs Kasada's script inside the page, while Kasada's server sits in front of the site checking what comes back. Kasada doesn't document any of this, so the specifics come from public reverse-engineering writeups and what you can see in DevTools on a protected site.

What happens on a Kasada page: the browser requests the page, Kasada returns a 429 on protected calls and points the browser to its challenge script, the script solves a proof of work, the browser sends the x-kpsdk headers, and Kasada's server verifies them and keeps scoring protected calls

The initial challenge is a proof of work

When a client that hasn't proven itself requests a protected page or endpoint, Kasada typically answers with a 429. That response points the browser to the challenge script Kasada ships (usually ips.js), which is heavily obfuscated, runs inside its own JavaScript virtual machine, and solves a proof-of-work challenge in your browser.

Proof of work is a small math problem that's cheap for one real browser and expensive for bots running at scale, and Kasada says it can turn up the difficulty to push that cost higher. Since the browser has to execute the puzzle as live JavaScript in a real page, you can't precompute the answer and paste it into a request.

A cryptographic proof that can't be replayed

The solved puzzle turns into a cryptographic proof that rides along on each protected request as headers. Two of them matter most. x-kpsdk-ct carries the client token, and x-kpsdk-cd carries the client data, which holds the proof-of-work answer. A third header, x-kpsdk-h, is a signature that ties the two together.

The client token sticks around for a while (around 30 minutes, according to a public reverse-engineering overview), but the client data works exactly once. Copy the headers off a request that worked, replay them on the next one, and the target server rejects the spent value.

Server-side checks that keep watching

Getting past the puzzle once doesn't buy you the rest of the session. Kasada's server keeps checking every protected request that follows, so your session effectively carries a running trust score, even though Kasada never shows you one.

Kasada also points out that matching IP addresses doesn't stop attackers who route through residential proxy networks, so it doesn't rely on IP alone and leans on the browser and how it behaves to distinguish humans from automation.

Why headless browsers trip Kasada's detection

Out of the box, headless browsers and automation libraries leave markers on the window and navigator objects that Kasada's script can detect. navigator.webdriver is the one everyone knows. They're also missing internals a real browser has, and they don't produce the small behavioral noise you leave without thinking about it, like scroll events and uneven timing.

Some checks dig deeper than reading one property. Kasada reportedly loads its fingerprinting script inside an invisible iframe. If your framework only patches properties in the top-level page, the iframe can still report the unpatched values.

That's why attempting a bypass with a fake user agent won't get you far on its own. Kasada reads the whole environment, and only a full browser gives consistent answers across all of it.

Why Kasada anti-bot workarounds stop working

Search for Kasada anti-detection techniques and you'll find patched browser-automation forks that fix specific, known detection flaws, and for a while they do work. Reverse-engineering a live defense and shipping a fix is real work, but those fixes rarely last.

Kasada points to its ability to randomize its defenses and keep changing how its code is presented to adversaries. A fork that passes today is a snapshot of today's checks, and it's vulnerable to whatever changes next.

If you're running a simple script once against one site, a patched fork might be all you need. Run it against Kasada continuously in production, though, and you've signed up for maintenance with no end date.

There's even a market built on that maintenance. Kasada has written about solver services, subscription services run by people who reverse-engineer its checks and sell access so buyers don't have to. Kasada's answer is to keep rotating and raising the cost of each bypass, until the work costs more money than it brings in.

Why there's no one-call Kasada solver

If you've dealt with Cloudflare Turnstile or DataDome before, you might expect a similar solve call to handle Kasada too. It doesn't. Kasada isn't one of the CAPTCHA types BrowserQL's solve mutation detects today.

Turnstile and DataDome's CAPTCHA give a solver a clear finish line, a challenge that's either solved or not. Kasada doesn't have one. Its scoring carries on for the whole session.

Check the site's terms before you bypass Kasada

Kasada exists to keep unwanted automated traffic off a website, so check the target site's terms of service and robots.txt before you scrape or automate anything against it. Some sites allow automated access for specific uses and others ban it outright. Enforcing that is the site owner's call, and no bypass technique changes it.

Everything that follows assumes you've got a legitimate reason to reach the target, like testing your own Kasada-protected property or running automation the site owner has signed off on.

A Kasada bypass that actually holds up

The setup that lasts is simple. Give Kasada a real browser on a clean connection, let its script run like it would for any visitor, and keep that setup consistent for the whole session. Patched forks and copied headers are partial solutions that only fake pieces of that.

It's the same layered approach Browserless uses to bypass bot detection in general. Start with the lightest option and only move up a tier when a target still blocks you, so most of your traffic runs on the simplest setup.

Kasada bypass escalation ladder: start with the stealth route, add a sticky residential proxy, move to the Unblock API, and hand off to a person only as a last resort

The stealth route and a residential proxy

BrowserQL's stealth route (/stealth/bql) applies fingerprint mitigations for you, with nothing to configure. Add humanlike=true to the connection URL and the session also gets human-like behavior, such as mouse movement and typing delays, which covers the behavioral noise headless browsers usually lack.

Pair the stealth route with the proxy mutation to send the session through Browserless's residential proxy network, and you're browsing from a residential IP instead of a datacenter address. The proxy matters more than you might expect. Datacenter ranges are cheap to enumerate and block, while a residential IP comes from the same pool of connections real users have, and in testing that difference decided whether a session got through.

Keep the same exit IP for the whole session. Browserless already holds the proxy IP sticky by default on stealth and BrowserQL sessions, so sticky: true in the query just makes that explicit. Swapping addresses mid-session only gives Kasada another inconsistency to notice.

If the stealth route itself gets blocked, Browserless suggests trying /chrome/bql with the same residential proxy before moving up a tier. Some sites specifically check for a genuine Chrome user agent.

A working example

Putting the stealth route and the proxy together takes one BrowserQL request. The script sends a mutation to /stealth/bql with humanlike=true that sets a sticky US residential proxy, loads your target page, and waits ten seconds so Kasada's script can finish, just like it would for a real visitor. Then it reads back the page title and text, which is how you'll tell whether you got through.

You'll need Node 18 or later and nothing else, since it uses the built-in fetch. Put your API token in BROWSERLESS_TOKEN and the target in TARGET_URL, and point it at a Kasada-protected page you're authorized to test.

// Node 18+. Needs BROWSERLESS_TOKEN and TARGET_URL, a Kasada-protected page you're
// authorized to test (for example, a page on a site you own).
const { BROWSERLESS_TOKEN, TARGET_URL } = process.env;
if (!BROWSERLESS_TOKEN || !TARGET_URL) {
  throw new Error("Set BROWSERLESS_TOKEN and TARGET_URL before running.");
}

const endpoint = `https://production-sfo.browserless.io/stealth/bql?token=${BROWSERLESS_TOKEN}&humanlike=true`;

const query = `
  mutation KasadaSession($url: String!) {
    proxy(url: ["*"], country: US, sticky: true) { time }
    goto(url: $url, waitUntil: load, timeout: 60000) { status }
    waitForTimeout(time: 10000) { time }
    title { title }
    text { text }
  }
`;

const response = await fetch(endpoint, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ query, variables: { url: TARGET_URL } }),
  signal: AbortSignal.timeout(120_000),
});

if (!response.ok) {
  throw new Error(
    `Browserless returned HTTP ${response.status}: ${await response.text()}`,
  );
}

const { data, errors } = await response.json();
if (errors?.length) {
  throw new Error(`BrowserQL error: ${errors.map((e) => e.message).join("; ")}`);
}

console.log("First response status:", data.goto.status);
console.log("Final title:", data.title.title);
console.log("Page text:", data.text.text.trim().slice(0, 200) || "(empty)");

Save it as kasada-session.mjs and run node kasada-session.mjs. The mutation's steps run in order inside one browser session, and proxy goes first, so its url: ["*"] pattern routes requests for all URLs through the residential network, including the very first request to your target.

If something goes wrong, the script throws on the HTTP or BrowserQL error instead of printing an empty result, so a failed run never passes for a good one. Once the request is complete, the browser session closes on its own, so there's nothing to clean up.

Kasada won't tell you that you've passed, so judge the result by what loaded. If the title matches the real page and the text contains content you'd expect, you got through, even if the first response status was a 429. A real title with empty text usually means the page hadn't finished rendering, so retry with a longer wait. A bare title with no real content, or Chrome's error page, means you're still hitting a Kasada block.

The script uses a fixed wait for a reason. Kasada reloads the page once the challenge passes, which breaks in-page polling such as BrowserQL's waitForFunction with a "target navigated" error.

In a test against the public homepage of a live Kasada-protected site, plain curl got the 429 challenge, and a cloud browser without the proxy stayed stuck on it in every run, stealth route or not. The same setup as the script got the real page in 12 of 13 runs, each time after a 429 first response, and the one miss came with a shorter wait than the ten seconds used here, so the longer wait trades a little speed for a better pass rate.

Build a retry into anything you write that runs on a schedule, and if a site keeps blocking you, change course and look at how the browser itself is driven.

If the stealth route still gets blocked

When stealth routes alone can't get past a site, Browserless recommends site unblocking, available through the Unblock API (/chromium/unblock) or BrowserQL. It works directly with the browser's native remote interfaces and launches the browser the way an end user would, instead of driving it through a Puppeteer or Playwright connection.

Keep the same residential proxy on the request (proxy=residential, which stays sticky by default on /unblock) and ask for a browserWSEndpoint. You get back the live session once it's past the block, kept open for the ttl you set. From there you can connect Puppeteer or Playwright and keep automating from the unblocked state, instead of starting your own session cold against Kasada.

When a Kasada challenge needs a human in the loop

Kasada's public material talks a lot about scalper bots at ticket and sneaker drops. On targets like those, no automated approach, Browserless included, gets through every time.

When automation can't clear a session, hybrid automation hands the browser to a person through a secure live URL, created with Browserless.liveURL over CDP or BrowserQL's liveURL mutation. They clear the checkpoint in the same session while your script waits for the Browserless.liveComplete event. That event only means the handoff ended. Its reason is timeout, closed, or viewerDisconnected, so check that the expected page loaded before your script carries on.

In practice, a person handles the one checkpoint in a live browser while the rest of the run stays automated. Minting a live URL doesn't extend the session's maximum duration, so leave room for the handoff in your timeout, and save it for the sites that won't let anything else through.

Conclusion

Every shortcut against Kasada has the same weakness. Copied headers and patched browsers each fake part of a real visit, and they only work until Kasada checks a part they don't cover. A real browser on a residential connection holds up far longer – it's exactly what Kasada expects to see.

If you'd rather not run that setup yourself, Browserless runs it for you. Start with the stealth route and a residential proxy, try the Unblock API if a site still blocks you, and bring in a person for any checkpoint automation can't clear. When you're ready to try it on a site you're allowed to test, sign up for Browserless.

Kasada bypass FAQs

What is Kasada's proof of work challenge?

It's a computational puzzle Kasada's script solves inside your browser before the site serves the page. Kasada calls it asymmetric. Solving it takes real work on the browser's side, while checking the answer is cheap for Kasada's server, so the cost lands on whoever sends traffic at volume rather than on the site.

How can you tell if a site is Kasada protected?

Open DevTools on the site and watch the network tab for three signs. Requests carry x-kpsdk-ct and x-kpsdk-cd headers, the page loads a challenge script like ips.js, and the protected page or its API calls come back as 429 until that script has run. If you see those, you'll need a real browser session to generate valid tokens. Plain HTTP requests won't get through.

What anti-bot mechanisms does Kasada use?

Kasada stacks several anti-bot mechanisms. A proof-of-work challenge runs in the browser, the result travels as x-kpsdk headers (the x-kpsdk-ct token plus single-use x-kpsdk-cd client data), fingerprinting checks the browser environment, and server-side detection keeps scoring protected requests. Each one can block a script on its own.

Is there a guaranteed way to bypass Kasada?

No. Nothing, including a stealth browser behind a residential proxy, gets through every target every time.