HTTP API reference
Camoufy 1.1.1
Everything the interface does goes through this API, so a script can do the same. For a short introduction see HTTP API in the docs.
Basics
On Windows the address is http://127.0.0.1:18800. In Docker it is the address of the interface, for example https://camoufy.example.com. Every path below starts with /api/v1.
Send the key from Settings in one of three ways: the X-Api-Key header, Authorization: Bearer KEY, or ?api_key=KEY in the address. Bodies and answers are JSON unless a row says otherwise.
curl -H "X-Api-Key: $KEY" http://127.0.0.1:18800/api/v1/profiles
An error comes back with an HTTP status and this body:
{"error": {"code": "not_found", "message": "profile not found"}}
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_request | The request is wrong. The message says what |
| 401 | unauthorized | The key is missing or wrong |
| 403 | wrong_password | Wrong profile password |
| 404 | not_found | No such profile, proxy or file |
| 409 | running | The profile has to be stopped first |
| 423 | locked | The profile has a password and the request gave none |
| 424 | no_engine | No engine is installed |
Profiles
| Request | What it does |
|---|---|
| GET /profiles | List profiles. Filters: q (name, notes, id, tag, proxy, country, IP), tag, status (running, stopped or an exact status). Answer: {profiles, running, total} |
| POST /profiles | Create a profile from the fields below. Answer 201: {profile, fingerprint} |
| GET /profiles/{id} | One profile with its fingerprint and the geo data of its last start |
| PATCH /profiles/{id} | Change name, tags, notes, proxy, addons, launch or geo. Only the keys you send are applied. The proxy of a running profile cannot be changed, and os never can |
| DELETE /profiles/{id} | Delete a stopped profile with its cookies and data |
| POST /profiles/{id}/clone | Copy a profile. Body: {name, with_cookies, keep_fingerprint}. Answer 201: {profile} |
| POST /profiles/bulk | One action over many profiles. Body: {action, ids} with action start, stop, delete, add_tag, remove_tag or set_proxy, plus tag, proxy_id or headless where the action needs it. Answer: {results}, "ok" or an error text for each id |
Fields of a profile:
| Field | Value |
|---|---|
| name, notes, tags | Text, text and a list of strings |
| os | windows, macos or linux. The fingerprint is generated for it. Default windows |
| proxy | {"mode": "none"}, {"mode": "list", "proxy_id": "..."} or {"mode": "tor", "tor_exit": "de"}. The exit country is optional |
| addons | List of add-on ids from the library |
| launch | start_urls, restore_session, headless_default, free_window (the window may grow beyond the screen of the fingerprint), theme (system, dark or light. The browser theme that sites see as prefers-color-scheme. Default system follows the computer the browser runs on), extra_prefs (Firefox preferences) |
| geo | {"mode": "auto"} follows the exit IP of the proxy. "manual" takes override: {timezone, locale, lat, lon}. "off" leaves geo alone |
| password, unlock_to | Only when creating. A password protects the profile at once. unlock_to is disk or memory |
curl -H "X-Api-Key: $KEY" -X POST http://127.0.0.1:18800/api/v1/profiles -d '{"name": "Shop DE", "os": "windows", "tags": ["shop"], "proxy": {"mode": "list", "proxy_id": "px_41c0aa"}}'
In answers a profile also carries id, created_at, updated_at, last_started_at, encrypted, status (the run state below), fingerprint (a summary) and proxy_info.
Start and stop
| Request | What it does |
|---|---|
| POST /profiles/{id}/start | Start the browser. Body, all optional: headless, urls, automation ("bidi" opens a WebDriver BiDi endpoint), password for a protected profile. Answer: the run state |
| POST /profiles/{id}/stop | Close the browser and wait until its data is saved. {"force": true} ends the process at once. Answer: the run state |
| POST /profiles/{id}/open-url | Open {"url": "..."} in a new tab of a running profile |
| GET /profiles/{id}/tabs | Open tabs as the browser last saved them: {tabs: [{window, index, url, title, active}]}. The browser saves its tabs every 15 seconds, so the list lags behind and is empty right after a start |
| POST /profiles/{id}/proxy/rotate | New sticky session on a proxy with {session}, or a new Tor circuit. Works on a running profile |
| POST /profiles/{id}/new-identity | Make a profile a new person. wipe erases the whole browser folder, bookmarks, saved logins and add-on data and settings included. It is the default when the body names no data part below. Body, each part true unless set to false. Browser data, cleared selectively when wipe is false: cookies, history (visits, forms, downloads, back and forward of tabs), site_data (localStorage, IndexedDB, service workers), tabs (open and recently closed) and cache. data sets all five at once. Firefox clears them itself during a few seconds of a start without a window and without network, so bookmarks, saved logins and add-on data stay. fingerprint draws a new one. proxy changes the IP. A proxy with {session} gets a new session, Tor builds new circuits, a plain proxy is swapped for a free working one from the list. Browser data and fingerprint need a stopped profile. A running profile can still get a new IP from a {session} proxy or Tor. A protected profile needs password to clear data selectively, a wipe needs none. Answer: profile, wiped, cleared, plus fingerprint and proxy: {changed, mode, proxy_id, session_id, note} for the parts done |
| GET /profiles/{id}/log | The end of the profile log as plain text, up to 256 KB |
The run state:
| Field | Value |
|---|---|
| status | stopped, starting, running, running_external (started from a launch recipe), proxy_error or crashed |
| pid, started_at, stopped_at | Process id and times |
| headless, screen | Whether it runs headless, and whether it has a virtual screen (Docker) |
| ws_endpoint | Local BiDi address, with automation "bidi" |
| remote_ws | Path of the same endpoint through the server, see below |
| bytes_in, bytes_out | Traffic through the proxy of the profile |
| error, exit_code | Why it stopped, if it did not stop cleanly |
| engine, proxy_id, dropped_keys | Engine version in use, proxy in use, fingerprint keys this engine does not know |
Automation
| Request | What it does |
|---|---|
| GET /profiles/{id}/bidi | WebSocket to the BiDi endpoint of a profile started with automation "bidi". Use the remote_ws path from the start answer. For a profile with a password it carries a token of that run |
| GET /profiles/{id}/launch-recipe | What your own Playwright needs to launch the profile: executable_path, user_data_dir, args, env, firefox_user_prefs, proxy, lease_id. Optional ?headless=1. The password of a protected profile goes in the X-Profile-Password header |
| DELETE /leases/{lease_id} | Tell Camoufy the browser from a recipe has closed. Without it the lease ends by itself soon after the browser exits |
| GET /profiles/{id}/screen | WebSocket with the VNC stream of the virtual screen of a profile (Docker). The interface uses it on its Screen page |
Three things to know when you write your own BiDi client:
- Create tabs in the background: browsingContext.create with {"type": "tab", "background": true}. Without background the engine never answers the command.
- For the tabs open right now ask the browser: browsingContext.getTree. GET /profiles/{id}/tabs reads the saved session and can be 15 seconds behind.
- The browser allows one BiDi session at a time and keeps it after its client disconnects. The remote_ws connection ends the session for you when you close it or it drops. On the local ws_endpoint send session.end before you close, or the next session.new fails until the profile restarts.
The recipe holds local paths, so it is for scripts on the same machine as Camoufy. From another machine use remote_ws or MCP.
Fingerprint
| Request | What it does |
|---|---|
| GET /profiles/{id}/fingerprint | {fingerprint, effective, dropped}: the stored fingerprint, the settings the engine receives, and the keys it does not know |
| PATCH /profiles/{id}/fingerprint | Replace your own overrides: {"overrides": {"navigator.hardwareConcurrency": 8}}. An empty object removes them all |
| POST /profiles/{id}/fingerprint/regenerate | New fingerprint for the same OS. The profile has to be stopped |
Cookies, export, password
| Request | What it does |
|---|---|
| POST /profiles/{id}/cookies/import | Put cookies in Netscape format (cookies.txt) into a stopped profile. Body: {text, password}, or a multipart form with file. ?domain=example.com keeps that domain and its subdomains. Up to 2000 cookies. Answer: {imported, parsed, failed, parse_errors, domains} |
| POST /profiles/{id}/cookies/export | Read the cookies of a stopped profile. The browser starts without a window for a few seconds. Body, all optional: format ("txt" for Netscape cookies.txt, the default, or "json" in the Cookie-Editor layout), domain to keep one domain and its subdomains, password for a protected profile. Answer: the file, with the count in the X-Cookie-Count header |
| GET /profiles/{id}/export | Download a stopped profile as a .cbprofile file. ?proxy=1 adds its proxy with the password, ?addons=1 adds its add-on files |
| POST /profiles/import | Multipart form with one or more file fields. Answer: {results} with a profile or an error for each file |
| POST /profiles/{id}/password | On a stopped profile. Set: {"new": "..."}. Change: {"current": "...", "new": "..."}. Remove: {"current": "...", "new": ""}. unlock_to (disk or memory) says where the data is decrypted at start |
Proxies
| Request | What it does |
|---|---|
| GET /proxies | {proxies}, each with its last check and used_by, the ids of the profiles on it |
| POST /proxies | Add one proxy: {type, host, port, username, password, label, tags}. Type is http, https or socks5. Or add a list: {text, tags}, one proxy per line. Answer: {added, total_parsed, proxies, errors}. POST /proxies/import is the same request |
| POST /proxies/quick | Check one line {text, tags} and add it only if it works. Answer: {ok, proxy, check} or {ok: false, error} |
| PATCH /proxies/{id} | Change label, tags, type, host, port, username or password |
| DELETE /proxies/{id} | Delete a proxy. If a profile uses it, add ?force=1 and that profile is left without a proxy |
| POST /proxies/delete | Delete many: {ids, force}. Without force, proxies in use answer 409 with used_by |
| POST /proxies/{id}/check | Check one proxy now, up to 25 seconds. Answer: {proxy} with last_check: {ok, ip, country, region, city, timezone, latency_ms, error} |
| POST /proxies/check | Check many in the background: {ids}, or all with an empty body. Answer 202. Results arrive as proxy.check events |
A line of a proxy list can look like any of these. Without a scheme the type is http. Put {session} in the login for sticky sessions.
host:port host:port:user:pass host:port:user:pass:socks5 user:pass@host:port socks5://user:pass@host:port
Add-ons
| Request | What it does |
|---|---|
| GET /addons | {addons}: id, name, version, description, source, used_by |
| POST /addons/from-url | Add from a direct link to an .xpi file: {"url": "..."}. Answer 201: {addon} |
| POST /addons | Upload .xpi files, a multipart form with one or more file fields |
| POST /addons/{id}/update | Fetch the newest version from addons.mozilla.org or the original link. Answer: {addon, updated, previous, restart}, where restart names the running profiles that still use the old files |
| DELETE /addons/{id} | Remove from the library. If a profile uses it, add ?force=1 |
An add-on works in a profile once its id is in the addons list of that profile. A link to an add-on from addons.mozilla.org looks like this:
https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi
Engine and Tor
| Request | What it does |
|---|---|
| GET /engine | {versions, current, dir}: installed Camoufox versions and the one in use |
| POST /engine/check-updates | {releases} available on GitHub, each with name, version, asset_url, asset_size, installed |
| POST /engine/install | Install a release. The body is one object from check-updates. Answer 202. Progress arrives as engine.progress events, then engine.installed or engine.error |
| POST /engine/use | Switch to an installed version: {"name": "..."} |
| POST /engine/import | Copy an engine from {"path": "..."} on the machine Camoufy runs on. Answer 202, same events |
| DELETE /engine/{name} | Remove a version. Every profile has to be stopped |
| GET /tor | {tor: {installed, version, tor_version, size_mb, transports}} |
| POST /tor/install | Download Tor. Optional {"version": "..."}. Answer 202, then tor.progress and tor.installed or tor.error events |
| DELETE /tor | Remove Tor. Profiles running through it have to be stopped |
Settings and system
| Request | What it does |
|---|---|
| GET /settings | All settings, the API key among them |
| PATCH /settings | Change any of port, theme (system, light, dark), lang (en, ru), ip_services, check_updates, tor_bridges, show_cursor, browser_ui (firefox, camoufox), and on Windows start_minimized, exit_on_close, minimize_to_tray, autostart, ui_mode |
| POST /settings/rotate-key | Issue a new API key. The old one stops working at once. The answer holds the new key |
| GET /system | Version, OS, folder sizes, number of profiles, running profiles, and whether this copy runs in a container with virtual screens |
| GET /update | Result of the last update check: {current, result, checking, error} |
| POST /update/check | Check camoufy.com for a new version now |
| POST /system/show | Bring the program window to the front (Windows) |
| POST /system/quit | Stop every profile and close Camoufy |
Events
GET /events is a stream of server-sent events. Each one has a name and a JSON body.
curl -N -H "X-Api-Key: $KEY" http://127.0.0.1:18800/api/v1/events
| Event | When |
|---|---|
| profile.status | The run state of a profile changed. The body is the new run state |
| profile.changed | A profile was created, updated, deleted or imported |
| proxy.check, proxy.check.done | One proxy was checked, and a background check of many has finished |
| proxy.rotated | A profile got a new sticky session or Tor circuit |
| proxy.changed, addon.changed, settings.changed | The list or the settings changed |
| engine.progress, engine.installed, engine.error, engine.changed | Engine download, install and switch |
| tor.progress, tor.installed, tor.error | Tor download and install |
| update | An update check has finished |