跳转到文档内容

云浏览器

保存配置、生命周期、代理与额度

APIv1当前版本
本页内容

创建并启动,停止后保留

可单独创建并保存档案,也可通过一个请求创建并启动云浏览器。source 区分 manual 和 launch 来源;两种档案停止后均保留配置,可查询、再次启动或显式删除,与临时 /cdp/sessions 分开管理。API Key 每次启动须携带自定义代理;starting/running/stopping 共用用户运行额度。确认停止释放运行额度,保存数量不减少。

POST /cloud-browsers/launch 创建档案并等待 running 后返回 201。runtime.connectUrl 可直接打开交互界面,Location 则是详情 API 地址。关闭查看器不会停止计费。每次 launch 都新建档案,无幂等键;失败时查询返回的 id,并有界重试停止,不能自动重复 launch。

打开交互式云浏览器

runtime.status 为 starting、running、stopping 或 stopped;starting/stopping 仍占额度。runtimeKind 为 neko 或 worker_cdp。活动会话带 sessionId、expiresAt;只有 running 才可能带 connectUrl,可直接打开对应实例的交互界面,需使用档案所有者账号登录。neko 链接指向 API 域 /cloud-browser-runtime/{sessionId}/,不返回 cdpBaseUrl;固定 usr/pwd 参数是公共查看器协议值,访问权限仍由会话 Cookie 校验,不使用只读 cast 模式。worker_cdp 使用 CDP Studio,可返回带临时令牌的 cdpBaseUrl。请使用返回地址,勿自行拼接或向 URL 添加 API Key、Cookie、代理凭据。地址缺失时先查询真实状态。

认证与资源归属

列表、创建、创建并启动、详情、启动和关闭支持 X-API-Key: <API_KEY> 或 Authorization: Bearer <SESSION_JWT>,也支持会话 Cookie。Bearer 必须是登录会话 JWT,不能填写 API Key。只能操作认证用户自己的资源;PATCH、DELETE 配置、查看器和 join-token 仍仅支持会话认证。

会话认证启动还必须传 apiKeyId,指定同一用户拥有且有效、未过期的 API Key。X-API-Key 会自动选择该 Key;若同时传 apiKeyId,必须一致。不要把 API Key 或代理凭据放入前端代码、URL 或日志;所有示例均使用占位凭据。

JSON 响应包含 traceId,响应头 X-Trace-Id 也提供同一追踪标识。错误包含 error,部分包含 code;请结合 HTTP 状态与稳定的 code 处理错误。

API 与页面的代理规则

使用 X-API-Key 时,每次启动请求都必须在顶层显式传入有效 proxy 对象,即使创建时已保存代理也不能省略。仅传 countryCode 或 source=web 不能替代代理。会话认证(包括 JWT Bearer)下,页面可使用有效自定义代理,或明确选择 countryCode(两位地区码,GLOBAL 表示随机地区);会话启动可复用已保存的明确选择。两个入口都不允许无代理运行。

proxy.server 必须是 http:// 或 socks5:// URL,显式包含 1–65535 端口,不能内嵌凭据、路径、查询参数或片段;也支持 protocol + host + port 拆分格式。无认证代理同时省略 username 和 password,需要认证时两者都必须非空。空代理或非法代理会被拒绝。proxy 和 countryCode 不能同传,否则返回 400 COUNTRY_PROXY_CONFLICT。启动覆盖只影响本次运行,不修改保存配置。

动态代理分配失败会拒绝启动,自定义代理失败同样不会回退直连。请修复代理,或待服务恢复后重试;不要通过移除代理绕过错误。

会话 JWT:显式选择动态代理
curl --fail-with-body -sS -X POST "https://api.adscrawl.net/cloud-browsers/<CLOUD_BROWSER_ID>/start" \
  -H "Authorization: Bearer <SESSION_JWT>" \
  -H "Content-Type: application/json" \
  -d '{"apiKeyId":"<API_KEY_ID>","countryCode":"GLOBAL"}'

保存数量与运行额度

GET /cloud-browsers 返回 limit(可保存配置数)、runningLimit(当前用户同时运行上限)和 runningCount(该用户所有 starting、running、stopping 云浏览器会话数,跨分页、跨 API Key 统计)。已保存但未运行的配置不占运行名额。页面和 API 共用运行额度,临时 Remote CDP 会话另行计算。

用户运行额度默认 1。未配置(NULL)或负数按 1 处理;0 禁止新启动;正整数表示上限。额度实时读取、无缓存。下调不会主动关闭现有会话,只会限制后续启动,直到有可用名额。启动时原子预占,启动失败、关闭完成或异常回收后释放;stopping 仍占用名额。

超过运行额度返回 409 CLOUD_BROWSER_CONCURRENCY_LIMIT;保存配置数达到上限则返回 409 Cloud Browser limit reached,两者不同。启动仍要求付费套餐且余额至少 1 credit。云浏览器从成功启动到停止按已开始的分钟计费,每分钟 1 credit,不足一分钟按一分钟计算;重复停止通知不会重复计费。

