Browser
Section titled “Browser”Hoody Browser gives you HTTP control over Chromium instances: start browsers, navigate pages, evaluate JavaScript, manage tabs, and capture DevTools URLs. Typical uses are web scraping, automated testing, screenshot services, and AI-driven web interaction.
Capabilities
Section titled “Capabilities”- Instance management - Start, stop, and restart Chromium processes, each with its own tabs, cookies, and state
- Page navigation - Browse a URL and read back its navigation metadata, HTML, or text
- JavaScript execution - Evaluate a script in the page context over GET or POST
- Tab management - List the open tabs and close them individually
- DevTools access - Get the WebSocket URL for the Chrome DevTools Protocol
- Fingerprinting - Set user agent, viewport, geolocation, locale, and Chromium version
- Health monitoring - Track server metrics and instance health
- Multiple instances - Run concurrent browsers on different ports
API Endpoints Summary
Section titled “API Endpoints Summary”All endpoints are relative to your Browser service URL:
https://PROJECT_ID-CONTAINER_ID-browser-1.SERVER.containers.hoody.comInstance management:
GET /start- Create or retrieve browser instanceGET /stop- Stop browser instanceGET /restart- Restart browser instance
Browser interaction:
GET /browse?url=...- Navigate to URL (returns navigation metadata)POST /browse- Navigate with POST body optionsGET /eval?script=...- Evaluate JavaScript scriptPOST /eval- Evaluate JavaScript with POST body
Page content and export:
GET /api/v1/browser/html- Get page HTML contentGET /api/v1/browser/text- Get page text contentGET /api/v1/browser/screenshot- Take a screenshot of the pageGET /api/v1/browser/pdf- Export page as PDF
Cookies:
GET /cookies- Get browser cookiesPOST /cookies- Set browser cookiesDELETE /cookies- Clear browser cookies
Introspection and control:
GET /metadata- Get instance metadata and DevTools URLGET /tabs- List browser tabsPOST /tab/close- Close a browser tabGET /api/v1/browser/devtools-url- Get DevTools WebSocket URLGET /api/v1/browser/shutdown- Shutdown browser instance
Logs and history:
GET /api/v1/browser/console- Get browser console logsGET /network- Get network request/response logsGET /history- Query browsing historyDELETE /history- Delete browsing history
Health:
GET /api/v1/browser/health- Service health check
Quick start
Section titled “Quick start”# Start a browser instancehoody browser start -c <container-id> --browser-id "0"
# Navigate to a URLhoody browser navigate -c <container-id> --browser-id "0" --url "https://example.com"
# Execute JavaScripthoody browser eval -c <container-id> --browser-id "0" --script "document.title"
# Take a screenshothoody browser screenshot -c <container-id> --browser-id "0"
# List open tabshoody browser tabs list -c <container-id> --browser-id "0"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });const containerClient = await client.withContainer({ id: CONTAINER_ID, project_id: PROJECT_ID, server: SERVER });
const BROWSER_ID = '0';
// Start browser instanceconst instance = await containerClient.browser.instances.start({ browser_id: BROWSER_ID });
// Navigate to URLconst page = await containerClient.browser.interaction.browse({ browser_id: BROWSER_ID, url: 'https://example.com',});
// Execute JavaScriptconst result = await containerClient.browser.interaction.evalPost({ script: 'document.title' }, { browser_id: BROWSER_ID });
// Take screenshotconst screenshot = await containerClient.browser.interaction.takeScreenshot({ browser_id: BROWSER_ID });
// List tabsconst tabs = await containerClient.browser.introspection.listTabs({ browser_id: BROWSER_ID });# Start browser instancecurl "https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/start?browser_id=0"
# Navigate to URLcurl "https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/browse?browser_id=0&url=https://example.com"
# Execute JavaScriptcurl "https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/eval?browser_id=0&script=document.title"
# List tabscurl "https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/tabs?browser_id=0"One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Runs the same four calls as the HTTP tab — start, navigate, evaluate a script, and list tabs — all against browser instance 0.
# Start a browser instance
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/start?browser_id=0&method=GET&response=transparent
# Navigate to a URL
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/browse?browser_id=0%26url=https://example.com&method=GET&response=transparent
# Execute JavaScript
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/eval?browser_id=0%26script=document.title&method=GET&response=transparent
# List open tabs
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/tabs?browser_id=0&method=GET&response=transparent Starting an instance returns its metadata, including the webSocketDebuggerUrl for Chrome DevTools Protocol access.
Browser configuration
Section titled “Browser configuration”Tuning the engine
Section titled “Tuning the engine”Everything about the instance is set at /start, before Chromium launches. A fingerprint profile supplies the baseline and any parameter you pass on top of it wins, so you can start from a known identity and change one thing:
# Start from the "default" fingerprint, then override identity and networkhoody browser start -c <container-id> --browser-id "0" \ --fingerprint-id default \ --chromium-version 136 \ --locale en-GB --timezone-id Europe/London \ --viewport 1920x1080 \ --proxy-server socks5://127.0.0.1:9050 \ --use-remote-debugging-portimport { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });const containerClient = await client.withContainer({ id: CONTAINER_ID, project_id: PROJECT_ID, server: SERVER });
// Start from the "default" fingerprint, then override identity and networkconst instance = await containerClient.browser.instances.start({ browser_id: '0', fingerprintId: 'default', chromiumVersion: '136', locale: 'en-GB', timezoneId: 'Europe/London', viewport: '1920x1080', proxyServer: 'socks5://127.0.0.1:9050', useRemoteDebuggingPort: true,});# Start from the "default" fingerprint, then override identity and networkcurl "https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/start?browser_id=0&fingerprintId=default&chromiumVersion=136&locale=en-GB&timezoneId=Europe/London&viewport=1920x1080&proxyServer=socks5://127.0.0.1:9050&useRemoteDebuggingPort=true"One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Starts browser instance 0 from the default fingerprint with the locale, timezone, viewport, and proxy overrides shown above.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/start?browser_id=0%26fingerprintId=default%26chromiumVersion=136%26locale=en-GB%26timezoneId=Europe/London%26viewport=1920x1080%26proxyServer=socks5://127.0.0.1:9050%26useRemoteDebuggingPort=true&method=GET&response=transparent Engine and profile
| Parameter | What it does |
|---|---|
chromiumVersion | Full version (136.0.7103.113), major version (136), or channel (stable, beta, dev, canary). The call blocks while the build downloads. |
fingerprintId | Loads storage/config/fingerprints/<id>.json for its context and launch defaults. Request parameters override it. |
stealth | Anti-detection patches. On by default. |
Identity presented to the page
| Parameter | What it does |
|---|---|
userAgent | Replaces the user-agent string. |
locale | BCP 47 language tag, for example en-GB. |
timezoneId | IANA timezone, for example Europe/London. |
geolocation | Coordinates reported to the geolocation API. |
viewport / noViewport | Window size, or let the window size itself. |
Network
| Parameter | Default | What it does |
|---|---|---|
proxyServer | none | http://, https://, socks5:// or socks5h://. Paired with proxyUsername, proxyPassword, proxyBypass. |
enableQuic | false | QUIC and HTTP/3 are blocked unless you turn them on. |
enableDnsOverHttps | true | DNS-over-HTTPS, resolver set by dnsOverHttpsUrl. |
dnsOverHttpsUrl | Cloudflare | Any HTTPS resolver. |
Debugging and display
| Parameter | Default | What it does |
|---|---|---|
useRemoteDebuggingPort | true | Launches with --remote-debugging-port and fills in webSocketDebuggerUrl. |
remoteDebuggingPort | free port | Pin the DevTools port. |
remoteDebuggingAddress | 127.0.0.1 | Use 0.0.0.0 only in trusted environments. |
showBrowser | true | Headful. Required for extensions. |
display | none | X display number for headful mode. |
extensions, extensionsDir, extensionsStoreIds | none | Load unpacked extensions, a directory of them, or Chrome Web Store IDs. All need showBrowser=true. |
Multiple instances
Section titled “Multiple instances”Run concurrent browser instances using different browser_id values:
# Start first instancecurl "https://PROJECT_ID-CONTAINER_ID-browser-1.SERVER.containers.hoody.com/api/v1/browser/start?browser_id=0"
# Start second instancecurl "https://PROJECT_ID-CONTAINER_ID-browser-1.SERVER.containers.hoody.com/api/v1/browser/start?browser_id=1"
# Each instance is addressed by its browser_idcurl "https://PROJECT_ID-CONTAINER_ID-browser-1.SERVER.containers.hoody.com/api/v1/browser/browse?browser_id=0&url=https://example.com"curl "https://PROJECT_ID-CONTAINER_ID-browser-1.SERVER.containers.hoody.com/api/v1/browser/browse?browser_id=1&url=https://example.org"Each instance is isolated with its own tabs, cookies, and state.
Chrome DevTools Protocol
Section titled “Chrome DevTools Protocol”Launch a Chromium instance with useRemoteDebuggingPort=true and it gets a paired cdp-{n} DevTools Protocol URL, where cdp-1 is the same browser as browser-1. Point Playwright, Puppeteer, or any CDP client at the HTTPS base URL and it discovers the live WebSocket for you:
const { chromium } = require('playwright');
// Connect to a Hoody Browser instance over CDPconst browser = await chromium.connectOverCDP( 'https://PROJECT_ID-CONTAINER_ID-cdp-1.SERVER.containers.hoody.com/');
const page = await browser.newPage();await page.goto('https://example.com');await page.screenshot({ path: 'screenshot.png' });- On demand - Connecting to a cold
cdp-{n}URL auto-starts that instance, so you do not have to start it first. - Restart-stable - The URL names the instance rather than a port, so it keeps working across browser restarts. Always pass the
https://…-cdp-{n}/base URL rather than a hard-codedwss://link, because debugger GUIDs change on every launch. - Chromium only - Connecting CDP to a Firefox instance returns
501.
The DevTools endpoint returns the same paired URL. Open it in your browser to load Chrome DevTools against the remote instance:
# Get the DevTools Protocol URLs for an instancehoody browser devtools -c <container-id> --browser-id "0"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://api.hoody.com', token: process.env.HOODY_TOKEN });const containerClient = await client.withContainer({ id: CONTAINER_ID, project_id: PROJECT_ID, server: SERVER });
// Get the DevTools Protocol URLs for an instanceconst devtools = await containerClient.browser.introspection.getDevtoolsUrl({ browser_id: '0' });// { webSocketDebuggerUrl, devtoolsHttpUrl, devtoolsFrontendUrl }# Get the DevTools Protocol URLs for an instancecurl "https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/devtools-url?browser_id=0"One request, one link
cURL runs inside your container and can wrap any HTTP request into a single GET URL. The call stops being something you need a client for and becomes something you can paste into a browser, send in a chat, bookmark, schedule with cron, or drop into a no-code tool.
Nothing is installed on the machine that opens it. The link does carry whatever credentials the call needs, so treat it as you would treat those credentials.
Slashes, colons and braces pass through as they are. The one character you must
encode is an & inside a value, which happens when the wrapped URL
carries its own query string. Left raw it ends the value early, and the rest is
read as cURL's own parameters, so you get a 200 on a request you did
not make.
How the wrapping works Chaining calls into one link Turning a link into a shortcut
Returns the paired DevTools Protocol URLs for browser instance 0, including the webSocketDebuggerUrl.
https://PROJECT_ID-CONTAINER_ID-curl-1.SERVER.containers.hoody.com/api/v1/curl/request?url=https://PROJECT-CONTAINER-browser-1.SERVER.containers.hoody.com/devtools-url?browser_id=0&method=GET&response=transparent Use Cases
Section titled “Use Cases”- Web scraping - Fetch a page’s rendered HTML or text over HTTP
- Automated testing - Run end-to-end tests against web applications, including CDP-driven Playwright and Puppeteer suites
- Screenshot services - Capture page images on demand without running Chrome locally
- AI web interaction - Let AI agents browse pages and evaluate scripts against them
- PDF generation - Render HTML to PDF via Chrome’s print functionality
- Performance monitoring - Audit web performance metrics
What’s Next
Section titled “What’s Next”- Browser Instance Management API - Start, stop, restart instances
- Browser Interaction API - Navigate and evaluate JavaScript
- Browser Control API - Metadata, tabs, and DevTools
- Browser Health API - Metrics and monitoring
- cURL Service - For simpler HTTP requests without a browser
- Exec Service - Execute scripts that orchestrate browser automation