By Rajesh Kannan, Co-Founder & CTO, Gramosoft · Last updated: · Lab results from our own local test on November 3, 2026 (Python 3.13, requests 2.34, httpx 0.28, Playwright 1.64)

Your Python scraper hits a ticketing or sneaker site and gets a 429 on the very first request, or a 200 with nothing in it. That's often Kasada. This guide shows how to recognise it from Python, why plain HTTP clients never get the page, how to stop counting empty pages as wins, and which routes hold up, including GcrawlAI.

TL;DR

  • Recognise it: a 403 or 429 with x-kpsdk-* headers, a script on a /<uuid>/<uuid>/ips.js path and window.KPSDK in a tiny page.
  • Plain HTTP clients can't pass: Kasada makes the client run a JavaScript challenge first, and requests or httpx have no JavaScript engine.
  • A 200 isn't proof: Kasada can block silently. In our lab, 30 of 30 fast page views were 200 OK, but only 19 had content.
  • Check content, pace sessions: the same 30 views spaced 0.6 seconds apart all came back full.
  • Pick a route you're allowed to use: an official API or permission first; for pages you may collect, GcrawlAI renders them in a real browser.

How do you scrape a Kasada-protected website with Python? First confirm it's Kasada: look for a 403 or 429 with x-kpsdk-* headers and an ips.js script. Plain requests won't work, because the page is only served after a JavaScript challenge runs in a real browser. Use an official API or ask for access where you can; for public pages you're allowed to collect, send them through a managed browser API such as GcrawlAI, and accept a page only if the content you expect is in it.

Three routes to the same data

Route Best when Trade-off
Official API, feed or data licence The site offers one, or will on request Paperwork and sometimes a fee, but nothing breaks
Managed browser API Public pages you're allowed to collect, at volume A cost per page, and you still check the content
Your own browser automation Small, occasional jobs on sites that allow it You own the infrastructure, the failures and the maintenance

Protected pages, one request each: GcrawlAI

Kasada only serves a page to a client that runs its JavaScript in a convincing browser, from a reasonable IP, at a human pace. Assembling that yourself means browsers, proxies and retries to run and maintain. GcrawlAI does it inside one API request and hands back the rendered page, so your Python code only has to check the content.

GcrawlAI homepage with the logo and menu (Products, Playground, Extractors, Docs, Pricing, Blog, Use Cases, Custom Request): Transform any website into structured LLM-ready data, the open-source web scraping API for AI agents, RAG pipelines and data teams, with JavaScript rendering, anti-bot stealth and proxies included in every request and no credit system; General, Extractors and Offline Bundle modes, tabs for Scrape, Map, Crawl, Batch, Screenshot, Search and Smart Answer, and the Batch tab open with a URL list, Markdown format, country picker and a Start batch scraping button
The GcrawlAI homepage doubles as a playground: here the Batch tab queues a list of URLs as one job, with rendering, anti-bot stealth and proxies included in every request (desktop screenshot taken October 31, 2026; the phone view, from October 28, shows on small screens).

The homepage says it plainly: JavaScript rendering, anti-bot stealth and proxies are included in every request, with no credit system. That matters on Kasada sites because the expensive part, a real browser through a residential IP, isn't a premium option priced at a multiple of a basic request.

Till receipt for one protected page sent through GcrawlAI: 01 your request, URL and country in one API call, 1 request; 02 a real browser opens it and runs the page's JavaScript, included; 03 residential IP in the country you chose, included; 04 challenge handled in-session with retries and stealth escalation, included; 05 HTML and Markdown back for you to check, included; content present is billed as 1 request, a failed request is never charged; extra credits 0
One protected page, one request: rendering, residential IPs and retries are on the same line.

Here's the whole client. It asks GcrawlAI for the page, then accepts it only if the listing really holds items, because on Kasada sites a 200 alone proves nothing:

# pip install gcrawl-sdk parsel
"""Fetch a protected page you're allowed to collect through GcrawlAI, then accept it only
if the content is really there. A 200 with an empty grid counts as a failure."""
import os
import time

from gcrawl_sdk import GcrawlClient, ScrapeOptions
from gcrawl_sdk.exceptions import GcrawlAPIError, GcrawlTimeoutError
from parsel import Selector