提高用户额度不会同时提高每 API Key 的 CDP 上限或全局运行容量;仍可能遇到 429 CDP sessions per API key limit reached 或 503 CDP session capacity exhausted。

创建 → 启动 → 查询 → 关闭

创建仅保存配置并返回 id。启动需单独请求,同步等待运行时确认后才返回 200 running。查询时按响应原样展示 runtime.status:starting → running → stopping → stopped。关闭的 202 表示尚未完成,应轮询详情直到 stopped。对已活动的配置重复启动返回 409;对已停止的配置重复关闭返回 200,runtime.status=stopped。

以下流程需要 bash、curl 和 jq。请替换为自己的测试凭据及可达代理。轮询最多等待约两分钟;超时不代表实例已关闭,请保留配置 id,按需再次查询或关闭。下方 JSON 为响应结构示例,并非在线接口执行结果。

cURL 完整流程(bash + jq)
set -euo pipefail
export ADSCRAWL_API_KEY="<API_KEY>"
API_BASE="https://api.adscrawl.net"

# 1. Save a profile; this does not start a browser.
created=$(curl --fail-with-body -sS -X POST "$API_BASE/cloud-browsers" \
  -H "X-API-Key: $ADSCRAWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"remark":"API example","browserSettings":{"viewport":{"width":1440,"height":900}}}')
CLOUD_BROWSER_ID=$(printf '%s' "$created" | jq -er '.id')

# 2. Send proxy again on EVERY start. Replace placeholder credentials.
curl --fail-with-body -sS -X POST "$API_BASE/cloud-browsers/$CLOUD_BROWSER_ID/start" \
  -H "X-API-Key: $ADSCRAWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"proxy":{"server":"http://proxy.example.com:8080","username":"<PROXY_USERNAME>","password":"<PROXY_PASSWORD>"}}'

# 3. Read the actual state, with a bounded wait for running/stopped.
wait_for_state() {
  local expected="$1" state attempt
  for attempt in {1..60}; do
    state=$(curl --fail-with-body -sS "$API_BASE/cloud-browsers/$CLOUD_BROWSER_ID" \
      -H "X-API-Key: $ADSCRAWL_API_KEY" | jq -er '.runtime.status') || return 1
    printf 'runtime.status=%s\n' "$state"
    if [ "$state" = "$expected" ]; then return 0; fi
    case "$state" in
      starting|running|stopping|stopped) ;;
      *) return 1 ;;
    esac
    if [ "$expected" = running ] && [ "$state" != starting ]; then return 1; fi
    sleep 2
  done
  return 1
}
if ! wait_for_state running; then
  printf '%s\n' 'Browser not ready; requesting stop for cleanup.' >&2
fi

# 4. Inspect account-wide limits (not just the current page).
curl --fail-with-body -sS "$API_BASE/cloud-browsers?page=1&pageSize=10" \
  -H "X-API-Key: $ADSCRAWL_API_KEY" | jq '{limit,runningLimit,runningCount}'

# 5. A 202 response means stopping, not stopped. Confirm via detail.
curl --fail-with-body -sS -X POST "$API_BASE/cloud-browsers/$CLOUD_BROWSER_ID/stop" \
  -H "X-API-Key: $ADSCRAWL_API_KEY"
wait_for_state stopped
GET/cloud-browsers

云浏览器列表与额度

请求

请求头

字段类型说明
x-api-keyAPI Key 鉴权时stringAPI 调用使用完整 API Key。这些接口也接受页面会话 Cookie 或 Authorization: Bearer <access-token>;任选一种鉴权方式。资源按用户归属隔离。

查询参数

字段类型说明
pageinteger默认 1,最大 10000;非法值或非正数使用默认值。
pageSizeinteger默认且最大 10;非法值或非正数使用默认值。

响应

200
application/jsonlimit 是套餐允许保存的档案数量;runningLimit 是用户同时运行上限;runningCount 统计该用户所有档案的 starting、running、stopping,会跨分页、API Key 和页面共享,不包含临时 /cdp/sessions。users.cloud_browser_running_limit 为 NULL 或负数时默认 1,0 禁止新启动,正数为上限。列表和每次启动实时读取;下调不会主动关闭已有实例。全局容量仍单独限制,不叠加临时 CDP 的每 Key 并发限制。
200
application/jsonruntime.status 为 starting、running、stopping 或 stopped;starting/stopping 仍占额度。runtimeKind 为 neko 或 worker_cdp。活动会话带 sessionId、expiresAt;只有 running 才可能带 connectUrl,可直接打开对应实例的交互界面,需使用档案所有者账号登录。neko 链接指向 API 域 /cloud-browser-runtime/{sessionId}/,不返回 cdpBaseUrl;固定 usr/pwd 参数是公共查看器协议值,访问权限仍由会话 Cookie 校验,不使用只读 cast 模式。worker_cdp 使用 CDP Studio,可返回带临时令牌的 cdpBaseUrl。请使用返回地址,勿自行拼接或向 URL 添加 API Key、Cookie、代理凭据。地址缺失时先查询真实状态。
401
application/json鉴权缺失、无效或已过期。
503
application/jsonCDP_WORKER_UNAVAILABLE,或无 code 的 Cloud browser runtime is unavailable。原节点记录丢失、bootId 改变或暂时失联都不能证明已停止;保留会话和运行额度,连接地址可能省略。
500
application/jsonInternal error:服务内部错误。

