cdpfleet / Shared threads
Plans · shared threads
Pooled browser-minutes for bursty work.
Each shared thread adds browser-minutes to one account pool and one more browser you can run at a time. Spend the pool on a few long sessions or many short ones — from $5 a month for 5 threads.
- $1–$4per thread / month
- 60–480min per thread per day
- 25%of the pool per rolling hour
- 5–1,000threads
One pool per account
A shared plan has two numbers: threads — how many browsers can run at once — and browser-minutes per thread per day. Every thread contributes its minutes to one account pool; there are no per-thread balances.
For example, 10 threads of Shared 240 put 2,400 browser-minutes a day in the pool, up to 600 in any rolling 60 minutes, with up to 10 threads' worth of browsers at once. Use them on 10 headless browsers for four hours, or on hundreds of one-minute jobs. The pool resets at midnight UTC and unused minutes don't carry over.
Minutes are metered to the second as thread-seconds: a headful browser takes 2 threads, so it uses the pool twice as fast as a headless one.
Prices
| Shared, per month | 5 threads | 10 threads | 25 threads | 50 threads | 100 threads | 500 threads | 1,000 threads |
|---|---|---|---|---|---|---|---|
| Shared 60$1 / thread · 60 browser-minutes/day per thread | $5300 min/day · 75 min/hour | $10600 min/day · 150 min/hour | $251,500 min/day · 375 min/hour | $503,000 min/day · 750 min/hour | $1006,000 min/day · 1,500 min/hour | $50030,000 min/day · 7,500 min/hour | $1,00060,000 min/day · 15,000 min/hour |
| Shared 120$1.50 / thread · 120 browser-minutes/day per thread | $7.50600 min/day · 150 min/hour | $151,200 min/day · 300 min/hour | $37.503,000 min/day · 750 min/hour | $756,000 min/day · 1,500 min/hour | $15012,000 min/day · 3,000 min/hour | $75060,000 min/day · 15,000 min/hour | $1,500120,000 min/day · 30,000 min/hour |
| Shared 240$2.50 / thread · 240 browser-minutes/day per thread | $12.501,200 min/day · 300 min/hour | $252,400 min/day · 600 min/hour | $62.506,000 min/day · 1,500 min/hour | $12512,000 min/day · 3,000 min/hour | $25024,000 min/day · 6,000 min/hour | $1,250120,000 min/day · 30,000 min/hour | $2,500240,000 min/day · 60,000 min/hour |
| Shared 480$4 / thread · 480 browser-minutes/day per thread | $202,400 min/day · 600 min/hour | $404,800 min/day · 1,200 min/hour | $10012,000 min/day · 3,000 min/hour | $20024,000 min/day · 6,000 min/hour | $40048,000 min/day · 12,000 min/hour | $2,000240,000 min/day · 60,000 min/hour | $4,000480,000 min/day · 120,000 min/hour |
At full use the effective price per browser-hour is Shared 60 $0.033, Shared 120 $0.025, Shared 240 $0.021, Shared 480 $0.017 — see the comparison with other cloud browsers.
Before a session starts
All of these must hold, or the launch is refused with a clear status you can act on:
| Check | If not |
|---|---|
| A free thread | 429 threads_exceeded — close a session or wait (Retry-After: 1). |
| Minutes left in today's pool | 429 daily_quota_exhausted — Retry-After counts down to midnight UTC. |
| Minutes left in the rolling hour (25% of the pool) | 429 hourly_quota_exhausted — the window rolls forward continuously. |
| Room in the shared fleet | 503 shared_capacity_full — retry after 5 s. Dedicated threads are never refused for this. |
Leases and timeouts
- Shared sessions run on 15-minute leases that renew automatically while shared capacity allows; a session can run up to 24 hours, within your remaining minutes.
- The idle timeout is 120 seconds by default and up to 10 minutes on shared plans (idle minutes count); dedicated threads can keep a quiet browser open for up to 24 hours.
keep_alive(reconnect to the same browser after a disconnect) is a dedicated-thread feature.- Short jobs should end themselves:
inactivity_timeoutandoverall_timeoutmake a hung script stop billing — see the burst-jobs recipe below.
// npm install [email protected]
// Browsers run on cdpfleet, so no `npx playwright install` is needed.
import { chromium } from 'playwright';
const KEY = process.env.CDPFLEET_API_KEY;
// 1. Launch the browser
const res = await fetch('https://starter.cdpfleet.com/chromium/session', {
method: 'POST',
headers: { 'x-api-key': KEY, 'content-type': 'application/json' },
body: JSON.stringify({
proxy: 'http://user:[email protected]:8080',
headless: 'new',
inactivity_timeout: '15s',
overall_timeout: '2m',
}),
});
if (!res.ok) throw new Error(`launch failed: ${res.status} ${await res.text()}`);
const { wsUrl } = await res.json();
// 2. Connect and drive it
const browser = await chromium.connect(wsUrl, { headers: { 'x-api-key': KEY } });
const page = await browser.newPage();
await page.goto('https://example.com');
console.log(await page.title());
await browser.close(); // ends the session and stops billing
# pip install playwright==1.60.0 requests
# Browsers run on cdpfleet, so no `playwright install` is needed.
import os
import requests
from playwright.sync_api import sync_playwright
KEY = os.environ["CDPFLEET_API_KEY"]
# 1. Launch the browser
res = requests.post(
"https://starter.cdpfleet.com/chromium/session",
headers={"x-api-key": KEY},
json={
"proxy": "http://user:[email protected]:8080",
"headless": "new",
"inactivity_timeout": "15s",
"overall_timeout": "2m",
},
timeout=60,
)
res.raise_for_status()
ws_url = res.json()["wsUrl"]
# 2. Connect and drive it
with sync_playwright() as p:
browser = p.chromium.connect(ws_url, headers={"x-api-key": KEY})
page = browser.new_page()
page.goto("https://example.com")
print(page.title())
browser.close() # ends the session and stops billing
// Maven: com.microsoft.playwright:playwright:1.60.0 and com.google.code.gson:gson:2.11.0
// Run with PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1: browsers run on cdpfleet.
import com.google.gson.JsonParser;
import com.microsoft.playwright.*;
import java.net.URI;
import java.net.http.*;
import java.util.Map;
public class Example {
public static void main(String[] args) throws Exception {
String key = System.getenv("CDPFLEET_API_KEY");
// 1. Launch the browser
String body = """
{
"proxy": "http://user:[email protected]:8080",
"headless": "new",
"inactivity_timeout": "15s",
"overall_timeout": "2m"
}
""";
HttpResponse<String> res = HttpClient.newHttpClient().send(
HttpRequest.newBuilder(URI.create("https://starter.cdpfleet.com/chromium/session"))
.header("x-api-key", key)
.header("content-type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build(),
HttpResponse.BodyHandlers.ofString());
if (res.statusCode() != 200) {
throw new RuntimeException("launch failed: " + res.statusCode() + " " + res.body());
}
String wsUrl = JsonParser.parseString(res.body()).getAsJsonObject().get("wsUrl").getAsString();
// 2. Connect and drive it
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().connect(wsUrl,
new BrowserType.ConnectOptions().setHeaders(Map.of("x-api-key", key)));
Page page = browser.newPage();
page.navigate("https://example.com");
System.out.println(page.title());
browser.close(); // ends the session and stops billing
}
}
}
// dotnet add package Microsoft.Playwright --version 1.60.0
// Browsers run on cdpfleet, so no `playwright install` is needed.
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using Microsoft.Playwright;
var key = Environment.GetEnvironmentVariable("CDPFLEET_API_KEY")!;
// 1. Launch the browser
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", key);
var body = """
{
"proxy": "http://user:[email protected]:8080",
"headless": "new",
"inactivity_timeout": "15s",
"overall_timeout": "2m"
}
""";
var res = await http.PostAsync("https://starter.cdpfleet.com/chromium/session",
new StringContent(body, Encoding.UTF8, "application/json"));
if (!res.IsSuccessStatusCode)
throw new Exception($"launch failed: {(int)res.StatusCode} {await res.Content.ReadAsStringAsync()}");
var wsUrl = (await res.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("wsUrl").GetString()!;
// 2. Connect and drive it
using var playwright = await Playwright.CreateAsync();
var browser = await playwright.Chromium.ConnectAsync(wsUrl, new BrowserTypeConnectOptions
{
Headers = new Dictionary<string, string> { ["x-api-key"] = key },
});
var page = await browser.NewPageAsync();
await page.GotoAsync("https://example.com");
Console.WriteLine(await page.TitleAsync());
await browser.CloseAsync(); // ends the session and stops billing
// go get github.com/playwright-community/[email protected]
//
// One-time driver setup (needs Node.js 18+): playwright-go can no longer download the
// 1.60.0 driver itself, so build it from npm and point PLAYWRIGHT_DRIVER_PATH at it:
// mkdir -p ~/.cache/pw-driver-1.60.0 && cd ~/.cache/pw-driver-1.60.0 &&
// curl -sL https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz | tar xz &&
// ln -sf "$(command -v node)" node
// export PLAYWRIGHT_DRIVER_PATH=~/.cache/pw-driver-1.60.0
// Browsers run on cdpfleet, so no browsers are downloaded (SkipInstallBrowsers).
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
"github.com/playwright-community/playwright-go"
)
func main() {
key := os.Getenv("CDPFLEET_API_KEY")
// 1. Launch the browser
body := `{
"proxy": "http://user:[email protected]:8080",
"headless": "new",
"inactivity_timeout": "15s",
"overall_timeout": "2m"
}`
req, _ := http.NewRequest("POST", "https://starter.cdpfleet.com/chromium/session", strings.NewReader(body))
req.Header.Set("x-api-key", key)
req.Header.Set("content-type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
msg, _ := io.ReadAll(res.Body)
log.Fatalf("launch failed: %s %s", res.Status, msg)
}
var session struct {
WsURL string `json:"wsUrl"`
}
if err := json.NewDecoder(res.Body).Decode(&session); err != nil {
log.Fatal(err)
}
// 2. Connect and drive it (Install fetches only the Playwright driver, once)
opts := &playwright.RunOptions{SkipInstallBrowsers: true}
if err := playwright.Install(opts); err != nil {
log.Fatal(err)
}
pw, err := playwright.Run(opts)
if err != nil {
log.Fatal(err)
}
defer pw.Stop()
browser, err := pw.Chromium.Connect(session.WsURL, playwright.BrowserTypeConnectOptions{
Headers: map[string]string{"x-api-key": key},
})
if err != nil {
log.Fatal(err)
}
page, err := browser.NewPage()
if err != nil {
log.Fatal(err)
}
if _, err := page.Goto("https://example.com"); err != nil {
log.Fatal(err)
}
title, _ := page.Title()
fmt.Println(title)
browser.Close() // ends the session and stops billing
}
Shared or dedicated?
Shared threads fit bursty and scheduled work — crawls, monitoring, tests — where the browsers don't run around the clock. If a browser runs most of the day, a dedicated thread at $5 a month with unlimited minutes is cheaper per hour ($0.007 at 24/7) and never waits for shared capacity.
| Community | Shared | Dedicated | |
|---|---|---|---|
| Price | Free | $1–$4 per thread / month | $5 per thread / month |
| Concurrent browsers | 2 threads | Up to your thread count | Up to your thread count |
| Daily browser-minutes | 60 per thread | Each thread adds its minutes to one account pool | Unlimited |
| Rolling-hour limit | 25% of the daily pool in any 60 minutes | 25% of the daily pool in any 60 minutes | None |
| Session length | Up to 15 minutes | Up to 24 h | Up to 24 h |
| Session leases | Lowest priority, 5-minute leases | 15-minute leases, renewed automatically while shared capacity allows | None — capacity is reserved |
| Idle timeout | 120 s by default, up to 5 min | 120 s by default, up to 10 min | 120 s by default, up to 24 h |
| Launch rate | At least 2 per second and 10 per minute | Threads ÷ 5 per second, threads × 6 per minute (at least 2 and 10) | Twice the shared rate: threads ÷ 5 × 2 per second, threads × 12 per minute |
| Proxies | Included (shared), or your own | Your own, the residential add-on, or the free Community proxy | Your own, the residential add-on, or the free Community proxy |
| Per session | 5 open pages, 3 GB memory | 10 open pages, 4 GB memory | 20 open pages, 8 GB memory |
| Recordings, profiles, keep-alive | Not included | Recordings, and profiles: 20 per thread (at least 100) | Recordings, keep-alive, and profiles: 30 per thread (at least 100) |
| Sizes | One size; invite-only for now | 5–1,000 threads | 5–10,000 threads, custom above |