Profiles
List profiles
http://127.0.0.1:40325/profilesLists persistent profiles (temporary profiles are hidden), newest first, pinned on top. Each entry is enriched with live run state.
Permanent JWT from Settings → Automation API.
200Profile list.application/json
Launcher-facing profile metadata (returned by create).
ISO-8601 or null.
Icon accent as #rrggbb; null means it is derived from the name, which is what the browser does when nothing is chosen.
Extension-library ids loaded at launch.
cdpobject · CdpInfo· nullableoptionalChrome DevTools Protocol endpoint of a running profile.
Show propertiesHide properties
Chrome DevTools Protocol endpoint of a running profile.
Chrome-chosen remote-debugging port.
REST base (/json, /json/version).
Browser-level WS endpoint for Puppeteer/Playwright connect.
401Missing or invalid Bearer token.
/profilesGET /profiles HTTP/1.1
Host: 127.0.0.1:40325
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*curl -X GET 'http://127.0.0.1:40325/profiles' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN'import requests
# Permanent JWT from Settings → Automation API.
token = "YOUR_SECRET_TOKEN"
url = "http://127.0.0.1:40325/profiles"
headers = {
"Authorization": f"Bearer {token}",
}
response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
print(response.status_code)
print(response.text)// Permanent JWT from Settings → Automation API.
const token = "YOUR_SECRET_TOKEN";
const url = "http://127.0.0.1:40325/profiles";
const response = await fetch(url, {
method: "GET",
headers: {
"Authorization": `Bearer ${token}`,
},
});
console.log(response.status);
console.log(await response.text());package main
import (
"fmt"
"io"
"log"
"net/http"
)
func main() {
// Permanent JWT from Settings → Automation API.
token := "YOUR_SECRET_TOKEN"
url := "http://127.0.0.1:40325/profiles"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, tokio = { version = "1", features = ["full"] }
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Permanent JWT from Settings → Automation API.
let token = "YOUR_SECRET_TOKEN";
let client = reqwest::Client::new();
let response = client
.get("http://127.0.0.1:40325/profiles")
.header("Authorization", format!("Bearer {token}"))
.send()
.await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// Permanent JWT from Settings → Automation API.
var token = "YOUR_SECRET_TOKEN";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(HttpMethod.Get, "http://127.0.0.1:40325/profiles");
var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}// build: c++ -std=c++17 main.cpp -lcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
// Permanent JWT from Settings → Automation API.
const std::string token = "YOUR_SECRET_TOKEN";
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "curl_easy_init failed\n";
curl_global_cleanup();
return 1;
}
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + token).c_str());
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:40325/profiles");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
const CURLcode rc = curl_easy_perform(curl);
if (rc != CURLE_OK) {
std::cerr << curl_easy_strerror(rc) << "\n";
} else {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
std::cout << status << "\n" << response << "\n";
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return rc == CURLE_OK ? 0 : 1;
}[
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "text",
"notes": "text",
"proxy_id": "text",
"last_launched_at": "text",
"created_at": "text",
"pinned": true,
"folder": "text",
"color": "text",
"extensions": [
"text"
],
"running": true,
"pid": 1,
"cdp": {
"port": 1,
"http_url": "http://127.0.0.1:53217",
"web_socket_debugger_url": "ws://127.0.0.1:53217/devtools/browser/ab12-..."
}
}
]Create a profile
http://127.0.0.1:40325/profilesPersists a profile from a client-supplied fingerprint exactly as given (no re-randomization; uniquification already happened in /fingerprint/new). Use folder to file it; bind a proxy by stored proxy_id or attach one inline via proxy (a string that is NOT saved to the proxy store).
Permanent JWT from Settings → Automation API.
Bind a proxy already in the store (by id).
Attach a proxy by string (host:port:user:pass or scheme://user:pass@host:port). On a persistent profile it is added to the proxy store (deduped by endpoint) and full-tested (UDP + geo), then bound by id; so it appears in the proxy list and QUIC/WebRTC gating has a cached result. On a temporary profile it is attached inline (not stored). Ignored if proxy_id is set.
Folder tag (ignored on /folders/{folder}/profiles, which wins).
Accent for the profile's window icon and for the pill carrying its name in the omnibox. Omit it and the icon derives a colour from the name while the pill keeps the browser's own toolbar colour.
Extension-library ids (GET /extensions), loaded at launch. An id the library does not hold is a 400 rather than a profile that silently starts without it.
Claimed display refresh rate, written into screen.refresh_rate. No web API reports it; a page measures it by timing requestAnimationFrame, which is why leaving it out is not neutral; absent means 60, what most machines report, rather than whatever the host's own screen does. Frames can only be slowed, so the effective rate is the closest whole division of the host's panel at or under this.
fingerprintobject · FingerprintrequiredStored verbatim. Get one from /fingerprint/new and edit as needed.
Show propertiesHide properties
Stored verbatim. Get one from /fingerprint/new and edit as needed.
0 = overrides-only mode (the common case).
navigatorobjectoptionalShow propertiesHide properties
81632screenobjectoptionalShow propertiesHide properties
srgbp3rec2020How often the claimed display refreshes. Absent means 60. See the refresh_rate field on the create/edit requests.
client_hintsobjectoptionalSec-CH-UA family (browser.vision calls this hints).
Show propertiesHide properties
Sec-CH-UA family (browser.vision calls this hints).
webglobjectoptionalShow propertiesHide properties
WebRTC handling mode.
autotcp_onlyblocknoiseobject · NoisePrefsoptionalPer-vector anti-fingerprint noise. Each block is {enabled, seed} (+ feature-specific knobs). enabled:false = pass-through.
Show propertiesHide properties
Per-vector anti-fingerprint noise. Each block is {enabled, seed} (+ feature-specific knobs). enabled:false = pass-through.
canvasobject · NoiseBlockoptionalShow propertiesHide properties
Per-profile entropy; 0 = derive automatically.
webglobject · NoiseBlockoptionalShow propertiesHide properties
Per-profile entropy; 0 = derive automatically.
audioobject · NoiseBlockoptionalShow propertiesHide properties
Per-profile entropy; 0 = derive automatically.
client_rectsobject · NoiseBlockoptionalShow propertiesHide properties
Per-profile entropy; 0 = derive automatically.
sensorsobject · NoiseBlockoptionalShow propertiesHide properties
Per-profile entropy; 0 = derive automatically.
fontsobject · NoiseBlockoptionalenabled:true hides a small deterministic per-profile subset of non-essential fonts (real host fonts otherwise pass through).
Show propertiesHide properties
enabled:true hides a small deterministic per-profile subset of non-essential fonts (real host fonts otherwise pass through).
Per-profile entropy; 0 = derive automatically.
networkobjectoptionalShow propertiesHide properties
Local-network port-scan defense (ports_protection).
IANA name, or "auto" to resolve from the bound proxy at launch.
200Created profile metadata.application/json
Launcher-facing profile metadata (returned by create).
ISO-8601 or null.
Icon accent as #rrggbb; null means it is derived from the name, which is what the browser does when nothing is chosen.
Extension-library ids loaded at launch.
400Missing/!object `fingerprint`, or an unparseable proxy string.application/json
401Missing or invalid Bearer token.
/profilesPOST /profiles HTTP/1.1
Host: 127.0.0.1:40325
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
{
"name": "text",
"notes": "text",
"proxy_id": "text",
"proxy": "socks5://user:[email protected]:1080",
"folder": "text",
"color": "#2FCB80",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
}curl -X POST 'http://127.0.0.1:40325/profiles' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"text","notes":"text","proxy_id":"text","proxy":"socks5://user:[email protected]:1080","folder":"text","color":"#2FCB80","extensions":["text"],"refresh_rate":60,"fingerprint":{"name":"text","notes":"text","seed":1,"navigator":{"user_agent":"text","platform":"Win32","hardware_concurrency":12,"device_memory":16,"language":"text","do_not_track":true},"screen":{"width":1,"height":1,"avail_width":1,"avail_height":1,"color_depth":24,"device_pixel_ratio":2,"color_gamut":"","refresh_rate":60},"client_hints":{"platform":"text","platform_version":"text","architecture":"x86","bitness":"64","mobile":true},"webgl":{"unmasked_vendor":"text","unmasked_renderer":"text"},"webgpu":{},"webrtc":"auto","noise":{"canvas":{"enabled":true,"seed":1},"webgl":{"enabled":true,"seed":1,"intensity":1},"audio":{"enabled":true,"seed":1,"intensity":1},"client_rects":{"enabled":true,"seed":1,"max_offset":1},"sensors":{"enabled":true,"seed":1},"fonts":{"enabled":true,"seed":1}},"network":{"blocked_ports":[1]},"timezone":"text"}}'import requests
# Permanent JWT from Settings → Automation API.
token = "YOUR_SECRET_TOKEN"
url = "http://127.0.0.1:40325/profiles"
headers = {
"Authorization": f"Bearer {token}",
}
payload = {
"name": "text",
"notes": "text",
"proxy_id": "text",
"proxy": "socks5://user:[email protected]:1080",
"folder": "text",
"color": "#2FCB80",
"extensions": [
"text",
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": True,
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60,
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": True,
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text",
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": True,
"seed": 1,
},
"webgl": {
"enabled": True,
"seed": 1,
"intensity": 1,
},
"audio": {
"enabled": True,
"seed": 1,
"intensity": 1,
},
"client_rects": {
"enabled": True,
"seed": 1,
"max_offset": 1,
},
"sensors": {
"enabled": True,
"seed": 1,
},
"fonts": {
"enabled": True,
"seed": 1,
},
},
"network": {
"blocked_ports": [
1,
],
},
"timezone": "text",
},
}
response = requests.post(url, headers=headers, json=payload, timeout=30)
response.raise_for_status()
print(response.status_code)
print(response.text)// Permanent JWT from Settings → Automation API.
const token = "YOUR_SECRET_TOKEN";
const url = "http://127.0.0.1:40325/profiles";
const payload = {
"name": "text",
"notes": "text",
"proxy_id": "text",
"proxy": "socks5://user:[email protected]:1080",
"folder": "text",
"color": "#2FCB80",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
};
const response = await fetch(url, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
console.log(response.status);
console.log(await response.text());package main
import (
"bytes"
"fmt"
"io"
"log"
"net/http"
)
func main() {
// Permanent JWT from Settings → Automation API.
token := "YOUR_SECRET_TOKEN"
url := "http://127.0.0.1:40325/profiles"
body := bytes.NewBufferString(`{
"name": "text",
"notes": "text",
"proxy_id": "text",
"proxy": "socks5://user:[email protected]:1080",
"folder": "text",
"color": "#2FCB80",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
}`)
req, err := http.NewRequest("POST", url, body)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, tokio = { version = "1", features = ["full"] }, serde_json = "1"
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Permanent JWT from Settings → Automation API.
let token = "YOUR_SECRET_TOKEN";
let client = reqwest::Client::new();
let response = client
.post("http://127.0.0.1:40325/profiles")
.header("Authorization", format!("Bearer {token}"))
.json(&serde_json::json!({
"name": "text",
"notes": "text",
"proxy_id": "text",
"proxy": "socks5://user:[email protected]:1080",
"folder": "text",
"color": "#2FCB80",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
}))
.send()
.await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// Permanent JWT from Settings → Automation API.
var token = "YOUR_SECRET_TOKEN";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(HttpMethod.Post, "http://127.0.0.1:40325/profiles");
request.Content = new StringContent("""
{
"name": "text",
"notes": "text",
"proxy_id": "text",
"proxy": "socks5://user:[email protected]:1080",
"folder": "text",
"color": "#2FCB80",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}// build: c++ -std=c++17 main.cpp -lcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
// Permanent JWT from Settings → Automation API.
const std::string token = "YOUR_SECRET_TOKEN";
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "curl_easy_init failed\n";
curl_global_cleanup();
return 1;
}
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + token).c_str());
headers = curl_slist_append(headers, "Content-Type: application/json");
const std::string body = R"json({
"name": "text",
"notes": "text",
"proxy_id": "text",
"proxy": "socks5://user:[email protected]:1080",
"folder": "text",
"color": "#2FCB80",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
})json";
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:40325/profiles");
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(body.size()));
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
const CURLcode rc = curl_easy_perform(curl);
if (rc != CURLE_OK) {
std::cerr << curl_easy_strerror(rc) << "\n";
} else {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
std::cout << status << "\n" << response << "\n";
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return rc == CURLE_OK ? 0 : 1;
}{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "text",
"notes": "text",
"proxy_id": "text",
"last_launched_at": "text",
"created_at": "text",
"pinned": true,
"folder": "text",
"color": "text",
"extensions": [
"text"
]
}{
"error": "text"
}Create a temporary profile
http://127.0.0.1:40325/profiles/temporaryCreates a profile from a random (or specified) library fingerprint, uniquified like /fingerprint/new and stored verbatim, flagged temporary: hidden from listings and auto-deleted when its browser closes (or purged on next app start after a crash). Pair with POST /profiles/{id}/start.
Permanent JWT from Settings → Automation API.
Library entry to base off; random match for platform when omitted.
Used to pick a random fingerprint when fingerprint_id is omitted; host OS when both omitted.
WindowsmacOSLinuxInline proxy string (not saved to the store).
Claimed display refresh rate, written into screen.refresh_rate. No web API reports it; a page measures it by timing requestAnimationFrame, which is why leaving it out is not neutral; absent means 60, what most machines report, rather than whatever the host's own screen does. Frames can only be slowed, so the effective rate is the closest whole division of the host's panel at or under this.
noiseobjectoptionalPer-vector fingerprint noise. Omitted vectors keep their defaults (disabled). Two formats can be combined: shorthand {"canvas": true, "webgl": true}, which also applies the UI default intensity to webgl and client_rects, and a full object such as {"canvas": {"enabled": true, "seed": 42}}, matching the format returned by GET /profiles/{id}.
Fields are merged with the existing vector settings. A missing or zero seed generates a stable value from the profile ID.
Show propertiesHide properties
Per-vector fingerprint noise. Omitted vectors keep their defaults (disabled). Two formats can be combined: shorthand {"canvas": true, "webgl": true}, which also applies the UI default intensity to webgl and client_rects, and a full object such as {"canvas": {"enabled": true, "seed": 42}}, matching the format returned by GET /profiles/{id}.
Fields are merged with the existing vector settings. A missing or zero seed generates a stable value from the profile ID.
200Created temporary profile.application/json
The library entry the profile was generated from.
Whether an inline proxy string was attached.
400Unparseable proxy string, or an unknown noise vector.application/json
401Missing or invalid Bearer token.
404No matching fingerprint / empty library.application/json
/profiles/temporaryPOST /profiles/temporary HTTP/1.1
Host: 127.0.0.1:40325
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
{
"fingerprint_id": "text",
"platform": "Windows",
"proxy": "text",
"name": "text",
"folder": "text",
"refresh_rate": 60,
"noise": {
"canvas": true,
"webgl": {
"enabled": true,
"intensity": 0.0005
},
"fonts": true
}
}curl -X POST 'http://127.0.0.1:40325/profiles/temporary' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"fingerprint_id":"text","platform":"Windows","proxy":"text","name":"text","folder":"text","refresh_rate":60,"noise":{"canvas":true,"webgl":{"enabled":true,"intensity":0.0005},"fonts":true}}'import requests
# Permanent JWT from Settings → Automation API.
token = "YOUR_SECRET_TOKEN"
url = "http://127.0.0.1:40325/profiles/temporary"
headers = {
"Authorization": f"Bearer {token}",
}
payload = {
"fingerprint_id": "text",
"platform": "Windows",
"proxy": "text",
"name": "text",
"folder": "text",
"refresh_rate": 60,
"noise": {
"canvas": True,
"webgl": {
"enabled": True,
"intensity": 0.0005,
},
"fonts": True,
},
}
response = requests.post(url, headers=headers, json=payload, timeout=30)
response.raise_for_status()
print(response.status_code)
print(response.text)// Permanent JWT from Settings → Automation API.
const token = "YOUR_SECRET_TOKEN";
const url = "http://127.0.0.1:40325/profiles/temporary";
const payload = {
"fingerprint_id": "text",
"platform": "Windows",
"proxy": "text",
"name": "text",
"folder": "text",
"refresh_rate": 60,
"noise": {
"canvas": true,
"webgl": {
"enabled": true,
"intensity": 0.0005
},
"fonts": true
}
};
const response = await fetch(url, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
console.log(response.status);
console.log(await response.text());package main
import (
"bytes"
"fmt"
"io"
"log"
"net/http"
)
func main() {
// Permanent JWT from Settings → Automation API.
token := "YOUR_SECRET_TOKEN"
url := "http://127.0.0.1:40325/profiles/temporary"
body := bytes.NewBufferString(`{
"fingerprint_id": "text",
"platform": "Windows",
"proxy": "text",
"name": "text",
"folder": "text",
"refresh_rate": 60,
"noise": {
"canvas": true,
"webgl": {
"enabled": true,
"intensity": 0.0005
},
"fonts": true
}
}`)
req, err := http.NewRequest("POST", url, body)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, tokio = { version = "1", features = ["full"] }, serde_json = "1"
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Permanent JWT from Settings → Automation API.
let token = "YOUR_SECRET_TOKEN";
let client = reqwest::Client::new();
let response = client
.post("http://127.0.0.1:40325/profiles/temporary")
.header("Authorization", format!("Bearer {token}"))
.json(&serde_json::json!({
"fingerprint_id": "text",
"platform": "Windows",
"proxy": "text",
"name": "text",
"folder": "text",
"refresh_rate": 60,
"noise": {
"canvas": true,
"webgl": {
"enabled": true,
"intensity": 0.0005
},
"fonts": true
}
}))
.send()
.await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// Permanent JWT from Settings → Automation API.
var token = "YOUR_SECRET_TOKEN";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(HttpMethod.Post, "http://127.0.0.1:40325/profiles/temporary");
request.Content = new StringContent("""
{
"fingerprint_id": "text",
"platform": "Windows",
"proxy": "text",
"name": "text",
"folder": "text",
"refresh_rate": 60,
"noise": {
"canvas": true,
"webgl": {
"enabled": true,
"intensity": 0.0005
},
"fonts": true
}
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}// build: c++ -std=c++17 main.cpp -lcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
// Permanent JWT from Settings → Automation API.
const std::string token = "YOUR_SECRET_TOKEN";
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "curl_easy_init failed\n";
curl_global_cleanup();
return 1;
}
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + token).c_str());
headers = curl_slist_append(headers, "Content-Type: application/json");
const std::string body = R"json({
"fingerprint_id": "text",
"platform": "Windows",
"proxy": "text",
"name": "text",
"folder": "text",
"refresh_rate": 60,
"noise": {
"canvas": true,
"webgl": {
"enabled": true,
"intensity": 0.0005
},
"fonts": true
}
})json";
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:40325/profiles/temporary");
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(body.size()));
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
const CURLcode rc = curl_easy_perform(curl);
if (rc != CURLE_OK) {
std::cerr << curl_easy_strerror(rc) << "\n";
} else {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
std::cout << status << "\n" << response << "\n";
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return rc == CURLE_OK ? 0 : 1;
}{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "text",
"fingerprint_id": "text",
"temporary": true,
"proxy_inline": true
}{
"error": "text"
}{
"error": "text"
}Get a profile
http://127.0.0.1:40325/profiles/{id}Returns the full stored profile: the _meta envelope plus the flattened FingerprintConfig. If the profile is running, running and cdp are added.
Permanent JWT from Settings → Automation API.
Profile UUID.
200The stored profile.application/json
Full on-disk profile: the _meta envelope plus the flattened FingerprintConfig (all Fingerprint fields appear at the top level). running/cdp are present only while the profile runs.
_metaobjectoptionalShow propertiesHide properties
inline_proxyobject · ProxyEntry· nullableoptionalFull proxy (as embedded in _meta.inline_proxy).
Show propertiesHide properties
Full proxy (as embedded in _meta.inline_proxy).
socks5httphttpsBumped by every write. The desktop editor sends back the number it opened the profile at, so a save that would land on top of a change made through this API is refused rather than silently reverting it. API edits are never refused; they read the profile and write it back in one step.
cdpobject · CdpInfo· nullableoptionalChrome DevTools Protocol endpoint of a running profile.
Show propertiesHide properties
Chrome DevTools Protocol endpoint of a running profile.
Chrome-chosen remote-debugging port.
REST base (/json, /json/version).
Browser-level WS endpoint for Puppeteer/Playwright connect.
401Missing or invalid Bearer token.
404No such profile.application/json
/profiles/123e4567-e89b-12d3-a456-426614174000GET /profiles/123e4567-e89b-12d3-a456-426614174000 HTTP/1.1
Host: 127.0.0.1:40325
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*curl -X GET 'http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN'import requests
# Permanent JWT from Settings → Automation API.
token = "YOUR_SECRET_TOKEN"
url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000"
headers = {
"Authorization": f"Bearer {token}",
}
response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
print(response.status_code)
print(response.text)// Permanent JWT from Settings → Automation API.
const token = "YOUR_SECRET_TOKEN";
const url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000";
const response = await fetch(url, {
method: "GET",
headers: {
"Authorization": `Bearer ${token}`,
},
});
console.log(response.status);
console.log(await response.text());package main
import (
"fmt"
"io"
"log"
"net/http"
)
func main() {
// Permanent JWT from Settings → Automation API.
token := "YOUR_SECRET_TOKEN"
url := "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, tokio = { version = "1", features = ["full"] }
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Permanent JWT from Settings → Automation API.
let token = "YOUR_SECRET_TOKEN";
let client = reqwest::Client::new();
let response = client
.get("http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000")
.header("Authorization", format!("Bearer {token}"))
.send()
.await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// Permanent JWT from Settings → Automation API.
var token = "YOUR_SECRET_TOKEN";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(HttpMethod.Get, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000");
var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}// build: c++ -std=c++17 main.cpp -lcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
// Permanent JWT from Settings → Automation API.
const std::string token = "YOUR_SECRET_TOKEN";
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "curl_easy_init failed\n";
curl_global_cleanup();
return 1;
}
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + token).c_str());
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
const CURLcode rc = curl_easy_perform(curl);
if (rc != CURLE_OK) {
std::cerr << curl_easy_strerror(rc) << "\n";
} else {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
std::cout << status << "\n" << response << "\n";
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return rc == CURLE_OK ? 0 : 1;
}{
"_meta": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"proxy_id": "text",
"inline_proxy": {
"id": "text",
"name": "text",
"kind": "socks5",
"host": "text",
"port": 1,
"username": "text",
"password": "text",
"country": "text",
"notes": "text"
},
"last_launched_at": "text",
"created_at": "text",
"pinned": true,
"folder": "text",
"temporary": true,
"rev": 1
},
"running": true,
"cdp": {
"port": 1,
"http_url": "http://127.0.0.1:53217",
"web_socket_debugger_url": "ws://127.0.0.1:53217/devtools/browser/ab12-..."
}
}{
"error": "text"
}Delete a profile
http://127.0.0.1:40325/profiles/{id}Moves the profile to Trash. It can be restored for 7 days. The archive includes cookies, logins, web data, preferences, Local Storage, and IndexedDB. Cache data is excluded. The original configuration and user data directory are deleted after the archive is created.
Temporary profiles are deleted automatically when their browser closes and are not moved to Trash.
Permanent JWT from Settings → Automation API.
Profile UUID.
200Profile moved to Trash.application/json
Can be restored from Trash for 7 days.
401Missing or invalid Bearer token.
500Deletion failed.application/json
/profiles/123e4567-e89b-12d3-a456-426614174000DELETE /profiles/123e4567-e89b-12d3-a456-426614174000 HTTP/1.1
Host: 127.0.0.1:40325
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*curl -X DELETE 'http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN'import requests
# Permanent JWT from Settings → Automation API.
token = "YOUR_SECRET_TOKEN"
url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000"
headers = {
"Authorization": f"Bearer {token}",
}
response = requests.delete(url, headers=headers, timeout=30)
response.raise_for_status()
print(response.status_code)
print(response.text)// Permanent JWT from Settings → Automation API.
const token = "YOUR_SECRET_TOKEN";
const url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000";
const response = await fetch(url, {
method: "DELETE",
headers: {
"Authorization": `Bearer ${token}`,
},
});
console.log(response.status);
console.log(await response.text());package main
import (
"fmt"
"io"
"log"
"net/http"
)
func main() {
// Permanent JWT from Settings → Automation API.
token := "YOUR_SECRET_TOKEN"
url := "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000"
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, tokio = { version = "1", features = ["full"] }
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Permanent JWT from Settings → Automation API.
let token = "YOUR_SECRET_TOKEN";
let client = reqwest::Client::new();
let response = client
.delete("http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000")
.header("Authorization", format!("Bearer {token}"))
.send()
.await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// Permanent JWT from Settings → Automation API.
var token = "YOUR_SECRET_TOKEN";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(HttpMethod.Delete, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000");
var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}// build: c++ -std=c++17 main.cpp -lcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
// Permanent JWT from Settings → Automation API.
const std::string token = "YOUR_SECRET_TOKEN";
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "curl_easy_init failed\n";
curl_global_cleanup();
return 1;
}
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + token).c_str());
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000");
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
const CURLcode rc = curl_easy_perform(curl);
if (rc != CURLE_OK) {
std::cerr << curl_easy_strerror(rc) << "\n";
} else {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
std::cout << status << "\n" << response << "\n";
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return rc == CURLE_OK ? 0 : 1;
}{
"deleted": true,
"id": "123e4567-e89b-12d3-a456-426614174000",
"trashed": true
}{
"error": "text"
}Edit a profile
http://127.0.0.1:40325/profiles/{id}Updates only the provided fields. When fingerprint is given it REPLACES the stored fingerprint verbatim (no re-randomization). folder: "" unfiles the profile; proxy_id: "" unbinds the proxy; a proxy string is stored (deduped) + full-tested, then bound. Returns the updated stored profile.
Permanent JWT from Settings → Automation API.
Profile UUID.
"" unfiles (moves to All).
"" unbinds the proxy.
Proxy string; stored (deduped) + full-tested, then bound.
#rrggbb; "" goes back to the name-derived colour.
Replaces the whole list; [] loads none.
Claimed display refresh rate, applied AFTER fingerprint and written into screen.refresh_rate. No web API reports it; a page measures it by timing requestAnimationFrame, which is why leaving it out is not neutral; absent means 60, what most machines report, rather than whatever the host's own screen does. Frames can only be slowed, so the effective rate is the closest whole division of the host's panel at or under this.
fingerprintobject · FingerprintoptionalWhen present, REPLACES the stored fingerprint verbatim.
Show propertiesHide properties
When present, REPLACES the stored fingerprint verbatim.
0 = overrides-only mode (the common case).
navigatorobjectoptionalShow propertiesHide properties
81632screenobjectoptionalShow propertiesHide properties
srgbp3rec2020How often the claimed display refreshes. Absent means 60. See the refresh_rate field on the create/edit requests.
client_hintsobjectoptionalSec-CH-UA family (browser.vision calls this hints).
Show propertiesHide properties
Sec-CH-UA family (browser.vision calls this hints).
webglobjectoptionalShow propertiesHide properties
WebRTC handling mode.
autotcp_onlyblocknoiseobject · NoisePrefsoptionalPer-vector anti-fingerprint noise. Each block is {enabled, seed} (+ feature-specific knobs). enabled:false = pass-through.
Show propertiesHide properties
Per-vector anti-fingerprint noise. Each block is {enabled, seed} (+ feature-specific knobs). enabled:false = pass-through.
canvasobject · NoiseBlockoptionalShow propertiesHide properties
Per-profile entropy; 0 = derive automatically.
webglobject · NoiseBlockoptionalShow propertiesHide properties
Per-profile entropy; 0 = derive automatically.
audioobject · NoiseBlockoptionalShow propertiesHide properties
Per-profile entropy; 0 = derive automatically.
client_rectsobject · NoiseBlockoptionalShow propertiesHide properties
Per-profile entropy; 0 = derive automatically.
sensorsobject · NoiseBlockoptionalShow propertiesHide properties
Per-profile entropy; 0 = derive automatically.
fontsobject · NoiseBlockoptionalenabled:true hides a small deterministic per-profile subset of non-essential fonts (real host fonts otherwise pass through).
Show propertiesHide properties
enabled:true hides a small deterministic per-profile subset of non-essential fonts (real host fonts otherwise pass through).
Per-profile entropy; 0 = derive automatically.
networkobjectoptionalShow propertiesHide properties
Local-network port-scan defense (ports_protection).
IANA name, or "auto" to resolve from the bound proxy at launch.
200Updated stored profile.application/json
Full on-disk profile: the _meta envelope plus the flattened FingerprintConfig (all Fingerprint fields appear at the top level). running/cdp are present only while the profile runs.
_metaobjectoptionalShow propertiesHide properties
inline_proxyobject · ProxyEntry· nullableoptionalFull proxy (as embedded in _meta.inline_proxy).
Show propertiesHide properties
Full proxy (as embedded in _meta.inline_proxy).
socks5httphttpsBumped by every write. The desktop editor sends back the number it opened the profile at, so a save that would land on top of a change made through this API is refused rather than silently reverting it. API edits are never refused; they read the profile and write it back in one step.
cdpobject · CdpInfo· nullableoptionalChrome DevTools Protocol endpoint of a running profile.
Show propertiesHide properties
Chrome DevTools Protocol endpoint of a running profile.
Chrome-chosen remote-debugging port.
REST base (/json, /json/version).
Browser-level WS endpoint for Puppeteer/Playwright connect.
400Bad fingerprint (not an object) or unparseable proxy.application/json
401Missing or invalid Bearer token.
404No such profile.application/json
/profiles/123e4567-e89b-12d3-a456-426614174000PATCH /profiles/123e4567-e89b-12d3-a456-426614174000 HTTP/1.1
Host: 127.0.0.1:40325
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
{
"name": "text",
"notes": "text",
"folder": "text",
"proxy_id": "text",
"proxy": "text",
"color": "text",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
}curl -X PATCH 'http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"text","notes":"text","folder":"text","proxy_id":"text","proxy":"text","color":"text","extensions":["text"],"refresh_rate":60,"fingerprint":{"name":"text","notes":"text","seed":1,"navigator":{"user_agent":"text","platform":"Win32","hardware_concurrency":12,"device_memory":16,"language":"text","do_not_track":true},"screen":{"width":1,"height":1,"avail_width":1,"avail_height":1,"color_depth":24,"device_pixel_ratio":2,"color_gamut":"","refresh_rate":60},"client_hints":{"platform":"text","platform_version":"text","architecture":"x86","bitness":"64","mobile":true},"webgl":{"unmasked_vendor":"text","unmasked_renderer":"text"},"webgpu":{},"webrtc":"auto","noise":{"canvas":{"enabled":true,"seed":1},"webgl":{"enabled":true,"seed":1,"intensity":1},"audio":{"enabled":true,"seed":1,"intensity":1},"client_rects":{"enabled":true,"seed":1,"max_offset":1},"sensors":{"enabled":true,"seed":1},"fonts":{"enabled":true,"seed":1}},"network":{"blocked_ports":[1]},"timezone":"text"}}'import requests
# Permanent JWT from Settings → Automation API.
token = "YOUR_SECRET_TOKEN"
url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000"
headers = {
"Authorization": f"Bearer {token}",
}
payload = {
"name": "text",
"notes": "text",
"folder": "text",
"proxy_id": "text",
"proxy": "text",
"color": "text",
"extensions": [
"text",
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": True,
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60,
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": True,
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text",
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": True,
"seed": 1,
},
"webgl": {
"enabled": True,
"seed": 1,
"intensity": 1,
},
"audio": {
"enabled": True,
"seed": 1,
"intensity": 1,
},
"client_rects": {
"enabled": True,
"seed": 1,
"max_offset": 1,
},
"sensors": {
"enabled": True,
"seed": 1,
},
"fonts": {
"enabled": True,
"seed": 1,
},
},
"network": {
"blocked_ports": [
1,
],
},
"timezone": "text",
},
}
response = requests.patch(url, headers=headers, json=payload, timeout=30)
response.raise_for_status()
print(response.status_code)
print(response.text)// Permanent JWT from Settings → Automation API.
const token = "YOUR_SECRET_TOKEN";
const url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000";
const payload = {
"name": "text",
"notes": "text",
"folder": "text",
"proxy_id": "text",
"proxy": "text",
"color": "text",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
};
const response = await fetch(url, {
method: "PATCH",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
console.log(response.status);
console.log(await response.text());package main
import (
"bytes"
"fmt"
"io"
"log"
"net/http"
)
func main() {
// Permanent JWT from Settings → Automation API.
token := "YOUR_SECRET_TOKEN"
url := "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000"
body := bytes.NewBufferString(`{
"name": "text",
"notes": "text",
"folder": "text",
"proxy_id": "text",
"proxy": "text",
"color": "text",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
}`)
req, err := http.NewRequest("PATCH", url, body)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, tokio = { version = "1", features = ["full"] }, serde_json = "1"
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Permanent JWT from Settings → Automation API.
let token = "YOUR_SECRET_TOKEN";
let client = reqwest::Client::new();
let response = client
.patch("http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000")
.header("Authorization", format!("Bearer {token}"))
.json(&serde_json::json!({
"name": "text",
"notes": "text",
"folder": "text",
"proxy_id": "text",
"proxy": "text",
"color": "text",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
}))
.send()
.await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// Permanent JWT from Settings → Automation API.
var token = "YOUR_SECRET_TOKEN";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(HttpMethod.Patch, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000");
request.Content = new StringContent("""
{
"name": "text",
"notes": "text",
"folder": "text",
"proxy_id": "text",
"proxy": "text",
"color": "text",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}// build: c++ -std=c++17 main.cpp -lcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
// Permanent JWT from Settings → Automation API.
const std::string token = "YOUR_SECRET_TOKEN";
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "curl_easy_init failed\n";
curl_global_cleanup();
return 1;
}
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + token).c_str());
headers = curl_slist_append(headers, "Content-Type: application/json");
const std::string body = R"json({
"name": "text",
"notes": "text",
"folder": "text",
"proxy_id": "text",
"proxy": "text",
"color": "text",
"extensions": [
"text"
],
"refresh_rate": 60,
"fingerprint": {
"name": "text",
"notes": "text",
"seed": 1,
"navigator": {
"user_agent": "text",
"platform": "Win32",
"hardware_concurrency": 12,
"device_memory": 16,
"language": "text",
"do_not_track": true
},
"screen": {
"width": 1,
"height": 1,
"avail_width": 1,
"avail_height": 1,
"color_depth": 24,
"device_pixel_ratio": 2,
"color_gamut": "",
"refresh_rate": 60
},
"client_hints": {
"platform": "text",
"platform_version": "text",
"architecture": "x86",
"bitness": "64",
"mobile": true
},
"webgl": {
"unmasked_vendor": "text",
"unmasked_renderer": "text"
},
"webgpu": {},
"webrtc": "auto",
"noise": {
"canvas": {
"enabled": true,
"seed": 1
},
"webgl": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"audio": {
"enabled": true,
"seed": 1,
"intensity": 1
},
"client_rects": {
"enabled": true,
"seed": 1,
"max_offset": 1
},
"sensors": {
"enabled": true,
"seed": 1
},
"fonts": {
"enabled": true,
"seed": 1
}
},
"network": {
"blocked_ports": [
1
]
},
"timezone": "text"
}
})json";
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000");
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(body.size()));
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
const CURLcode rc = curl_easy_perform(curl);
if (rc != CURLE_OK) {
std::cerr << curl_easy_strerror(rc) << "\n";
} else {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
std::cout << status << "\n" << response << "\n";
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return rc == CURLE_OK ? 0 : 1;
}{
"_meta": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"proxy_id": "text",
"inline_proxy": {
"id": "text",
"name": "text",
"kind": "socks5",
"host": "text",
"port": 1,
"username": "text",
"password": "text",
"country": "text",
"notes": "text"
},
"last_launched_at": "text",
"created_at": "text",
"pinned": true,
"folder": "text",
"temporary": true,
"rev": 1
},
"running": true,
"cdp": {
"port": 1,
"http_url": "http://127.0.0.1:53217",
"web_socket_debugger_url": "ws://127.0.0.1:53217/devtools/browser/ab12-..."
}
}{
"error": "text"
}{
"error": "text"
}Launch a profile (with CDP)
http://127.0.0.1:40325/profiles/{id}/startSpawns the ShardX browser for the profile with remote-debugging enabled, resolves any auto timezone/locale/geo from the bound proxy, and returns the CDP endpoint once Chrome has written its DevToolsActivePort. CDP is enabled only on API launches (UI launches stay debugging-free for anti-detect). The call waits up to 30 seconds for the endpoint; if it still has none, cdp is null and cdp_error says what happened and where to read the port yourself. Works for both regular and temporary profiles.
Permanent JWT from Settings → Automation API.
Profile UUID.
Optional. Empty body launches headed.
Launch headless (--headless=new).
200Launched.application/json
OS process id.
cdpobject · CdpInfo· nullableoptionalChrome DevTools Protocol endpoint of a running profile.
Show propertiesHide properties
Chrome DevTools Protocol endpoint of a running profile.
Chrome-chosen remote-debugging port.
REST base (/json, /json/version).
Browser-level WS endpoint for Puppeteer/Playwright connect.
Why cdp is null, when it is. Absent otherwise.
401Missing or invalid Bearer token.
500Binary not configured / spawn failed.application/json
/profiles/123e4567-e89b-12d3-a456-426614174000/startPOST /profiles/123e4567-e89b-12d3-a456-426614174000/start HTTP/1.1
Host: 127.0.0.1:40325
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
{
"headless": false
}curl -X POST 'http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/start' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"headless":false}'import requests
# Permanent JWT from Settings → Automation API.
token = "YOUR_SECRET_TOKEN"
url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/start"
headers = {
"Authorization": f"Bearer {token}",
}
payload = {
"headless": False,
}
response = requests.post(url, headers=headers, json=payload, timeout=30)
response.raise_for_status()
print(response.status_code)
print(response.text)// Permanent JWT from Settings → Automation API.
const token = "YOUR_SECRET_TOKEN";
const url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/start";
const payload = {
"headless": false
};
const response = await fetch(url, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
console.log(response.status);
console.log(await response.text());package main
import (
"bytes"
"fmt"
"io"
"log"
"net/http"
)
func main() {
// Permanent JWT from Settings → Automation API.
token := "YOUR_SECRET_TOKEN"
url := "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/start"
body := bytes.NewBufferString(`{
"headless": false
}`)
req, err := http.NewRequest("POST", url, body)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, tokio = { version = "1", features = ["full"] }, serde_json = "1"
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Permanent JWT from Settings → Automation API.
let token = "YOUR_SECRET_TOKEN";
let client = reqwest::Client::new();
let response = client
.post("http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/start")
.header("Authorization", format!("Bearer {token}"))
.json(&serde_json::json!({
"headless": false
}))
.send()
.await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// Permanent JWT from Settings → Automation API.
var token = "YOUR_SECRET_TOKEN";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(HttpMethod.Post, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/start");
request.Content = new StringContent("""
{
"headless": false
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}// build: c++ -std=c++17 main.cpp -lcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
// Permanent JWT from Settings → Automation API.
const std::string token = "YOUR_SECRET_TOKEN";
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "curl_easy_init failed\n";
curl_global_cleanup();
return 1;
}
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + token).c_str());
headers = curl_slist_append(headers, "Content-Type: application/json");
const std::string body = R"json({
"headless": false
})json";
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/start");
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(body.size()));
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
const CURLcode rc = curl_easy_perform(curl);
if (rc != CURLE_OK) {
std::cerr << curl_easy_strerror(rc) << "\n";
} else {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
std::cout << status << "\n" << response << "\n";
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return rc == CURLE_OK ? 0 : 1;
}{
"profile_id": "text",
"pid": 1,
"headless": true,
"cdp": {
"port": 1,
"http_url": "http://127.0.0.1:53217",
"web_socket_debugger_url": "ws://127.0.0.1:53217/devtools/browser/ab12-..."
},
"cdp_error": "text"
}{
"error": "text"
}Stop a profile
http://127.0.0.1:40325/profiles/{id}/stopSends the browser a graceful shutdown (SIGTERM on Unix; 5s grace then SIGKILL). Temporary profiles are deleted as part of close. stopped is false if the profile wasn't running.
Permanent JWT from Settings → Automation API.
Profile UUID.
200Stop requested.application/json
401Missing or invalid Bearer token.
/profiles/123e4567-e89b-12d3-a456-426614174000/stopPOST /profiles/123e4567-e89b-12d3-a456-426614174000/stop HTTP/1.1
Host: 127.0.0.1:40325
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*curl -X POST 'http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/stop' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN'import requests
# Permanent JWT from Settings → Automation API.
token = "YOUR_SECRET_TOKEN"
url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/stop"
headers = {
"Authorization": f"Bearer {token}",
}
response = requests.post(url, headers=headers, timeout=30)
response.raise_for_status()
print(response.status_code)
print(response.text)// Permanent JWT from Settings → Automation API.
const token = "YOUR_SECRET_TOKEN";
const url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/stop";
const response = await fetch(url, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
},
});
console.log(response.status);
console.log(await response.text());package main
import (
"fmt"
"io"
"log"
"net/http"
)
func main() {
// Permanent JWT from Settings → Automation API.
token := "YOUR_SECRET_TOKEN"
url := "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/stop"
req, err := http.NewRequest("POST", url, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, tokio = { version = "1", features = ["full"] }
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Permanent JWT from Settings → Automation API.
let token = "YOUR_SECRET_TOKEN";
let client = reqwest::Client::new();
let response = client
.post("http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/stop")
.header("Authorization", format!("Bearer {token}"))
.send()
.await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// Permanent JWT from Settings → Automation API.
var token = "YOUR_SECRET_TOKEN";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(HttpMethod.Post, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/stop");
var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}// build: c++ -std=c++17 main.cpp -lcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
// Permanent JWT from Settings → Automation API.
const std::string token = "YOUR_SECRET_TOKEN";
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "curl_easy_init failed\n";
curl_global_cleanup();
return 1;
}
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + token).c_str());
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/stop");
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
const CURLcode rc = curl_easy_perform(curl);
if (rc != CURLE_OK) {
std::cerr << curl_easy_strerror(rc) << "\n";
} else {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
std::cout << status << "\n" << response << "\n";
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return rc == CURLE_OK ? 0 : 1;
}{
"profile_id": "text",
"stopped": true
}Export cookies
http://127.0.0.1:40325/profiles/{id}/cookiesReads the profile's Chromium cookie store and returns all cookies decrypted. Works whether the profile is running or stopped. Empty array if the profile has never launched.
Permanent JWT from Settings → Automation API.
Profile UUID.
200Cookies.application/json
cookiesobject · Cookie[]optionalShow propertiesHide properties
Cookie host (Chromium host_key), e.g. ".example.com".
Unix seconds; null/absent = session cookie.
Case-insensitive on import.
StrictLaxNoneunspecified401Missing or invalid Bearer token.
500Cookie DB read/decrypt failed.application/json
/profiles/123e4567-e89b-12d3-a456-426614174000/cookiesGET /profiles/123e4567-e89b-12d3-a456-426614174000/cookies HTTP/1.1
Host: 127.0.0.1:40325
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*curl -X GET 'http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN'import requests
# Permanent JWT from Settings → Automation API.
token = "YOUR_SECRET_TOKEN"
url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies"
headers = {
"Authorization": f"Bearer {token}",
}
response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
print(response.status_code)
print(response.text)// Permanent JWT from Settings → Automation API.
const token = "YOUR_SECRET_TOKEN";
const url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies";
const response = await fetch(url, {
method: "GET",
headers: {
"Authorization": `Bearer ${token}`,
},
});
console.log(response.status);
console.log(await response.text());package main
import (
"fmt"
"io"
"log"
"net/http"
)
func main() {
// Permanent JWT from Settings → Automation API.
token := "YOUR_SECRET_TOKEN"
url := "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, tokio = { version = "1", features = ["full"] }
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Permanent JWT from Settings → Automation API.
let token = "YOUR_SECRET_TOKEN";
let client = reqwest::Client::new();
let response = client
.get("http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies")
.header("Authorization", format!("Bearer {token}"))
.send()
.await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// Permanent JWT from Settings → Automation API.
var token = "YOUR_SECRET_TOKEN";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(HttpMethod.Get, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies");
var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}// build: c++ -std=c++17 main.cpp -lcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
// Permanent JWT from Settings → Automation API.
const std::string token = "YOUR_SECRET_TOKEN";
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "curl_easy_init failed\n";
curl_global_cleanup();
return 1;
}
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + token).c_str());
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
const CURLcode rc = curl_easy_perform(curl);
if (rc != CURLE_OK) {
std::cerr << curl_easy_strerror(rc) << "\n";
} else {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
std::cout << status << "\n" << response << "\n";
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return rc == CURLE_OK ? 0 : 1;
}{
"cookies": [
{
"domain": "text",
"name": "text",
"value": "text",
"path": "/",
"expires": 1,
"secure": false,
"http_only": false,
"same_site": "Strict"
}
]
}{
"error": "text"
}Import cookies
http://127.0.0.1:40325/profiles/{id}/cookiesWrites cookies into the profile's cookie store (re-encrypting to Chromium's v10 scheme). The profile must be stopped; a running browser rewrites the store on exit and would clobber the import.
Permanent JWT from Settings → Automation API.
Profile UUID.
cookiesobject · Cookie[]requiredShow propertiesHide properties
Cookie host (Chromium host_key), e.g. ".example.com".
Unix seconds; null/absent = session cookie.
Case-insensitive on import.
StrictLaxNoneunspecified200Imported.application/json
Number of cookies written.
401Missing or invalid Bearer token.
409Profile is running; stop it first.application/json
500Cookie DB write failed.application/json
/profiles/123e4567-e89b-12d3-a456-426614174000/cookiesPOST /profiles/123e4567-e89b-12d3-a456-426614174000/cookies HTTP/1.1
Host: 127.0.0.1:40325
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
{
"cookies": [
{
"domain": "text",
"name": "text",
"value": "text",
"path": "/",
"expires": 1,
"secure": false,
"http_only": false,
"same_site": "Strict"
}
]
}curl -X POST 'http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"cookies":[{"domain":"text","name":"text","value":"text","path":"/","expires":1,"secure":false,"http_only":false,"same_site":"Strict"}]}'import requests
# Permanent JWT from Settings → Automation API.
token = "YOUR_SECRET_TOKEN"
url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies"
headers = {
"Authorization": f"Bearer {token}",
}
payload = {
"cookies": [
{
"domain": "text",
"name": "text",
"value": "text",
"path": "/",
"expires": 1,
"secure": False,
"http_only": False,
"same_site": "Strict",
},
],
}
response = requests.post(url, headers=headers, json=payload, timeout=30)
response.raise_for_status()
print(response.status_code)
print(response.text)// Permanent JWT from Settings → Automation API.
const token = "YOUR_SECRET_TOKEN";
const url = "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies";
const payload = {
"cookies": [
{
"domain": "text",
"name": "text",
"value": "text",
"path": "/",
"expires": 1,
"secure": false,
"http_only": false,
"same_site": "Strict"
}
]
};
const response = await fetch(url, {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
console.log(response.status);
console.log(await response.text());package main
import (
"bytes"
"fmt"
"io"
"log"
"net/http"
)
func main() {
// Permanent JWT from Settings → Automation API.
token := "YOUR_SECRET_TOKEN"
url := "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies"
body := bytes.NewBufferString(`{
"cookies": [
{
"domain": "text",
"name": "text",
"value": "text",
"path": "/",
"expires": 1,
"secure": false,
"http_only": false,
"same_site": "Strict"
}
]
}`)
req, err := http.NewRequest("POST", url, body)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, tokio = { version = "1", features = ["full"] }, serde_json = "1"
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Permanent JWT from Settings → Automation API.
let token = "YOUR_SECRET_TOKEN";
let client = reqwest::Client::new();
let response = client
.post("http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies")
.header("Authorization", format!("Bearer {token}"))
.json(&serde_json::json!({
"cookies": [
{
"domain": "text",
"name": "text",
"value": "text",
"path": "/",
"expires": 1,
"secure": false,
"http_only": false,
"same_site": "Strict"
}
]
}))
.send()
.await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// Permanent JWT from Settings → Automation API.
var token = "YOUR_SECRET_TOKEN";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(HttpMethod.Post, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies");
request.Content = new StringContent("""
{
"cookies": [
{
"domain": "text",
"name": "text",
"value": "text",
"path": "/",
"expires": 1,
"secure": false,
"http_only": false,
"same_site": "Strict"
}
]
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}// build: c++ -std=c++17 main.cpp -lcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
// Permanent JWT from Settings → Automation API.
const std::string token = "YOUR_SECRET_TOKEN";
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "curl_easy_init failed\n";
curl_global_cleanup();
return 1;
}
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + token).c_str());
headers = curl_slist_append(headers, "Content-Type: application/json");
const std::string body = R"json({
"cookies": [
{
"domain": "text",
"name": "text",
"value": "text",
"path": "/",
"expires": 1,
"secure": false,
"http_only": false,
"same_site": "Strict"
}
]
})json";
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:40325/profiles/123e4567-e89b-12d3-a456-426614174000/cookies");
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<long>(body.size()));
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
const CURLcode rc = curl_easy_perform(curl);
if (rc != CURLE_OK) {
std::cerr << curl_easy_strerror(rc) << "\n";
} else {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
std::cout << status << "\n" << response << "\n";
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return rc == CURLE_OK ? 0 : 1;
}{
"imported": 1
}{
"error": "text"
}{
"error": "text"
}List running profiles
http://127.0.0.1:40325/runningProfiles with a live browser process, including the CDP endpoint when launched via the API.
Permanent JWT from Settings → Automation API.
200Running profiles.application/json
cdpobject · CdpInfo· nullableoptionalChrome DevTools Protocol endpoint of a running profile.
Show propertiesHide properties
Chrome DevTools Protocol endpoint of a running profile.
Chrome-chosen remote-debugging port.
REST base (/json, /json/version).
Browser-level WS endpoint for Puppeteer/Playwright connect.
401Missing or invalid Bearer token.
/runningGET /running HTTP/1.1
Host: 127.0.0.1:40325
Authorization: Bearer YOUR_SECRET_TOKEN
Accept: */*curl -X GET 'http://127.0.0.1:40325/running' \
-H 'Authorization: Bearer YOUR_SECRET_TOKEN'import requests
# Permanent JWT from Settings → Automation API.
token = "YOUR_SECRET_TOKEN"
url = "http://127.0.0.1:40325/running"
headers = {
"Authorization": f"Bearer {token}",
}
response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
print(response.status_code)
print(response.text)// Permanent JWT from Settings → Automation API.
const token = "YOUR_SECRET_TOKEN";
const url = "http://127.0.0.1:40325/running";
const response = await fetch(url, {
method: "GET",
headers: {
"Authorization": `Bearer ${token}`,
},
});
console.log(response.status);
console.log(await response.text());package main
import (
"fmt"
"io"
"log"
"net/http"
)
func main() {
// Permanent JWT from Settings → Automation API.
token := "YOUR_SECRET_TOKEN"
url := "http://127.0.0.1:40325/running"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}// Cargo.toml: reqwest = { version = "0.12", features = ["json"] }, tokio = { version = "1", features = ["full"] }
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Permanent JWT from Settings → Automation API.
let token = "YOUR_SECRET_TOKEN";
let client = reqwest::Client::new();
let response = client
.get("http://127.0.0.1:40325/running")
.header("Authorization", format!("Bearer {token}"))
.send()
.await?;
println!("{}", response.status());
println!("{}", response.text().await?);
Ok(())
}using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// Permanent JWT from Settings → Automation API.
var token = "YOUR_SECRET_TOKEN";
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var request = new HttpRequestMessage(HttpMethod.Get, "http://127.0.0.1:40325/running");
var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
}// build: c++ -std=c++17 main.cpp -lcurl
#include <curl/curl.h>
#include <iostream>
#include <string>
static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append(ptr, size * nmemb);
return size * nmemb;
}
int main() {
// Permanent JWT from Settings → Automation API.
const std::string token = "YOUR_SECRET_TOKEN";
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = curl_easy_init();
if (!curl) {
std::cerr << "curl_easy_init failed\n";
curl_global_cleanup();
return 1;
}
struct curl_slist *headers = nullptr;
headers = curl_slist_append(headers, ("Authorization: Bearer " + token).c_str());
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1:40325/running");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
const CURLcode rc = curl_easy_perform(curl);
if (rc != CURLE_OK) {
std::cerr << curl_easy_strerror(rc) << "\n";
} else {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
std::cout << status << "\n" << response << "\n";
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
return rc == CURLE_OK ? 0 : 1;
}[
{
"profile_id": "text",
"pid": 1,
"cdp": {
"port": 1,
"http_url": "http://127.0.0.1:53217",
"web_socket_debugger_url": "ws://127.0.0.1:53217/devtools/browser/ab12-..."
}
}
]Last updated on