请求示例

cURL
curl --fail-with-body --silent --show-error --max-time 65 \
  -X GET 'https://api.adscrawl.net/cloud-browsers?page=1&pageSize=10' \
  -H 'x-api-key: <api-key>'

响应示例

200
{
  "ok": true,
  "data": [
    {
      "id": "<browser-id>",
      "source": "manual",
      "deleteOnStop": false,
      "remark": "work profile",
      "browserSettings": {
        "viewport": {
          "width": 1440,
          "height": 900
        }
      },
      "proxyDisplayIp": null,
      "proxyDisplayRegion": null,
      "lastOpenedAt": null,
      "updatedAt": "2026-09-07T08:00:00.000Z",
      "runtime": {
        "runtimeKind": "neko",
        "status": "stopped"
      }
    }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 10,
    "total": 1,
    "totalPages": 1
  },
  "limit": 10,
  "runningLimit": 1,
  "runningCount": 0
}
POST/cloud-browsers

创建云浏览器配置

请求

请求头

字段类型说明
x-api-keyAPI Key 鉴权时stringAPI 调用使用完整 API Key。这些接口也接受页面会话 Cookie 或 Authorization: Bearer <access-token>;任选一种鉴权方式。资源按用户归属隔离。
content-type必填application/json请求体为一个 JSON 对象,最大 1 MiB。

请求体

字段类型说明
remarkstring可选备注;trim 后最多 255 个 Unicode 字符。
browserSettingsobject可选持久配置,例如 viewport、locale、timezoneId、proxy 或 countryCode、cookies 和 fingerprint。省略时为 {},传入时必须为对象。创建仅保存配置,不启动实例;保存代理也不能替代 API Key 下次启动时的顶层 proxy。预置 cookies 须为数组,服务端加密保存,所有者读取时回填。

响应

201
application/json返回 {ok: true, id},档案处于 stopped,未占运行额度。免费套餐最多保存 1 个档案;实际保存上限见列表 limit。完整流程示例见请求示例的 Node.js 标签。
400
application/json空 body、null、数组、标量或非法字段类型;remark 超长、Invalid cookies、INVALID_PROXY、INVALID_COUNTRY_CODE 或 COUNTRY_PROXY_CONFLICT。{} 是有效创建请求。
401
application/json鉴权缺失、无效或已过期。
409
application/jsonCloud Browser limit reached:已达保存数量 limit,无 code;与运行额度错误不同。
500
application/jsonInternal error:服务内部错误。

请求示例

cURL
curl --fail-with-body --silent --show-error --max-time 65 \
  -X POST 'https://api.adscrawl.net/cloud-browsers' \
  -H 'x-api-key: <api-key>' \
  -H 'content-type: application/json' \
  --data '{
  "remark": "work profile",
  "browserSettings": {
    "viewport": {
      "width": 1440,
      "height": 900
    }
  }
}'
JSON
{
  "remark": "work profile",
  "browserSettings": {
    "viewport": {
      "width": 1440,
      "height": 900
    }
  }
}
Node.js 完整流程
// Node.js 20+, save as .mjs. Replace proxy placeholders before running.
const baseUrl = "https://api.adscrawl.net";
const apiKey = process.env.ADSCRAWL_API_KEY;
if (!apiKey) throw new Error("ADSCRAWL_API_KEY is required");
const proxy = {
  "server": "http://proxy.example.com:8080",
  "username": "<proxy-user>",
  "password": "<proxy-password>"
};

async function request(method, path, body, timeoutMs = 65000) {
  const res = await fetch(baseUrl + path, {
    method,
    headers: { "x-api-key": apiKey, "content-type": "application/json" },
    body: body === undefined ? undefined : JSON.stringify(body),
    signal: AbortSignal.timeout(timeoutMs),
  });
  const data = await res.json();
  if (!res.ok) {
    const error = new Error(data.error || "HTTP " + res.status);
    error.status = res.status;
    error.code = data.code;
    error.id = data.id;
    throw error;
  }
  return data;
}

async function stopAndWait(id) {
  const path = "/cloud-browsers/" + encodeURIComponent(id);
  // At most 30 attempts, 2 seconds apart; each request times out after 10 seconds.
  for (let attempt = 0; attempt < 30; attempt++) {
    try {
      const stopped = await request("POST", path + "/stop", undefined, 10000);
      if (stopped.runtime.status === "stopped") return;
      const current = await request("GET", path, undefined, 10000);
      if (current.runtime.status === "stopped") return;
    } catch (error) {
      if (error.code !== "CDP_SESSION_STARTING" &&
          !(error.status >= 500) && error.name !== "TimeoutError") throw error;
    }
    await new Promise((resolve) => setTimeout(resolve, 2000));
  }
  throw new Error("Stop unconfirmed; quota is still reserved. Retry stop for " + id);
}
const { id } = await request("POST", "/cloud-browsers", {
  "remark": "work profile",
  "browserSettings": {
    "viewport": {
      "width": 1440,
      "height": 900
    }
  }
});
try {
  // Include a valid proxy again on EVERY start, even for an existing profile.
  await request("POST", "/cloud-browsers/" + encodeURIComponent(id) + "/start", { proxy });
  const current = await request("GET", "/cloud-browsers/" + encodeURIComponent(id));
  console.log({ id, source: current.source, status: current.runtime.status, connectUrl: current.runtime.connectUrl });
  // Open connectUrl in a browser signed in as the profile owner before continuing.
  const { limit, runningLimit, runningCount } = await request("GET", "/cloud-browsers");
  console.log({ limit, runningLimit, runningCount });
} finally {
  // Also attempt cleanup after a failed start: a runtime may still need recovery.
  await stopAndWait(id);
}
console.log("Stopped; the saved profile remains", id);