gc = GcrawlClient(api_key=os.getenv("GCRAWL_API_KEY", "gc-YOUR_API_KEY"))
OPTS = ScrapeOptions(html_enabled=True, html_clean=False, markdown_enabled=True, proxy_geo="US", timeout=60)


def has_content(html: str, item_css: str, min_items: int) -> bool:
    return len(Selector(html or "").css(item_css)) >= min_items


def fetch(url: str, item_css: str, min_items: int = 5, tries: int = 3):
    for attempt in range(1, tries + 1):
        try:
            page = gc.scrape(url=url, options=OPTS, wait=True)
            if has_content(page.html, item_css, min_items):
                return page
            print(f"attempt {attempt}: page came back without {min_items}+ items")
        except (GcrawlAPIError, GcrawlTimeoutError) as e:
            print(f"attempt {attempt}: {e}")
        time.sleep(2 ** attempt)                              # back off between tries
    return None


if __name__ == "__main__":
    page = fetch("https://example.com/category/shoes", item_css="li.product")
    print(page.markdown[:500] if page else "no usable page")
  • Rendering and access: a real browser through residential IPs in the country you choose, with retries and stealth escalation inside the request.
  • Output you can check: HTML, Markdown or JSON, plus extractors that return structured fields for common page types.
  • Scrape, crawl, screenshots and Search API: scrape single pages, crawl whole sites, capture screenshots, or use the Search API.
  • For developers and AI agents: a Python SDK, an MCP server for Claude, Cursor and other agents, the Playground to test a page before you write code, and the docs.

The MIT-licensed core also runs on your own servers:

git clone https://github.com/GramosoftAI/GcrawlAI.git && cd GcrawlAI
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt && playwright install
cp .env.example .env                      # add your database, Redis and proxy settings
python -m api.core.db_setup
redis-server &
celery -A web_crawler.crawler.celery_config worker -l info &
uvicorn api.api:app --port 8000

Pricing is a free plan of 50 requests a month with no card, paid plans from $0.67 to $1.45 per 1,000 requests, and a self-hosted core that costs nothing. Failed requests are never charged. The full plan table is in the cost section.

Where it falls short: Kasada is one of the harder protections, and no service passes every Kasada site every time, GcrawlAI included; we haven't been part of a public Kasada benchmark yet, so test your own targets on the free plan. It won't log in for you, and it doesn't make collecting a site's data acceptable when that site's terms say no.

"On Kasada sites the dangerous failure isn't the 429, because you notice that. It's the run that reports 100% success and stored empty pages. We judge every response on its content before we count it."

Rajesh Kannan, Co-Founder & CTO at Gramosoft

What Kasada is, and why Python sees nothing

Kasada is a bot-management service that sits in front of a website and decides whether each client is a real browser before the site answers. Founded in 2015, it's common on ticketing, sneaker, gaming and travel sites. Unlike a CAPTCHA, it shows no puzzle: a client that fails just gets an error or an empty page.

The core idea is making the client prove it can run code. On the first visit, Kasada returns a small page whose script runs heavy, obfuscated JavaScript in the browser, including proof-of-work, and sends the result back. Only then does the server issue a session token, sent on later requests in headers such as x-kpsdk-ct, and serve the real page.

That's why a requests script fails at step one: it downloads the challenge page and stops, because it can't run JavaScript. According to DataImpulse's write-up, Kasada's own site describes a deployment where 90% of requests were bad bots and 98% of those never executed its JavaScript. ScrapingBee notes Kasada was named a leader in the Forrester Wave for bot and agent trust management, Q2 2026.

How to tell a site uses Kasada

Before changing anything, confirm what's blocking you, because Cloudflare, Akamai and DataDome also return 403 and 429. Kasada leaves a recognisable set of fingerprints in the response: its own headers, a script on a distinctive path, and a near-empty HTML page. Two or more of them together are a reliable sign.

Signal What it looks like Where to see it
Kasada headers x-kpsdk-ct, x-kpsdk-r, x-kpsdk-v, x-kpsdk-cd and others Response headers in DevTools or r.headers
Status on first visit 429 or 403, with no visible challenge page Your client's status code
Challenge script A path of two UUIDs ending in ips.js Script tags in the HTML; the Network tab
Global object window.KPSDK Inline script in the challenge page
Empty body A few hundred bytes, empty title, no content Response length

The header names come from ScrapingBee and ZenRows; the UUID-and-ips.js path and window.KPSDK from Decodo's analysis. This detector checks for all five and needs only httpx:

# pip install httpx
"""Tell whether a response came from a Kasada-style challenge instead of the real page."""
import re
import sys

import httpx

SCRIPT_PATH = re.compile(r"/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/"
                         r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/(ips|p)\.js")


def kasada_signals(status: int, headers: httpx.Headers, html: str) -> list[str]:
    found = []
    kp = sorted(h for h in headers if h.lower().startswith("x-kpsdk-"))
    if kp:
        found.append("headers: " + ", ".join(kp))
    if status in (403, 429):
        found.append(f"status: {status}")
    if SCRIPT_PATH.search(html):
        found.append("script: /<uuid>/<uuid>/" + SCRIPT_PATH.search(html).group(1) + ".js")
    if "KPSDK" in html:
        found.append("global: window.KPSDK")
    if len(html) < 2_000 and "<title></title>" in html.replace(" ", ""):
        found.append(f"body: {len(html)} bytes, empty title")
    return found


if __name__ == "__main__":
    url = sys.argv[1] if len(sys.argv) > 1 else "http://127.0.0.1:8772/products"
    r = httpx.get(url, headers={"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
                                              "(KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36"})
    signals = kasada_signals(r.status_code, r.headers, r.text)
    print(f"{r.status_code} {url}")
    for s in signals:
        print("  -", s)
    print("verdict:", "Kasada-style challenge" if len(signals) >= 2 else "no challenge signals")

Against our lab edge, which copies those public signals, it found all five:

429 http://127.0.0.1:8772/products
  - headers: x-kpsdk-ct, x-kpsdk-r, x-kpsdk-v
  - status: 429
  - script: /<uuid>/<uuid>/ips.js
  - global: window.KPSDK
  - body: 281 bytes, empty title
verdict: Kasada-style challenge

Log the verdict with every failed request. Knowing which vendor stopped you tells you whether to look at your client, your pace or the route you chose, instead of guessing.

The layers Kasada checks

Kasada doesn't publish its scoring, but public write-ups agree on the broad shape: several layers, each able to stop a request on its own. Knowing which layer stopped you explains the symptom. A block before any script loads is a different problem from a page that loads, then empties.

Rock-strata cross-section, dig through the layers where a Kasada-protected site can stop a Python scraper: 01 TLS and HTTP/2 handshake, where Python requests looks nothing like Chrome; 02 IP reputation, though one vendor's own test saw the same 200 from datacenter and residential IPs; 03 JavaScript challenge, an obfuscated proof-of-work script, so no JS engine means a 429 and x-kpsdk-* headers; 04 browser environment, where a stock headless browser often fails; 05 behaviour and session, where access turns into empty 200 pages, the silent block
Five places a Kasada-protected site can stop a Python scraper, summarised from public write-ups.
  • TLS and HTTP/2: the handshake requests sends looks nothing like Chrome's, so a request can be judged before any page exists.
  • IP reputation: datacenter and shared proxy ranges score worse, though DataImpulse's own test got the same 200 from datacenter and residential IPs on one page.
  • The JavaScript challenge: no JavaScript engine, no token, so plain HTTP clients stop here.
  • Browser environment: signs that a browser is automated or inconsistent. A stock headless browser often fails here even though it ran the script.
  • Behaviour and session: pace and repetition over time, which is where silent blocks come from.

We don't cover patching browsers to hide automation or reusing Kasada tokens outside the browser that earned them. Those techniques exist to defeat a control the site chose to deploy, they break with each Kasada update, and they're the riskiest part of this work legally.

What Python can and can't do here

Python has three realistic options against a Kasada page: an HTTP client, a browser you drive with Playwright, or an API that does the browsing for you. We ran the first two against a local toy edge that copies Kasada's public behaviour, to show what each one actually receives before any fingerprinting comes into play.

The toy edge is not Kasada and models none of its fingerprinting. It only issues a 429 with x-kpsdk-* headers, serves an ips.js proof-of-work script, and quietly empties pages for sessions that browse too fast. The full lab is in the code download; this is the test:

# pip install requests httpx parsel playwright && playwright install chromium
"""Run three clients against the local lab edge and grade every response on content."""
import time

import httpx
import requests
from playwright.sync_api import sync_playwright

from content_check import check_page
from detect_kasada import kasada_signals

URL = "http://127.0.0.1:8772/products"
UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36"

print("1) HTTP clients, no JavaScript engine")
for name, get in (("requests", lambda: requests.get(URL, headers={"User-Agent": UA})),
                  ("httpx", lambda: httpx.get(URL, headers={"User-Agent": UA}))):
    r = get()
    print(f"  {name:<9} {r.status_code}  signals={len(kasada_signals(r.status_code, r.headers, r.text))}  -> {check_page(r.status_code, r.text)}")

print("2) A real browser that runs the page's JavaScript")
with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    first = page.goto(URL)
    page.wait_for_selector("li.product", timeout=15_000)        # the script solves, then reloads
    print(f"  chromium  first response {first.status}, after reload -> {check_page(200, page.content())}")

    print("3) Same session, 30 page views: status code vs content")
    for label, gap in (("no delay", 0.0), ("0.6 s apart", 0.6)):
        ctx = browser.new_context(); pg = ctx.new_page()
        pg.goto(URL); pg.wait_for_selector("li.product", timeout=15_000)
        codes, verdicts = [], []
        for _ in range(30):
            resp = pg.goto(URL)
            codes.append(resp.status); verdicts.append(check_page(resp.status, pg.content()))
            time.sleep(gap)
        ok200 = codes.count(200); real = sum(v.startswith("ok") for v in verdicts)
        print(f"  {label:<12} 200 OK: {ok200}/30   real content: {real}/30   silent blocks: {30 - real}")
        ctx.close()
    browser.close()
1) HTTP clients, no JavaScript engine
  requests  429  signals=5  -> challenge
  httpx     429  signals=5  -> challenge
