Skip to main content

browser.screenshot_url

The reference pack for the helmdeck pack substrate. Drives a headless Chromium session via CDP to navigate to a URL and capture a PNG screenshot, then uploads the PNG to the artifact store and returns both an artifact_key reference and a signed S3 URL (in the response's top-level artifacts block) that operators can fetch directly. Smoke-test target on every release; first pack to ship in any new MCP integration.

Inputs

FieldTypeRequiredDefaultNotes
urlstringyesAbsolute URL. Validated by the egress guard (RFC 1918, metadata IP, loopback all blocked).
fullPagebooleannofalseCapture the entire scrollable page rather than just the viewport.

Outputs

FieldTypeNotes
output.urlstringEcho of the input URL (helps when batching).
output.artifact_keystringbrowser.screenshot_url/<rand>-screenshot.png. The stable handle that follow-up packs can reference.
output.sizenumberPNG size in bytes.
artifactsarray (top-level)Each entry has key, url (signed S3 URL valid 15 min), size, content_type, created_at. The url is what an agent or operator actually opens.

Vault credentials needed

None. Pure unauthenticated GET → screenshot. For pages behind a login, use web.login_and_fetch (vault-backed) or web.scrape_spa with a vault session-cookie credential.

Use it from your agent (OpenClaw chat-UI worked example)

Prompt (sent in OpenClaw chat UI / openclaw-cli agent):

:Use the helmdeck__browser-screenshot_url tool to take a fullPage screenshot of https://example.com. Tell me the artifact_key and the size in bytes.

Tool call (1 call, no failures):

{
"name": "helmdeck__browser-screenshot_url",
"arguments": {
"url": "https://example.com",
"fullPage": true
}
}

Pack response (truncated):

{"pack":"browser.screenshot_url","version":"v1","output":{"artifact_key":"browser.screenshot_url/e45db6a88080613e-screenshot.png","size":16491,"url":"https://example.com"},"artifacts":[{"key":"browser.screenshot_url/e45db6a88080613e-screenshot.png","url":"http://garage:3900/helmdeck-artifacts/browser.screenshot_url/e45db6a88080613e-screenshot.png?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Credential=GKaef177ebe9fd814dc103b84b%2F20260507%2Fgarage%2Fs3%2Faws4_request\u0026X-Amz-Date=20260507T202256Z\u0026X-Amz-Expires=900\u0026X-Amz-SignedHeaders=host\u0026X-Amz-Signature=6759dc0df6e691a1bf36f610e6511153f221aedefd0edae0d45675cfc8f27d92","size":16491,"content_type":"image/png","created_at":"2026-05-07T20:22:56.861538262Z","pack":"browser.screenshot_url"}],"duration_ms":2872412151,"session_id
...[truncated]

Agent's final reply:

  • artifact_key: browser.screenshot_url/e45db6a88080613e-screenshot.png
  • size: 16,491 bytes

Verified via OpenClaw 2026.5.6 + helmdeck v0.9.0-dev + openrouter/openai/gpt-oss-120b on 2026-05-07 (cost: $0.0082).

Developer reference (curl)

curl -fsS -X POST http://localhost:3000/api/v1/packs/browser.screenshot_url \
-H "Authorization: Bearer $JWT" \
-H 'Content-Type: application/json' \
-d '{"url":"https://example.com","fullPage":true}'

Real captured response (signed-URL portions truncated):

{
"pack": "browser.screenshot_url",
"version": "v1",
"output": {
"url": "https://example.com",
"artifact_key": "browser.screenshot_url/22228b5ede04b9b0-screenshot.png",
"size": 16491
},
"artifacts": [
{
"key": "browser.screenshot_url/22228b5ede04b9b0-screenshot.png",
"url": "http://garage:3900/helmdeck-artifacts/browser.screenshot_url/22228b5ede04b9b0-screenshot.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&...&X-Amz-Expires=900&X-Amz-Signature=...",
"size": 16491,
"content_type": "image/png",
"created_at": "2026-05-07T19:36:25.507708975Z"
}
],
"duration_ms": 3236
}

The signed URL expires in 15 minutes (X-Amz-Expires=900). For longer-lived access, fetch the bytes directly:

curl -fsS -H "Authorization: Bearer $JWT" \
"http://localhost:3000/api/v1/artifacts/browser.screenshot_url/22228b5ede04b9b0-screenshot.png" \
-o screenshot.png

Error codes

CodeTriggersCaptured response
invalid_inputurl field missing{"error":"invalid_input","message":"missing required field \"url\""}
handler_failedURL is malformed (chromedp can't parse){"error":"handler_failed","message":"navigate not-a-real-url: Cannot navigate to invalid URL (-32000)"}
handler_failedPage navigation fails (DNS, TLS, timeout)wrapped Go error
session_unavailableEngine has no CDP factory wired (sidecar image absent)runtime not configured
artifact_failedGarage / S3 wouldn't accept the uploadcheck Garage health, disk pressure

The egress guard runs after URL parsing, so a syntactically-malformed URL hits handler_failed, while a parseable URL pointing at a blocked range hits invalid_input. Document both for completeness; agents react differently to each.

Session chaining

needs_session: true. The engine acquires an ephemeral session per call; sessions are transparent to this pack (no _session_id field). For chained workflows where you want the same browser session across multiple browser.* calls, use browser.interact instead — its actions array gives you N steps in one call.

Async behavior

Synchronous only. Typical latency 1–4 seconds against a warm sidecar. Heavy pages bounded by the per-session timeout (default 60s) → past that, handler_failed with context deadline exceeded.

See also