响应示例

201
{
  "ok": true,
  "id": "<browser-id>"
}
POST/cloud-browsers/launch

创建并启动云浏览器

请求

请求头

字段类型说明
x-api-keyAPI Key 鉴权时stringAPI 调用使用完整 API Key。这些接口也接受页面会话 Cookie 或 Authorization: Bearer <access-token>;任选一种鉴权方式。资源按用户归属隔离。
content-type必填application/json请求体为一个 JSON 对象,最大 1 MiB。

请求体

字段类型说明
proxy必填object所有鉴权方式每次必传。 API Key 每次启动必须显式传顶层有效 proxy;历史 browserSettings.proxy、上次运行代理、countryCode 或伪造 source 都不能替代。仅接受 http 或 socks5:{server: "http://proxy.example.com:8080"} 或 {protocol: "socks5", host: "proxy.example.com", port: 1080}。端口为 1-65535 的整数或整数字符串;server 必须含端口,不含 URL 凭据、查询或片段,不能同时传 host。username/password 可选但须成对非空字符串,不能写在 URL 内。代理失败不得回退直连。
tabs(string | {url: string, active?: boolean})[]默认 [],不注入标签页,保留 Runtime 初始页面。最多 8 项;仅 HTTP(S) URL,每项最多 16384 bytes,禁止 URL 凭据、控制字符或首尾空白。active 默认 false,最多一个 true;未指定活动项时激活第一项。
cookiescookie[]默认 [],无预置 Cookie。最多 10000 条,整个请求最大 1 MiB。name/domain 为非空 string;value 为 string,默认空;path 默认 /;secure/httpOnly/session 为 boolean;expires 为 Unix 秒;sameSite 为 Strict/Lax/None。支持已有 Cookie 快照兼容字段;过滤过期项,拒绝未知字段和非法类型。Cookie 独立加密保存,所有者可读取。
fingerprintobject默认 webRtc=forward,其余 webGl、webGpu、webGlImage、canvas、audioContext、clientRects、speechVoices、fonts、hardware、doNotTrack 均为 random。部分传入时补齐默认值;字段允许值与组合限制同启动接口。hardwareConcurrency/deviceMemory 可选整数 1-64,运行 seed 由服务端生成。
apiKeyId会话/Bearer 鉴权时string (UUID)会话/Bearer 需指定本人有效 Key;API Key 鉴权时自动使用当前 Key,若传入必须匹配。

响应

201
application/json返回 {ok: true, id, source: launch, deleteOnStop: false, runtime} 与 Location: /cloud-browsers/<id>,仅确认 running 后成功。runtime.connectUrl 是可直接打开的交互界面链接;Location 是查询接口地址。source 仅区分来源。手动停止、到期停止或启动失败确认回收后,保留档案配置及 Cookie/标签快照,仍计入保存额度,可查询、再次启动或显式删除。关闭查看器不会停止浏览器。
201
application/jsonruntime.status 为 starting、running、stopping 或 stopped;starting/stopping 仍占额度。runtimeKind 为 neko 或 worker_cdp。活动会话带 sessionId、expiresAt;只有 running 才可能带 connectUrl,可直接打开对应实例的交互界面,需使用档案所有者账号登录。neko 链接指向 API 域 /cloud-browser-runtime/{sessionId}/,不返回 cdpBaseUrl;固定 usr/pwd 参数是公共查看器协议值,访问权限仍由会话 Cookie 校验,不使用只读 cast 模式。worker_cdp 使用 CDP Studio,可返回带临时令牌的 cdpBaseUrl。请使用返回地址,勿自行拼接或向 URL 添加 API Key、Cookie、代理凭据。地址缺失时先查询真实状态。
201
application/json沿用付费套餐、保存 limit、用户 runningLimit 和全局容量,starting/running/stopping 占运行额度。成功启动到确认停止每开始分钟 1 credit。确认 stopped 后释放运行额度;保存数量不减少,显式 DELETE /cloud-browsers/{id} 才删除档案。此接口仅支持已启用的 Cloud Runtime。
400
application/jsonPROXY_REQUIRED、INVALID_PROXY、INVALID_TABS、INVALID_COOKIES、INVALID_FINGERPRINT_SETTINGS。显式 null、未知字段(含 countryCode/source/browserSettings)、非法 JSON 或类型不匹配均被拒绝;不创建档案。
401
application/json鉴权缺失、无效或已过期。
402
application/jsonPAID_PLAN_REQUIRED 或 INSUFFICIENT_CREDITS;不创建档案。
403
application/json所选 Key 越权或与认证 Key 不匹配;不创建档案。
409
application/jsonCloud Browser limit reached:保存数量满,不创建。CLOUD_BROWSER_CONCURRENCY_LIMIT:运行额度满或为 0;若已创建档案,响应附 id、source: launch、deleteOnStop: false、deleted: false 与真实 runtime,档案保留。
502/503/504/500
application/json沿用启动接口错误码和容量重试字段。档案创建后的错误附 id、runtime 与 Location;已预留时含 sessionId。未确认回收时仍为 stopping 并占额度。Cloud Runtime 未启用返回 503,不转发 Worker。启动等待 60 秒,回收确认可能额外等待至多 120 秒。
502/503/504/500
application/json每次调用创建新档案,无幂等键;不要自动重发 launch。错误返回 id 时先查询并有界重试同一 stop,直到 stopped。档案保留,deleted: false;未确认回收时还继续占运行额度。完全丢失响应时先核对列表与额度;不能假定未创建或已停止。