2) A real browser that runs the page's JavaScript
  chromium  first response 429, after reload -> ok (24 items)
3) Same session, 30 page views: status code vs content
  no delay     200 OK: 30/30   real content: 19/30   silent blocks: 11
  0.6 s apart  200 OK: 30/30   real content: 30/30   silent blocks: 0
Dial gauges from our November 3, 2026 local lab on a toy edge that copies Kasada's public signals: in a fast session 30 of 30 page views were 200 OK but only 19 of 30 had real content, 11 were silent blocks; with page views 0.6 seconds apart 30 of 30 had content; requests and httpx got a 429 challenge, Chromium ran the page's script and got 200 with 24 items
Our lab: every fast page view returned 200, but 11 of 30 were empty.

Both HTTP clients got the challenge page and nothing else, which is exactly what happens on a real Kasada site. The browser ran the script and got all 24 products. On a real Kasada site that last step is far less certain, because the browser-environment layer often flags stock headless automation, which our toy doesn't check.

  • requests and httpx: fine for detection and for reading the response, never enough to get the page.
  • Your own Playwright browser: runs the challenge, but you own the detection risk, the proxies and the maintenance.
  • A managed browser API: one HTTP call from Python, with the browser, IPs and retries on the provider's side.

Catch silent blocks with content checks

The most expensive Kasada failure is the one you don't see. Instead of an error, a flagged session can get a 200 OK with an empty or misleading page. A scraper that only checks status codes keeps running, reports success, and fills your database with nothing. The fix is simple: judge every page on its content.

"""Judge a page by what it holds, not by its status code: catches silent 200 blocks."""
from parsel import Selector

MIN_ITEMS = 5              # what a real listing page on this site always has


def check_page(status: int, html: str) -> str:
    sel = Selector(html)
    items = sel.css("li.product")
    priced = [i for i in items if i.css(".price::text").get()]
    if status in (403, 429):
        return "challenge"
    if status != 200:
        return f"error {status}"
    if not sel.css("h1::text").get():
        return "not the page (no heading)"
    if len(priced) < MIN_ITEMS:
        return f"silent block ({len(priced)} items)"
    return f"ok ({len(priced)} items)"

In the lab, the fast session got 30 responses with status 200, and this check flagged 11 of them as empty: the edge allowed 20 page views in 10 seconds, counting the one that solved the challenge. Scrapeway's Kasada benchmark makes the same point about real sites, warning that silent blocking leaves you paying for empty 200 responses unless you check content.

  • Assert on something only a real page has: a minimum number of items, a price field, a heading you expect.
  • Treat an empty 200 as a failure: retry it later, don't store it.
  • Track the content rate, not the status rate: a drop in items per page is your early warning.

"Our dashboards don't count 200s, they count items. When the item rate drops and the status rate doesn't, that's a silent block, and it's the first number we look at on any protected site."

