# Akamai SBSD Unblocker — bypass SBSD, get clearance cookies (`xhrdev/akamai-sbsd-unblocker`) Actor

Answer Akamai's SBSD channel — the bundle that posts its own bodies back, scored separately from the \_abck sensor. Returns the page behind the challenge plus the cookies that unlocked it. Powered by xhr.dev.

- **URL**: https://apify.com/xhrdev/akamai-sbsd-unblocker.md
- **Developed by:** [xhrdev](https://apify.com/xhrdev) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 1 total users, 1 monthly users, 60.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$15.00 / 1,000 akamai sbsd clearances

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Akamai SBSD Unblocker

**Answer Akamai's second scoring channel and keep the cookies.** Give this Actor a list of URLs and it returns the page behind the challenge plus the cookies that unlocked it — so your own scraper can carry on from there without solving anything again.

It is powered by [**xhr.dev**](https://xhr.dev), a challenge solver that normally runs as a Docker container inside your own network. This Actor talks to a hosted trial of it, so you can try it before you host anything.

### Which Akamai channel is this?

Akamai Bot Manager scores every request on **two independent channels**, and a property chooses which ones it runs. They are scored separately, which is exactly why this is a different Actor from the [Akamai Sensor Unblocker](https://apify.com/xhrdev/akamai-unblocker).

| Channel | What it is | This Actor |
| --- | --- | --- |
| **SBSD** | A separate bundle script that POSTs its own bodies back to the path it was served from, answered with a one-shot ledger. | **Yes — this is what it solves.** |
| **`_abck` sensor** | The classic obfuscated sensor script, solved over a stateful session until the cookie is accepted. | Also solved, where the property gates on it. |

A page can hold a perfectly good `_abck` and still be refused because its SBSD carriers were never answered. If you are being blocked on a property that sets `bm_s`, `bm_so`, `bm_sc` or `bm_lso`, this is the Actor you want.

#### How to tell which channel a page runs

- **`bm_s`, `bm_so`, `bm_sc` or `bm_lso` in the cookie jar** mean SBSD is running — even if you never saw a request to `/.well-known/sbsd`.
- `/.well-known/sbsd` is one convention, not the rule. On aa.com and aircanada.com the bundle sits on a per-property obfuscated path right next to the `_abck` sensor script, under the same random prefix, with nothing in either path naming the channel. What identifies it is the **UUID `v=`** on its `src` — that value seeds the bundle's codec rather than versioning a file, so an ordinary `?v=3.5.6` cache-buster does not look like it. This Actor discovers the path rather than assuming it.
- **A site that looks unprotected at its apex may not be.** `www.aircanada.com/` is a region chooser and serves anyone; `/ca/en/aco/home.html` behind it is challenged.

### Why use Akamai SBSD Unblocker?

**It handles the ordering, which is forced rather than chosen.** The first document a protected property serves is a small Akamai bootstrap that reloads itself once its SBSD carrier has been answered. The real page — and the `_abck` sensor script on it — only exists after that. Get this backwards and you solve the sensor against a document that is about to be destroyed. This Actor installs its router before the first navigation, answers SBSD during the bootstrap, and solves `_abck` afterwards against the document you actually wanted.

**It knows which properties gate on `_abck` and which do not.** aircanada.com serves its booking page to an ordinary Chrome carrying `_abck=~-1~`, and keeps serving it — 35 rounds of solving the sensor moved neither the cookie nor the page. There, `~-1~` is the steady state, not a stuck solve. Treating it as a failure would report a perfectly good run as broken, and replacing a sensor script that was scoring fine makes things worse. Each supported site carries the right mode.

**One request, not a conversation.** SBSD is answered by a single POST to the solver, which returns a FIFO ledger of bodies for the document that is live at that moment. The page's own carrier POSTs are then rewritten to use them in order. Nothing new is sent to the target that it was not already going to send.

**It fails closed.** Rows are a capacity, not a promise: the ledger carries `expectedCap` rows and the page emits as many carriers as it emits. If it emits more than the ledger holds, the extra ones are aborted rather than allowed through — letting a native body past would hand Akamai a payload from an uninstrumented page alongside ours, which is worse than sending nothing.

### How to use Akamai SBSD Unblocker

1. Click **Try for free**.
2. Pick the sites you want from the **Sites** dropdown. The default is Hilton, a live SBSD target you can use to watch both channels work at once.
3. Leave the proxy off to start. Both supported sites were verified clearing straight from Apify's own address.
4. Click **Start**. The log names each stage: the bundle captured, the ledger issued, each row handed out, and the sensor rounds if the property gates on them.
5. Take the results from the **Output** tab. The `cookieHeader` field is ready to send as-is.

### Input

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `sites` | array | `["hilton.com"]` | Which offered sites to clear, each using its verified URL. |
| `startUrls` | array | — | Exact pages instead of each site's default. Must be on a supported domain. |
| `proxyConfiguration` | object | off | Optional. Apify's RESIDENTIAL group is refused — see below. |
| `returnHtml` | boolean | `true` | Include the unblocked page's full HTML. |
| `returnCookies` | boolean | `true` | Include the full cookie jar and a ready-to-send `Cookie` header. |
| `blockAssets` | boolean | `true` | Drop images, media and fonts. Cheaper, and the payloads are unchanged. |
| `maxRetries` | integer | `3` | Attempts per URL, each with a fresh browser context and proxy session. |
| `maxConcurrency` | integer | `2` | URLs at once. Each concurrent solve is a browser context, so keep it low. |
| `targetPolicy` | string | `verified-only` | Refuse URLs outside the supported list before the run starts. |
| `timeoutSecs` | integer | `180` | How long one URL gets. |

Up to **20 URLs per run** on the shared trial solver.

### Output

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

```json
{
    "url": "https://www.aa.com/booking/find-flights",
    "succeeded": true,
    "carriersAnswered": 1,
    "sbsdCookies": ["bm_s", "bm_so", "bm_sc"],
    "abckAccepted": true,
    "sensorChannel": "solver",
    "finalUrl": "https://www.aa.com/booking/search/find-flights",
    "title": "American Airlines - Advanced search",
    "cookieHeader": "bm_s=YAAQ...; bm_so=5F1...; _abck=57C...~0~...; ak_bmsc=E3B...",
    "attempts": 1,
    "durationMs": 28410,
    "error": null,
    "errorType": null
}
```

#### Data fields

| Field | Type | What it is |
| --- | --- | --- |
| `url` | string | The URL you asked for. |
| `succeeded` | boolean | Whether the page behind the challenge was reached. |
| `carriersAnswered` | number | How many SBSD carrier POSTs were answered from the ledger. |
| `sbsdCookies` | array | Which of `bm_s`, `bm_so`, `bm_sc`, `bm_lso` ended up in the jar. |
| `abckAccepted` | boolean | Whether `_abck` reached its accepted `~0~` state. |
| `sensorChannel` | string | `solver` if this Actor answered `_abck`, `page` if the site does not gate on it. |
| `finalUrl` | string | Where the browser ended up — often a redirect from the URL you gave. |
| `title` | string | The page title behind the challenge. |
| `cookies` / `cookieHeader` | object / string | The full jar, and the same thing ready to send. |
| `html` | string | The unblocked page's HTML. |
| `attempts` | number | How many tries it took. |
| `durationMs` | number | Wall time for the URL. |
| `error` / `errorType` | string | Why it failed: `no_carrier`, `not_accepted`, `access_denied`, `ledger_refused`, `timeout`, `rate_limited`. |

### Which sites are supported

| Site | Gates on `_abck`? | What you get |
| --- | --- | --- |
| **hilton.com** | Yes | The hotel search page, both channels solved |
| **aircanada.com** | No — `~-1~` is its steady state | The booking page, SBSD answered |

**Every site here is verified on Apify itself**, not merely on a desktop. That distinction is the whole list: aa.com solves cleanly from a dedicated address and only about one run in three from the platform's, so it is not offered at all rather than offered with a caveat.

The list grows on request — ask at [xhr.dev](https://xhr.dev). Setting `targetPolicy` to `allow-any` lets you try another site, but on a property that does not run SBSD there is no carrier to answer, so the attempt spends its full deadline discovering that.

### About proxies, and why residential is refused

Akamai relays its telemetry through the browser this Actor drives, so the exit address is not what the sensor is scoring — which is the opposite of DataDome work, where the exit decides the challenge type outright. Both supported sites were measured clearing 2/2 from Apify's own container address with no proxy at all.

Apify's **RESIDENTIAL** group is therefore refused before a run starts. It bills around $8/GB, and a browser solve moves megabytes: $0.040 per URL on residential against $0.0077 with none, for the same solve rate. Datacenter groups are accepted, and `proxyUrls` takes your own residential or ISP endpoint if you want one — that transfer is billed to your provider rather than through the run.

### The exit address still matters on some targets

SBSD properties are sensitive to the address you leave from, and the sensitivity is **cumulative rather than binary**. Measured on hilton.com over one afternoon from a single desktop address: direct runs went 2/4, and after another handful of runs from the same address, 0/2. Through an ISP proxy across the same window, 4/4. Nothing about the payloads changed.

The same effect decides aa.com, which is why it is not in the dropdown, and it is worth knowing before you blame a solve: an address that has already been used for several runs is the most common reason a target that passed yesterday fails today.

So if runs start failing where they used to pass, **suspect the exit before the solve**. A fresh address is the cheapest fix; a residential or ISP proxy is the durable one, and a datacenter pool is not a substitute for either.

Clearance cookies are also bound to the IP that earned them. Reuse them from the same proxy session, or the target will simply challenge again.

### How much does it cost?

**$0.06 per URL cleared** — not for failures, and not for URLs where nothing was solved. The charge happens after the result is stored, so you never pay for a row you cannot read.

That is priced against what a clearance actually costs to produce. Each one drives a real browser through an Akamai bootstrap, its self-reload, and often a full sensor conversation on top, and the page has to be fetched over a residential address to be scored like a person. Measured on a two-URL run: 8.3 MB of residential transfer and 0.05 compute units.

**Two settings move that bill, both on by default:**

- **`blockAssets`** drops images, media and fonts. Akamai scores JavaScript execution and the sensor conversation, not decoded pictures, so this changes the bytes and not the payloads. It is about a third of the traffic.
- **`maxRetries`** stops after three attempts. A target that will not clear from a burned address does not clear on the fourth try either.

If you already have a residential or ISP proxy, put it in `proxyConfiguration` — you get better solve rates than a shared pool, and the transfer is billed to your provider rather than through the run.

### FAQ

**Is this the same as the Akamai Sensor Unblocker?** No. That one solves the `_abck` sensor channel. This one answers SBSD, and also solves `_abck` on the properties that gate on both. If your target sets `bm_s` and friends, you want this one.

**Why does `aircanada.com` report `abckAccepted: false` and still succeed?** Because that property does not gate on `_abck` at that URL. `~-1~` is its steady state, not a stuck solve, and demanding acceptance there would report a good run as a failure.

**Can I run this without a browser?** Not through this Actor. The ledger request itself no longer needs a live realm — every reading it used to carry is now derived server-side — but the rows still have to reach the page's own carrier POSTs, and that is done by intercepting them in a real browser.

**Why is it limited to a few sites?** Because an unblocker that *looks* like it works everywhere gets pointed at an untested target, behaves unpredictably, and the product gets blamed for something nobody ever checked. Every site on the list is verified end to end.

**My run stopped early on a rate limit.** The shared trial key has limits. A dedicated container has none — see [xhr.dev](https://xhr.dev).

### Support

Found a bug or want a site added? Use the **Issues** tab, or get in touch at [xhr.dev](https://xhr.dev).

This Actor is a demonstration of [xhr.dev](https://xhr.dev), which you can run yourself: a Docker container on your own infrastructure, where your traffic goes to the target directly and neither your cookies nor your tokens are sent to a third party. Full documentation at [docs.xhr.dev](https://docs.xhr.dev).

# Actor input Schema

## `sites` (type: `array`):

The SBSD-protected sites to clear. Every site listed here is verified end to end on Apify itself, not just on a desktop — each one answers its SBSD carriers from a generated ledger and serves the document behind the challenge, repeatedly, from the platform's own address. The list grows on request.

## `proxyConfiguration` (type: `object`):

Optional, and usually best left off. Both supported sites were verified clearing straight from the container's own address, and Akamai relays its telemetry through the browser rather than judging the exit — so unlike DataDome work, the address is not what is being scored. Apify's RESIDENTIAL group is refused: it bills ~$8/GB against this Actor and was measured at $0.040 per URL against $0.0077 with no proxy, on identical solve rates. Datacenter groups are fine, and you can always point proxyUrls at your own residential or ISP endpoint.

## `returnHtml` (type: `boolean`):

Include the full HTML of the unblocked page in each dataset item.

## `returnCookies` (type: `boolean`):

Include the full cookie jar — the SBSD cookies (bm\_s, bm\_so, bm\_sc, bm\_lso), \_abck where the property gates on it, and the rest — plus a ready-to-send Cookie header.

## `blockAssets` (type: `boolean`):

On by default, and it is mostly a cost setting. Images and fonts dominate the bytes a browser pulls — a measured two-URL run moved 11.7 MB, about 90% of it pictures — and on a residential proxy those bytes are the expensive part. Akamai scores JavaScript execution and the sensor conversation, not decoded images, and the SBSD ledger derives its resource inventory from the page's HTML rather than from what was actually fetched. Turn it off if you need the images themselves.

## `maxRetries` (type: `integer`):

How many times to try a URL before giving up. Each attempt takes a fresh browser context, and a fresh proxy session if a proxy is configured — which is the point: on this channel a failure is usually the exit address rather than the payload, so a retry on a new session is a genuinely different attempt. Three by default because shared residential pools hand out exits that Akamai has already seen.

## `maxConcurrency` (type: `integer`):

How many URLs to work on at once. Each concurrent solve is a browser context running a bootstrap, a reload and — on a property that gates on both channels — a full sensor conversation, so keep this low.

## `startUrls` (type: `array`):

Optional. Exact pages to clear, instead of each site's default page. Every URL must be on one of the supported domains above, or it is refused before the run starts. Note that protection often sits on an application path rather than the apex — www.aircanada.com is an unprotected region chooser, while /ca/en/aco/home.html behind it is challenged.

## `targetPolicy` (type: `string`):

Verified only (the default) refuses any URL outside the supported list, before the run starts. That matters here more than for an HTTP-based unblocker: on a property that does not run SBSD there is no carrier to answer, so the attempt spends its full deadline discovering that. Need a site added? Ask at https://xhr.dev.

## `timeoutSecs` (type: `integer`):

How long one URL gets. An SBSD solve runs a bootstrap, waits for its self-reload, and then — on a property that gates on both channels — a full sensor conversation on top. Raise this before lowering it.

## Actor input object example

```json
{
  "sites": [
    "hilton.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "returnHtml": true,
  "returnCookies": true,
  "blockAssets": true,
  "maxRetries": 3,
  "maxConcurrency": 2,
  "targetPolicy": "verified-only",
  "timeoutSecs": 180
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "sites": [
        "hilton.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("xhrdev/akamai-sbsd-unblocker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "sites": ["hilton.com"] }

# Run the Actor and wait for it to finish
run = client.actor("xhrdev/akamai-sbsd-unblocker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "sites": [
    "hilton.com"
  ]
}' |
apify call xhrdev/akamai-sbsd-unblocker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,xhrdev/akamai-sbsd-unblocker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/8oDfoeonJw3aUALyM/builds/up7DMCQAkaokNG4cF/openapi.json