请求示例

cURL
curl --fail-with-body --silent --show-error --max-time 200 \
  -X POST 'https://api.adscrawl.net/cloud-browsers/launch' \
  -H 'x-api-key: <api-key>' \
  -H 'content-type: application/json' \
  --data '{
  "proxy": {
    "server": "http://proxy.example.com:8080",
    "username": "<proxy-user>",
    "password": "<proxy-password>"
  },
  "tabs": [
    "https://example.com"
  ],
  "cookies": [
    {
      "name": "sid",
      "value": "<cookie-value>",
      "domain": "example.com",
      "path": "/",
      "secure": true
    }
  ],
  "fingerprint": {
    "canvas": "real"
  }
}'
JSON
{
  "proxy": {
    "server": "http://proxy.example.com:8080",
    "username": "<proxy-user>",
    "password": "<proxy-password>"
  },
  "tabs": [
    "https://example.com"
  ],
  "cookies": [
    {
      "name": "sid",
      "value": "<cookie-value>",
      "domain": "example.com",
      "path": "/",
      "secure": true
    }
  ],
  "fingerprint": {
    "canvas": "real"
  }
}
最小请求
{
  "proxy": {
    "server": "http://proxy.example.com:8080",
    "username": "<proxy-user>",
    "password": "<proxy-password>"
  }
}
Node.js 完整流程
// Node.js 20+, save as .mjs. Replace proxy placeholders before running.
const baseUrl = "https://api.adscrawl.net";
const apiKey = process.env.ADSCRAWL_API_KEY;
if (!apiKey) throw new Error("ADSCRAWL_API_KEY is required");
const proxy = {
  "server": "http://proxy.example.com:8080",
  "username": "<proxy-user>",
  "password": "<proxy-password>"
};

async function request(method, path, body, timeoutMs = 65000) {
  const res = await fetch(baseUrl + path, {
    method,
    headers: { "x-api-key": apiKey, "content-type": "application/json" },
    body: body === undefined ? undefined : JSON.stringify(body),
    signal: AbortSignal.timeout(timeoutMs),
  });
  const data = await res.json();
  if (!res.ok) {
    const error = new Error(data.error || "HTTP " + res.status);
    error.status = res.status;
    error.code = data.code;
    error.id = data.id;
    throw error;
  }
  return data;
}

async function stopAndWait(id) {
  const path = "/cloud-browsers/" + encodeURIComponent(id);
  // At most 30 attempts, 2 seconds apart; each request times out after 10 seconds.
  for (let attempt = 0; attempt < 30; attempt++) {
    try {
      const stopped = await request("POST", path + "/stop", undefined, 10000);
      if (stopped.runtime.status === "stopped") return;
      const current = await request("GET", path, undefined, 10000);
      if (current.runtime.status === "stopped") return;
    } catch (error) {
      if (error.code !== "CDP_SESSION_STARTING" &&
          !(error.status >= 500) && error.name !== "TimeoutError") throw error;
    }
    await new Promise((resolve) => setTimeout(resolve, 2000));
  }
  throw new Error("Stop unconfirmed; quota is still reserved. Retry stop for " + id);
}
let id;
try {
  // One call creates AND starts. Never automatically repeat this POST.
  const launched = await request("POST", "/cloud-browsers/launch", {
    proxy,
    tabs: ["https://example.com"],
    // cookies and fingerprint omitted: use their defaults.
  }, 195000);
  id = launched.id;
  const current = await request("GET", "/cloud-browsers/" + encodeURIComponent(id));
  console.log({ id, status: current.runtime.status });
} catch (error) {
  id = id || error.id;
  if (!id) console.error("No profile id received; inspect /cloud-browsers before retrying launch.");
  throw error;
} finally {
  // Errors after profile creation also return id; unconfirmed cleanup reserves quota.
  if (id) await stopAndWait(id);
}
console.log("Stopped; the saved profile remains", id);