Rajesh Kannan, Co-Founder & CTO at Gramosoft

Pace sessions and back off

Kasada's last layer watches behaviour over time, so how fast you go matters as much as what you send. In our lab, slowing the same browser session to one page view every 0.6 seconds took silent blocks from 11 to zero. Real thresholds are unknown and vary by site, so start slow and measure.

  • Start well below human browsing speed and raise the rate only while your content rate stays flat.
  • Back off on 429 and on empty pages: wait longer after each failure instead of retrying at once.
  • Cap concurrency per site and read robots.txt, including any crawl delay.
  • Collect only what you need: fewer pages means fewer chances to be flagged and less load on the site.

Rotating IPs faster doesn't fix a pace problem. It spreads the same behaviour across more addresses, which is the pattern behaviour layers are built to notice.

How scraping APIs score on Kasada

If you go the managed route, results vary widely between providers on Kasada. The independent Scrapeway benchmark tested six scraping APIs against a live Kasada-protected target, Realtor.com, in October 2026, and success rates ranged from 100% down to 8%. Price per 1,000 requests didn't track success.

API Success on Kasada Avg. speed Cost per 1,000
Firecrawl 100% 4.2 s $0.83
Scrapfly 98% 15.3 s $1.56
ZenRows 80% 12.8 s $6.90
Scrapingdog 79% 9.9 s $5.00
ScraperAPI 37% 3.7 s $0.49
WebScrapingAPI 8% 14.9 s $2.45

Source: Scrapeway, October 2026 Kasada benchmark. GcrawlAI wasn't in this run, so we make no claim against these numbers. One target is a small sample, and results change month to month: run your own pages through any provider, GcrawlAI included, and measure the content rate.

What scraping protected pages costs

On Kasada sites every page needs JavaScript rendering, and usually premium IPs, so compare providers on their protected-page price, not their headline rate. For 100,000 successful protected pages a month, credit-based APIs cost $249 to $399 at list price and GcrawlAI costs $101. For plain pages, they're cheaper.

Option, 100,000 successful pages a month Plain HTML pages Protected pages (JS rendering + premium proxies) Are failed requests billed?
GcrawlAI (every request rendered, residential IPs included) $101 (Growth $79 + 20,000 overage at $1.10 per 1,000) $101 (same request, no multiplier) No: failed requests are never charged
ScraperAPI $49 (Hobby, 100,000 credits) $299 (Business; 25 credits per page = 2.5M credits) Charges only 200 and 404 responses
ZenRows $39 (Build B3, 120,000 credits) $399 (Growth G3; 25 credits per page = 2.5M credits) Failed requests never charged; 404 and 410 count as successful
ScrapingBee $49 (Freelance, 250,000 credits; JS off) $249 (Business; 25 credits per page = 2.5M credits) Charges only 200, 404 and 410

List-price arithmetic, not a benchmark. Credit costs and billing rules come from ScraperAPI's credit docs, ZenRows' pricing docs and ScrapingBee's FAQ, checked November 1, 2026. The honest read: for plain HTML, ZenRows, ScraperAPI and ScrapingBee cost less than GcrawlAI. And on Kasada, a status-200 bill can include silent blocks, so the price that counts is the one per page with content.

GcrawlAI plans (GcrawlAI pricing, checked October 28, 2026):

Plan Price Requests/month Concurrent Per 1,000 Overage per 1,000
Free $0 forever, no card 50 2 – –
Starter $29/month 20,000 10 $1.45 $1.60
Growth (most popular) $79/month 80,000 35 $0.99 $1.10
Pro $199/month 250,000 50 $0.80 $0.90
Scale $499/month 750,000 100 $0.67 $0.75
Enterprise Volume pricing 2M+ Custom – –
Self-hosted $0 (MIT) Your servers Your servers Infrastructure only –

Every plan, Free included, has scrape, crawl, the Search API, JavaScript rendering, residential IP rotation and stealth escalation in each request, and each feature counts as one request. Failed requests are never charged. Annual billing charges 10 months for 12, unused requests on paid plans roll over once, and Indian customers are billed in INR with a GST invoice.

Which route fits your project

Start with the route that carries the least risk and the least maintenance, and move on only when it can't give you the data. For Kasada sites that order is usually an official source, then a managed browser API, then your own browsers. The table shows where GcrawlAI fits in each case.

