Instance Control
Section titled “Instance Control”The Instance Control API provides endpoints for inspecting metadata, managing tabs, controlling browser lifecycle, and manipulating cookies within a Hoody browser container. Use these endpoints to query session information, list open tabs, retrieve Chrome DevTools connection details, modify the runtime viewport, and manage the cookie store of a running browser instance. All endpoints target the browser-1 service on the container’s subdomain.
Introspection
Section titled “Introspection”Get instance metadata
Section titled “Get instance metadata”GET /metadata
Retrieves detailed metadata for an existing browser instance, including session information, browser details, operating system, viewport, geolocation, open tabs, and the Chrome DevTools WebSocket URL (when remote debugging is enabled).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
browser_id | query | string | Yes | Unique identifier for the browser instance (0-based index) |
start | query | boolean | No | Controls instance creation behavior. Default mode: instances are created automatically. Set to false to prevent creation. When auto-start is disabled globally, set to true to create an instance. Omitting this parameter is not equivalent to sending true — the server branches on HOODY_DISABLE_AUTO_START (DISABLE ? start === 'true' : start !== 'false'), so an ABSENT value means “auto-start unless the operator disabled it” while an explicit true means “start even though the operator disabled it”. |
Response
Section titled “Response”{ "engine": "playwright", "stealth": false, "headless": true, "chromiumBuildId": "136.0.7103.113", "chromiumExecutablePath": "/hoody/storage/hoody-browser/chrome/chrome/linux-136.0.7103.113/chrome-linux64/chrome", "browserExecutablePath": "/hoody/storage/hoody-browser/chrome/chrome/linux-136.0.7103.113/chrome-linux64/chrome", "fingerprintId": "default", "display": ":99", "iframe_url": null, "browser_id": "0", "browser_host": "browser-1", "browser_port": 9222, "sessionId": "sess_a1b2c3d4e5f6", "sessionName": "default", "timezoneId": "America/New_York", "locale": "en-US", "geolocation": { "latitude": 40.7128, "longitude": -74.006, "accuracy": 50 }, "viewport": { "width": 1280, "height": 720 }, "viewportSource": "creation", "userAgentString": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36", "browserName": "chromium", "browserFullVersion": "136.0.7103.113", "operatingSystemName": "Linux", "operatingSystemPlatform": "linux", "operatingSystemVersion": "5.15.0", "renderingEngine": "Blink", "renderingEngineVersion": "136.0.7103.113", "webSocketDebuggerUrl": "wss://{projectId}-{containerId}-cdp-1.{server}.containers.hoody.com/devtools/browser/b6e7d6f4-8d1e-4f3a-9b2c-1d4e5f6g7h8i", "devtoolsHttpUrl": "https://{projectId}-{containerId}-cdp-1.{server}.containers.hoody.com/json/version", "devtoolsFrontendUrl": "https://{projectId}-{containerId}-cdp-1.{server}.containers.hoody.com", "extensions": [], "useRemoteDebuggingPort": true, "remoteDebuggingPort": 9222, "remoteDebuggingAddress": "0.0.0.0", "quicDisabled": true, "http3Disabled": true, "dnsOverHttpsEnabled": true, "dnsOverHttpsUrl": "https://cloudflare-dns.com/dns-query", "tabs": [ { "id": 1, "url": "https://example.com" } ]}When the browser is launched with remote debugging enabled (via useRemoteDebuggingPort=true and browser=chromium), webSocketDebuggerUrl, devtoolsHttpUrl, and devtoolsFrontendUrl are populated. In Hoody container deployments these URLs are rewritten onto the cdp-{N} proxy hostname pattern (paired 1:1 with browser-{N}). The WebSocket URL is not promised stable across browser restarts; prefer chromium.connectOverCDP("https://...-cdp-{N}/"), which resolves the live URL via /json/version and cold-starts instance N on demand.
When the browser uses pipe transport (default behavior), the three DevTools URL fields are null:
{ "engine": "playwright", "browser_id": "0", "browser_host": "browser-1", "browser_port": 9222, "sessionId": "sess_a1b2c3d4e5f6", "sessionName": "default", "webSocketDebuggerUrl": null, "devtoolsHttpUrl": null, "devtoolsFrontendUrl": null, "useRemoteDebuggingPort": false, "remoteDebuggingPort": null, "tabs": [ { "id": 1, "url": "https://example.com" } ]}{ "error": "Instance not found", "code": "INSTANCE_NOT_FOUND", "details": {}}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSTANCE_NOT_FOUND | Instance Not Found | No browser instance exists for the specified browser_id | Verify the browser_id value, or create a new instance using /start |
SDK usage
Section titled “SDK usage”curl -X GET "https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com/metadata?browser_id=0" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.browser.introspection.getMetadata({ browser_id: '0' });Get DevTools URLs
Section titled “Get DevTools URLs”GET /devtools-url
Returns the Chrome DevTools WebSocket URL and HTTP discovery URL for the specified browser instance. The HTTP URL (/json/version) can be used to resolve the WebSocket endpoint automatically.
In container deployments these URLs are minted on the cdp-{N} hostname (paired 1:1 with browser-{N}). The relay is reached HTTP-first: connect with chromium.connectOverCDP("https://...-cdp-{N}/"), which fetches /json/version to resolve the live WebSocket endpoint before upgrading, and cold-starts instance N on demand if it isn’t already running. Only the read-only discovery endpoints (/json/version, /json/list, /json) and DevTools WebSocket sessions (/devtools/browser/<id>, /devtools/page/<id>) are relayed — mutation endpoints (/json/new, /json/close, /json/activate) are not exposed.
These URLs are populated when the instance is launched with useRemoteDebuggingPort=true and browser=chromium. Otherwise they will be null.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
browser_id | query | string | Yes | Unique identifier for the browser instance (0-based index) |
start | query | boolean | No | Controls instance creation behavior. Default mode: instances are created automatically. Set to false to prevent creation. When auto-start is disabled globally, set to true to create an instance. Omitting this parameter is not equivalent to sending true — the server branches on HOODY_DISABLE_AUTO_START (DISABLE ? start === 'true' : start !== 'false'), so an ABSENT value means “auto-start unless the operator disabled it” while an explicit true means “start even though the operator disabled it”. |
Response
Section titled “Response”{ "webSocketDebuggerUrl": "wss://{projectId}-{containerId}-cdp-1.{server}.containers.hoody.com/devtools/browser/b6e7d6f4-8d1e-4f3a-9b2c-1d4e5f6g7h8i", "devtoolsHttpUrl": "https://{projectId}-{containerId}-cdp-1.{server}.containers.hoody.com/json/version", "devtoolsFrontendUrl": "https://{projectId}-{containerId}-cdp-1.{server}.containers.hoody.com"}{ "error": "Instance not found", "code": "INSTANCE_NOT_FOUND", "details": {}}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSTANCE_NOT_FOUND | Instance Not Found | No browser instance exists for the specified browser_id | Verify the browser_id value, or create a new instance using /start |
SDK usage
Section titled “SDK usage”curl -X GET "https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com/devtools-url?browser_id=0" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.browser.introspection.getDevtoolsUrl({ browser_id: '0' });List browser tabs
Section titled “List browser tabs”GET /tabs
Lists all open tabs in a browser instance. Each tab includes its identifier, current URL, and whether it is the active tab.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
browser_id | query | string | Yes | Unique identifier for the browser instance (0-based index) |
start | query | boolean | No | Controls instance creation behavior. Default mode: instances are created automatically. Set to false to prevent creation. When auto-start is disabled globally, set to true to create an instance. Omitting this parameter is not equivalent to sending true — the server branches on HOODY_DISABLE_AUTO_START (DISABLE ? start === 'true' : start !== 'false'), so an ABSENT value means “auto-start unless the operator disabled it” while an explicit true means “start even though the operator disabled it”. |
Response
Section titled “Response”[ { "id": 1, "url": "https://example.com", "isActive": true }, { "id": 2, "url": "https://docs.example.com/getting-started", "isActive": false }]{ "error": "Instance not found", "code": "INSTANCE_NOT_FOUND", "details": {}}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSTANCE_NOT_FOUND | Instance Not Found | No browser instance exists for the specified browser_id | Verify the browser_id value, or create a new instance using /start |
SDK usage
Section titled “SDK usage”curl -X GET "https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com/tabs?browser_id=0" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.browser.introspection.listTabs({ browser_id: '0' });Tab & Lifecycle Management
Section titled “Tab & Lifecycle Management”Close a browser tab
Section titled “Close a browser tab”POST /tab/close
Closes a specific browser tab by its tab ID. If no tabId is provided, closes the active tab (unless it is the last remaining tab).
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
browser_id | query | string | Yes | Unique identifier for the browser instance (0-based index) |
start | query | boolean | No | Controls instance creation behavior. Default mode: instances are created automatically. Set to false to prevent creation. When auto-start is disabled globally, set to true to create an instance. Omitting this parameter is not equivalent to sending true — the server branches on HOODY_DISABLE_AUTO_START (DISABLE ? start === 'true' : start !== 'false'), so an ABSENT value means “auto-start unless the operator disabled it” while an explicit true means “start even though the operator disabled it”. |
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
tabId | integer | No | The ID of the tab to close |
Response
Section titled “Response”{ "closed": 1, "remaining": 1}{ "error": "Cannot close the last remaining tab", "code": "LAST_TAB", "details": {}}{ "error": "Tab not found", "code": "TAB_NOT_FOUND", "details": { "tabId": 99 }}SDK usage
Section titled “SDK usage”curl -X POST "https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com/tab/close?browser_id=0" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{"tabId": 2}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.browser.introspection.closeTab({ tabId: 2 }, { browser_id: '0' });Shutdown browser instance
Section titled “Shutdown browser instance”GET /shutdown
Shuts down a specific browser instance. The instance can be recreated later via /start.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
browser_id | query | string | Yes | Unique identifier for the browser instance (0-based index) |
Response
Section titled “Response”{ "message": "Instance shutdown successfully"}{ "error": "Instance not found", "code": "INSTANCE_NOT_FOUND", "details": {}}| Error Code | Title | Description | Resolution |
|---|---|---|---|
INSTANCE_NOT_FOUND | Instance Not Found | No browser instance exists for the specified browser_id | Verify the browser_id value, or create a new instance using /start |
SDK usage
Section titled “SDK usage”curl -X GET "https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com/shutdown?browser_id=0" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.browser.introspection.shutdown({ browser_id: '0' });Viewport
Section titled “Viewport”Get the current viewport policy
Section titled “Get the current viewport policy”GET /viewport
Returns the instance’s current viewport policy without mutating anything. viewport: null means fixed-viewport emulation is disabled (responsive — the page follows the real window size). source is creation until the first successful POST /viewport, then runtime. converged reports whether every live page currently reflects the policy.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
browser_host | query | string | No | Instance host. Must be paired with browser_port; when both are omitted the single running instance is selected (400 AMBIGUOUS_INSTANCE with more than one). |
browser_port | query | integer | No | Instance port. Must be paired with browser_host. |
Response
Section titled “Response”{ "viewport": { "width": 1280, "height": 720 }, "source": "creation", "tabs": 2, "converged": true}{ "error": "Multiple browser instances running; specify browser_host and browser_port", "code": "AMBIGUOUS_INSTANCE", "details": {}}{ "error": "No browser instance is running", "code": "NO_INSTANCE", "details": { "reason": "no_instance" }}{ "error": "The instance's control process did not answer", "code": "PARENT_PROXY_FAILURE", "details": {}}SDK usage
Section titled “SDK usage”curl -X GET "https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com/viewport" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.browser.introspection.getViewport();Change the viewport at runtime
Section titled “Change the viewport at runtime”POST /viewport
Mutates the running instance’s viewport policy. JSON body only:
- Fixed size:
{"viewport": {"width": 1280, "height": 800}}(integers 1..8192; no other keys) - Responsive (follow the real window):
{"viewport": null}
Applies to every currently-open tab; tabs opened later inherit the policy.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
browser_host | query | string | No | Instance host. Must be paired with browser_port; when both are omitted the single running instance is selected (400 AMBIGUOUS_INSTANCE with more than one). |
browser_port | query | integer | No | Instance port. Must be paired with browser_host. |
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
viewport | object | null | Yes | Fixed size {width, height} (integers 1..8192, no other keys), or null for responsive. |
The fixed-size object accepts only these properties:
| Field | Type | Required | Description |
|---|---|---|---|
width | integer | Yes | Viewport width (1..8192). |
height | integer | Yes | Viewport height (1..8192). |
Response
Section titled “Response”{ "viewport": { "width": 1280, "height": 800 }, "source": "runtime", "tabs": 2, "converged": true}{ "error": "Viewport width must be an integer between 1 and 8192", "code": "VALIDATION_ERROR", "details": {}}{ "error": "No browser instance is running", "code": "NO_INSTANCE", "details": { "reason": "no_instance" }}{ "error": "Instance was created with a fixed viewport; close and recreate it responsive", "code": "REQUIRES_RESTART", "details": {}}{ "error": "Responsive viewport at runtime is not supported on this engine", "code": "NOT_SUPPORTED", "details": { "engine": "firefox" }}{ "error": "Some tabs failed to apply the new viewport", "code": "VIEWPORT_APPLY_INCOMPLETE", "details": { "failedTabs": [3] }}SDK usage
Section titled “SDK usage”curl -X POST "https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com/viewport" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{"viewport": {"width": 1280, "height": 800}}'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.browser.introspection.setViewport({ viewport: { width: 1280, height: 800 } });Cookies
Section titled “Cookies”Get cookies
Section titled “Get cookies”GET /cookies
Returns all cookies for the browser context, optionally filtered by URL. Each cookie includes its name, value, domain, path, httpOnly and secure flags.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
browser_id | query | string | Yes | Unique identifier for the browser instance (0-based index) |
start | query | boolean | No | Controls instance creation behavior. Default mode: instances are created automatically. Set to false to prevent creation. When auto-start is disabled globally, set to true to create an instance. Omitting this parameter is not equivalent to sending true — the server branches on HOODY_DISABLE_AUTO_START (DISABLE ? start === 'true' : start !== 'false'), so an ABSENT value means “auto-start unless the operator disabled it” while an explicit true means “start even though the operator disabled it”. |
url | query | string | No | Filter cookies by URL |
Response
Section titled “Response”{ "cookies": [ { "name": "session", "value": "abc123xyz789", "domain": ".example.com", "path": "/", "httpOnly": true, "secure": true }, { "name": "pref", "value": "compact", "domain": ".example.com", "path": "/", "httpOnly": false, "secure": false } ]}SDK usage
Section titled “SDK usage”curl -X GET "https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com/cookies?browser_id=0" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.browser.cookies.get({ browser_id: '0' });Set cookies
Section titled “Set cookies”POST /cookies
Adds cookies to the browser context. Each cookie entry in the cookies array requires name, value, and url. The optional domain, path, httpOnly, and secure fields override inferred defaults.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
browser_id | query | string | Yes | Unique identifier for the browser instance (0-based index) |
start | query | boolean | No | Controls instance creation behavior. Default mode: instances are created automatically. Set to false to prevent creation. When auto-start is disabled globally, set to true to create an instance. Omitting this parameter is not equivalent to sending true — the server branches on HOODY_DISABLE_AUTO_START (DISABLE ? start === 'true' : start !== 'false'), so an ABSENT value means “auto-start unless the operator disabled it” while an explicit true means “start even though the operator disabled it”. |
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
cookies | array | Yes | List of cookies to add. |
Each cookie object supports:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Cookie name. |
value | string | Yes | Cookie value. |
url | string | Yes | URL the cookie is associated with. |
domain | string | No | Cookie domain (overrides inferred from url). |
path | string | No | Cookie path. |
httpOnly | boolean | No | Set the HttpOnly flag. |
secure | boolean | No | Set the Secure flag. |
Response
Section titled “Response”{ "added": 2}SDK usage
Section titled “SDK usage”curl -X POST "https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com/cookies?browser_id=0" \ -H "Authorization: Bearer $HOODY_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "cookies": [ { "name": "auth", "value": "token_abc123", "url": "https://example.com", "httpOnly": true, "secure": true } ] }'import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.browser.cookies.set({ cookies: [ { name: 'auth', value: 'token_abc123', url: 'https://example.com', httpOnly: true, secure: true, }, ],}, { browser_id: '0' });Clear all cookies
Section titled “Clear all cookies”DELETE /cookies
Removes all cookies from the browser context.
Parameters
Section titled “Parameters”| Name | In | Type | Required | Description |
|---|---|---|---|---|
browser_id | query | string | Yes | Unique identifier for the browser instance (0-based index) |
start | query | boolean | No | Controls instance creation behavior. Default mode: instances are created automatically. Set to false to prevent creation. When auto-start is disabled globally, set to true to create an instance. Omitting this parameter is not equivalent to sending true — the server branches on HOODY_DISABLE_AUTO_START (DISABLE ? start === 'true' : start !== 'false'), so an ABSENT value means “auto-start unless the operator disabled it” while an explicit true means “start even though the operator disabled it”. |
Response
Section titled “Response”{ "cleared": true}SDK usage
Section titled “SDK usage”curl -X DELETE "https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com/cookies?browser_id=0" \ -H "Authorization: Bearer $HOODY_TOKEN"import { HoodyClient } from 'hoody-sdk';
const client = new HoodyClient({ baseURL: 'https://{projectId}-{containerId}-browser-1.{server}.containers.hoody.com', token: process.env.HOODY_TOKEN });
await client.browser.cookies.clear({ browser_id: '0' });