响应示例

201
{
  "ok": true,
  "id": "<browser-id>",
  "source": "launch",
  "deleteOnStop": false,
  "runtime": {
    "runtimeKind": "neko",
    "status": "running",
    "sessionId": "<session-id>",
    "expiresAt": "2026-09-07T09:00:00.000Z",
    "connectUrl": "https://api.adscrawl.net/cloud-browser-runtime/<session-id>/?usr=adscrawl&pwd=adscrawl"
  }
}
504 stopping
{
  "error": "Cloud browser runtime request timed out",
  "code": "CLOUD_RUNTIME_TIMEOUT",
  "id": "<browser-id>",
  "source": "launch",
  "deleteOnStop": false,
  "deleted": false,
  "runtime": {
    "runtimeKind": "neko",
    "status": "stopping",
    "sessionId": "<session-id>",
    "expiresAt": "2026-09-07T09:00:00.000Z"
  }
}
GET/cloud-browsers/{id}

查询云浏览器状态

请求

请求头

字段类型说明
x-api-keyAPI Key 鉴权时stringAPI 调用使用完整 API Key。这些接口也接受页面会话 Cookie 或 Authorization: Bearer <access-token>;任选一种鉴权方式。资源按用户归属隔离。

路径参数

字段类型说明
id必填string (UUID)创建或列表返回的持久化云浏览器 id,不是运行时 sessionId。

响应

200
application/json直接返回档案对象,不包裹 data 或 ok。包括 id、remark、browserSettings、proxyDisplayIp/Region(可为 null)、lastOpenedAt(可为 null)、updatedAt 和 runtime。代理凭据从响应中移除;所有者可读取已保存的 cookies。
200
application/jsonruntime.status 为 starting、running、stopping 或 stopped;starting/stopping 仍占额度。runtimeKind 为 neko 或 worker_cdp。活动会话带 sessionId、expiresAt;只有 running 才可能带 connectUrl,可直接打开对应实例的交互界面,需使用档案所有者账号登录。neko 链接指向 API 域 /cloud-browser-runtime/{sessionId}/,不返回 cdpBaseUrl;固定 usr/pwd 参数是公共查看器协议值,访问权限仍由会话 Cookie 校验,不使用只读 cast 模式。worker_cdp 使用 CDP Studio,可返回带临时令牌的 cdpBaseUrl。请使用返回地址,勿自行拼接或向 URL 添加 API Key、Cookie、代理凭据。地址缺失时先查询真实状态。
200
application/jsonsource 为 manual 或 launch;launch 表示创建并启动接口来源,不是删除策略。旧 deleteOnStop 标记由后端兼容处理,现返回 false;停止后配置、快照和来源继续保留,仍占保存额度。历史已删除记录不会恢复,可能返回 deleted: true、stopped 和空配置;仅真正删除的记录不在列表中。
401
application/json鉴权缺失、无效或已过期。
404
application/json档案不存在或不属于当前用户。
503
application/jsonCDP_WORKER_UNAVAILABLE,或无 code 的 Cloud browser runtime is unavailable。原节点记录丢失、bootId 改变或暂时失联都不能证明已停止;保留会话和运行额度,连接地址可能省略。
500
application/jsonInternal error:服务内部错误。

请求示例

cURL
curl --fail-with-body --silent --show-error --max-time 65 \
  -X GET 'https://api.adscrawl.net/cloud-browsers/<browser-id>' \
  -H 'x-api-key: <api-key>'

响应示例

stopped
{
  "id": "<browser-id>",
  "source": "manual",
  "deleteOnStop": false,
  "remark": "work profile",
  "browserSettings": {
    "viewport": {
      "width": 1440,
      "height": 900
    }
  },
  "proxyDisplayIp": null,
  "proxyDisplayRegion": null,
  "lastOpenedAt": null,
  "updatedAt": "2026-09-07T08:00:00.000Z",
  "runtime": {
    "runtimeKind": "neko",
    "status": "stopped"
  }
}
stopping
{
  "id": "<browser-id>",
  "source": "manual",
  "deleteOnStop": false,
  "remark": "work profile",
  "browserSettings": {
    "viewport": {
      "width": 1440,
      "height": 900
    }
  },
  "proxyDisplayIp": null,
  "proxyDisplayRegion": null,
  "lastOpenedAt": null,
  "updatedAt": "2026-09-07T08:00:00.000Z",
  "runtime": {
    "runtimeKind": "neko",
    "status": "stopping",
    "sessionId": "<session-id>",
    "expiresAt": "2026-09-07T09:00:00.000Z"
  }
}
launch stopped
{
  "id": "<browser-id>",
  "source": "launch",
  "deleteOnStop": false,
  "remark": "work profile",
  "browserSettings": {
    "viewport": {
      "width": 1440,
      "height": 900
    }
  },
  "proxyDisplayIp": null,
  "proxyDisplayRegion": null,
  "lastOpenedAt": null,
  "updatedAt": "2026-09-07T08:00:00.000Z",
  "runtime": {
    "runtimeKind": "neko",
    "status": "stopped"
  }
}
POST/cloud-browsers/{id}/start