Your situation Route Where GcrawlAI fits
The site has an API, feed or partner programme Use it Not needed; use GcrawlAI for your other, unprotected sources
Public pages, terms allow collection, steady volume Managed browser API with content checks GcrawlAI renders each page in a real browser, one request per page
A handful of pages, occasionally Manual or a slow, polite browser script The GcrawlAI free plan's 50 requests a month
Not sure whether it's Kasada Run the detector first Test the same URL in the GcrawlAI Playground and compare content
You need full control of the stack Self-host The MIT GcrawlAI core on your servers
AI agents need the page A tool the agent can call GcrawlAI MCP server with scrape, crawl and Search API

When your own Python is enough

Plenty of Kasada-related work needs no service at all: detecting which sites use it, monitoring whether your access still returns content, or collecting a few pages slowly from a site that allows it. The detector and content check above cost nothing and belong in every pipeline that touches protected pages, whatever fetches them.

When volume grows or the content rate drops, move the fetching to GcrawlAI and keep your checks. Its free Cloud plan's 50 requests a month are enough to test your real targets, the Playground shows the result without code, and the MIT core self-hosts for free. For the build-or-buy trade-off, read web scraping with Python vs a scraping API.

Is it OK to scrape a Kasada-protected site?

A site that pays for Kasada is telling you it doesn't want automated traffic it hasn't approved. That doesn't make every collection unlawful, but it raises the bar. Read the terms and robots.txt, ask for an API or data licence, stay on public pages, and keep your pace gentle.

Don't defeat the protection itself: no reverse-engineering Kasada's script, forging or replaying its tokens, or solving challenges outside the browser that received them. Don't scrape behind a login, don't buy tickets or limited stock with bots, and don't collect personal data you have no basis to hold. For the legal background, read what web scraping is and where it's legal, and get advice for your own case.

"When a customer brings us a Kasada site, the first question is whether there's an official feed. Often there is, and it's cheaper than any scraper. The pages we do fetch are public ones they're entitled to, at a pace the site won't notice."

Rajesh Kannan, Co-Founder & CTO at Gramosoft

Frequently asked questions

How do I know if a website uses Kasada?

Check the response: a 403 or 429 with x-kpsdk-* headers, a script on a path of two UUIDs ending in ips.js, and window.KPSDK in a tiny HTML page. Two or more together point to Kasada rather than Cloudflare or Akamai.

Can Python requests scrape a Kasada-protected site?

No. Kasada makes the client run an obfuscated JavaScript challenge before it serves the page. requests and httpx can't run JavaScript, so they only ever receive the challenge. They're still useful for detecting Kasada and checking responses.

What is a Kasada silent block?

A 200 OK response with empty or misleading content instead of an error. In our lab, 11 of 30 fast page views were silent blocks. Check that the content you expect is present before you store a page or count it as a success.

What does the x-kpsdk-ct header mean?

It's one of the x-kpsdk-* headers Kasada uses, carrying the session token issued after the challenge. Seeing these headers on a 403 or 429 is the clearest sign that Kasada, not the site itself, rejected the request.

Do residential proxies get past Kasada?

Not on their own. IP reputation is one layer of several, and a client that can't pass the JavaScript challenge fails from any IP. One vendor's own test even got the same 200 from datacenter and residential IPs on the same page.

Which scraping APIs work on Kasada?

Results vary a lot. Scrapeway's October 2026 benchmark on one Kasada target ranged from 100% success to 8%. Test your own pages, measure how many come back with real content, and compare cost per successful page, not per request.

Is GcrawlAI open source, and can I use it commercially?

Yes. The GcrawlAI core is MIT licensed on GitHub, so you can self-host it and use it commercially. The managed Cloud API adds residential IPs and stealth escalation, with a Python SDK and MCP for AI agents, a free plan of 50 requests a month and paid plans from $0.67 to $1.45 per 1,000 requests.

RK

Rajesh Kannan M

Rajesh Kannan M is Co-Founder & CTO of Gramosoft in Chennai, where he leads the team building GcrawlAI, an open-source web scraping, crawling and Search API platform for developers and AI agents. LinkedIn

Check the content, not the status

Start with 50 free requests a month, no card. Send the protected pages you're allowed to collect through GcrawlAI, verify the content that comes back, and pay only for requests that succeed.

CTA Illustration