启动云浏览器

请求

请求头

字段类型说明
x-api-keyAPI Key 鉴权时stringAPI 调用使用完整 API Key。这些接口也接受页面会话 Cookie 或 Authorization: Bearer <access-token>;任选一种鉴权方式。资源按用户归属隔离。
content-type必填application/json请求体为一个 JSON 对象,最大 1 MiB。

路径参数

字段类型说明
id必填string (UUID)创建或列表返回的持久化云浏览器 id,不是运行时 sessionId。

请求体

字段类型说明
proxyAPI Key 鉴权时objectAPI Key 每次启动必须显式传顶层有效 proxy;历史 browserSettings.proxy、上次运行代理、countryCode 或伪造 source 都不能替代。仅接受 http 或 socks5:{server: "http://proxy.example.com:8080"} 或 {protocol: "socks5", host: "proxy.example.com", port: 1080}。端口为 1-65535 的整数或整数字符串;server 必须含端口,不含 URL 凭据、查询或片段,不能同时传 host。username/password 可选但须成对非空字符串,不能写在 URL 内。代理失败不得回退直连。
apiKeyId会话/Bearer 鉴权时string (UUID)页面会话/Bearer 鉴权必填,选择本人有效 Key。API Key 鉴权时自动使用当前 Key;若同时传 apiKeyId 必须与之相同。
countryCodestring (session/Bearer only)页面可明确选择 GLOBAL 或支持的二字地区码(例如 FR),优先同地区可信代理,不可用时动态代理兜底;空字符串不算选择。页面启动在合并保存配置与本次覆盖后也必须有 proxy 或非空 countryCode。API Key 不能用它替代 proxy;同次请求不得同时出现两者。本次选择会清除相反的已保存路由,仅作用于运行快照,不写回档案。
cookiescookie[]可选本次运行覆盖,必须为数组;优先于保存快照,不写回档案配置。
fingerprintobject可选本次覆盖,按字段与保存设置合并。webRtc: forward|real|disabled(旧 random 转 forward);webGpu: random|real|disabled;doNotTrack: random|enabled|disabled;webGl、webGlImage、canvas、audioContext、clientRects、speechVoices、fonts、hardware: random|real。兼容 hardwareConcurrency/deviceMemory 整数 1-64;未知、非法或冲突组合返回 INVALID_FINGERPRINT_SETTINGS。

响应

200
application/json同步等待启动确认,只在 running 后返回 {ok: true, runtime},不会把 starting 当成功。需要有效付费套餐,成功启动至停止按已开始分钟计费,每分钟 1 credit,不足 1 分钟按 1 分钟。runtime 字段见查询接口;neko 不含 cdpBaseUrl。
400
application/jsonPROXY_REQUIRED:缺少本次顶层 proxy;INVALID_PROXY:代理无效;COUNTRY_PROXY_CONFLICT:同次传 proxy/countryCode;INVALID_COUNTRY_CODE、INVALID_FINGERPRINT_SETTINGS、Invalid cookies。body/cookies/fingerprint 类型错误,或页面缺少 apiKeyId、选择的 Key 不存在/停用/过期也返回 400。
401
application/json鉴权缺失、无效或已过期。
402
application/jsonPAID_PLAN_REQUIRED:无有效付费套餐;INSUFFICIENT_CREDITS:余额不足 1 credit(附 balance、requiredCredits)。
403
application/jsonapiKeyId 与认证 Key 不一致,或所选 Key 不属于当前用户。
404
application/json档案不存在或不属于当前用户。
409
application/jsonCLOUD_BROWSER_CONCURRENCY_LIMIT:用户额度已满或为 0。Browser is already running(无 code):该档案已有活动会话。 limit 是套餐允许保存的档案数量;runningLimit 是用户同时运行上限;runningCount 统计该用户所有档案的 starting、running、stopping,会跨分页、API Key 和页面共享,不包含临时 /cdp/sessions。users.cloud_browser_running_limit 为 NULL 或负数时默认 1,0 禁止新启动,正数为上限。列表和每次启动实时读取;下调不会主动关闭已有实例。全局容量仍单独限制,不叠加临时 CDP 的每 Key 并发限制。
502
application/jsonCLOUD_RUNTIME_AUTH_FAILED、CLOUD_RUNTIME_NOT_FOUND、CLOUD_RUNTIME_HTTP_ERROR、CLOUD_RUNTIME_INVALID_RESPONSE 或 CLOUD_RUNTIME_CONTROLLER_FAILED:运行时拒绝或响应异常。
503
application/jsonCLUSTER_NO_CAPACITY:在线节点无容量,附可空 nextAvailableAt、retryAfterMs;CDP session capacity exhausted(无 code):全局容量满。也可能是 DYNAMIC_PROXY_NOT_CONFIGURED、MANAGED_PROXY_UNAVAILABLE、CLOUD_RUNTIME_CONFIG_INVALID 或 CLOUD_RUNTIME_UNREACHABLE。代理失败不会直连;先查询档案状态再决定重试。
503
application/jsonCDP_WORKER_UNAVAILABLE,或无 code 的 Cloud browser runtime is unavailable。原节点记录丢失、bootId 改变或暂时失联都不能证明已停止;保留会话和运行额度,连接地址可能省略。
504
application/jsonCLOUD_RUNTIME_TIMEOUT:启动超时不代表实例不存在;查询状态,必要时重试停止。未确认回收时保留 stopping 和额度。
500
application/jsonInternal error:服务内部错误。

请求示例

cURL
curl --fail-with-body --silent --show-error --max-time 65 \
  -X POST 'https://api.adscrawl.net/cloud-browsers/<browser-id>/start' \
  -H 'x-api-key: <api-key>' \
  -H 'content-type: application/json' \
  --data '{
  "proxy": {
    "server": "http://proxy.example.com:8080",
    "username": "<proxy-user>",
    "password": "<proxy-password>"
  }
}'
JSON
{
  "proxy": {
    "server": "http://proxy.example.com:8080",
    "username": "<proxy-user>",
    "password": "<proxy-password>"
  }
}
SOCKS5
{
  "proxy": {
    "protocol": "socks5",
    "host": "proxy.example.com",
    "port": 1080,
    "username": "<proxy-user>",
    "password": "<proxy-password>"
  }
}
Bearer 地区
curl --fail-with-body --silent --show-error --max-time 65 \
  'https://api.adscrawl.net/cloud-browsers/<browser-id>/start' \
  -H 'Authorization: Bearer <access-token>' \
  -H 'content-type: application/json' \
  --data '{
  "apiKeyId": "<api-key-id>",
  "countryCode": "GLOBAL"
}'

响应示例

200 neko
{
  "ok": true,
  "runtime": {
    "runtimeKind": "neko",
    "status": "running",
    "sessionId": "<session-id>",
    "expiresAt": "2026-09-07T09:00:00.000Z",
    "connectUrl": "https://api.adscrawl.net/cloud-browser-runtime/<session-id>/?usr=adscrawl&pwd=adscrawl"
  }
}
400
{
  "error": "API key starts require an explicit proxy in every request",
  "code": "PROXY_REQUIRED"
}
409
{
  "error": "Cloud browser running limit reached",
  "code": "CLOUD_BROWSER_CONCURRENCY_LIMIT"
}
503
{
  "error": "Cloud browser cluster has no available capacity",
  "code": "CLUSTER_NO_CAPACITY",
  "nextAvailableAt": null,
  "retryAfterMs": null
}
POST/cloud-browsers/{id}/stop

停止云浏览器

请求

请求头

字段类型说明
x-api-keyAPI Key 鉴权时stringAPI 调用使用完整 API Key。这些接口也接受页面会话 Cookie 或 Authorization: Bearer <access-token>;任选一种鉴权方式。资源按用户归属隔离。

路径参数

字段类型说明
id必填string (UUID)创建或列表返回的持久化云浏览器 id,不是运行时 sessionId。

响应

200
application/jsonruntime.status=stopped:已确认停止或本来就无活动会话,释放运行额度。manual 和 launch 档案均保留配置、快照和来源,继续占保存额度;可再次启动,只有显式删除才删档。重复停止仍返回 stopped,不重复计费。source 标识来源,deleteOnStop 为 false;历史已删除记录才返回 deleted: true。无活动会话时省略 sessionId。
202
application/jsonruntime.status=stopping:另一个停止请求正在执行,尚未完成,仍占运行额度。继续 GET 详情做有界轮询;如一直 stopping,可重试同一 stop,直到确认 stopped。创建接口的 Node.js 完整流程含轮询和重试示例。
401
application/json鉴权缺失、无效或已过期。
404
application/json档案不存在或不属于当前用户。
409
application/jsonCDP_SESSION_STARTING:启动尚未完成,等待后重试停止。
503
application/jsonCDP_WORKER_UNAVAILABLE,或无 code 的 Cloud browser runtime is unavailable。原节点记录丢失、bootId 改变或暂时失联都不能证明已停止;保留会话和运行额度,连接地址可能省略。
500
application/jsonInternal error:停止失败或超时不能当作成功。会话仍可能 stopping 并占额度;先查询,修复可达性后重试 stop。原节点身份丢失时不能改向新节点删除或手工伪造 stopped 释放额度。

请求示例

cURL
curl --fail-with-body --silent --show-error --max-time 65 \
  -X POST 'https://api.adscrawl.net/cloud-browsers/<browser-id>/stop' \
  -H 'x-api-key: <api-key>'

响应示例

200 stopped
{
  "ok": true,
  "runtime": {
    "status": "stopped",
    "sessionId": "<session-id>"
  }
}
202 stopping
{
  "ok": true,
  "runtime": {
    "status": "stopping",
    "sessionId": "<session-id>"
  }
}
409
{
  "error": "CDP session is starting; retry after startup completes",
  "code": "CDP_SESSION_STARTING"
}
503
{
  "error": "Cloud browser runtime is unavailable"
}
200 launch retained
{
  "ok": true,
  "source": "launch",
  "deleteOnStop": false,
  "runtime": {
    "status": "stopped",
    "sessionId": "<session-id>"
  }
}