How camofox-browser Snapshot Screenshots Include Base64 PNG Images

When the includeScreenshot=true query parameter is passed to the /snapshot endpoint, camofox-browser captures a PNG via Playwright, converts the binary buffer to Base64 using pngBuffer.toString('base64'), and embeds it within the JSON response as a structured object containing mimeType and data fields.

The camofox-browser repository (jo-inc/camofox-browser) provides a browser automation server that generates accessible DOM snapshots alongside optional visual screenshots. Understanding how camofox-browser snapshot screenshots include base64 PNG images is essential for integrating visual verification into LLM toolchains and automated testing workflows.

The /snapshot Endpoint and Screenshot Activation

The /snapshot route and its cached-offset variant support optional screenshot generation through a query string parameter. When the request includes includeScreenshot=true, the handler triggers a visual capture of the current page state.

This functionality is implemented consistently across three distinct code paths in server.js:

  1. Cached-offset path (lines 1876-1880): Retrieves a previously computed snapshot window and attaches the screenshot when requested.
  2. Google SERP fast-path (lines 1823-1826): Processes Google search results pages, building the snapshot before optionally appending the screenshot.
  3. Normal ARIA snapshot path (lines 1829-1832): Generates an accessibility tree snapshot and conditionally includes the Base64 PNG image.

Base64 Encoding Implementation in server.js

The conversion from binary PNG to Base64 string occurs through a two-step process in the route handlers. First, Playwright captures the screenshot using:

await tabState.page.screenshot({ type: 'png' })

Then, the resulting buffer undergoes encoding:

const base64String = pngBuffer.toString('base64')

The handler constructs the response object by adding a screenshot field to the JSON payload. This field contains an object with data (the Base64 string) and mimeType set to 'image/png'.

The same encoding logic applies across all three snapshot paths in server.js, ensuring consistent behavior whether processing cached offsets, Google SERP pages, or standard ARIA-based snapshots.

Requesting and Decoding Screenshot Data

Clients can request a snapshot with an embedded screenshot using HTTP query parameters or programmatic client methods.

HTTP Request Example

Use the includeScreenshot=true query parameter when calling the /snapshot endpoint:

curl -G "http://localhost:9377/snapshot" \
  -d "userId=myUser" \
  -d "targetId=abc123" \
  -d "includeScreenshot=true" \
  -H "Accept: application/json"

The JSON response structure includes the Base64-encoded image:

{
  "url": "https://example.com",
  "snapshot": "...",
  "refsCount": 42,
  "screenshot": {
    "mimeType": "image/png",
    "data": "iVBORw0KGgoAAAANSUhEUgAA..."
  }
}

Decoding the Base64 PNG

To convert the Base64 string back to binary data in Node.js:

const base64Data = snapshot.screenshot.data;
const pngBuffer = Buffer.from(base64Data, 'base64');

// Verify PNG magic bytes (optional validation)
if (pngBuffer[0] === 0x89 && pngBuffer[1] === 0x50 &&
    pngBuffer[2] === 0x4E && pngBuffer[3] === 0x47) {
  console.log('Valid PNG image');
}

Why Base64 Encoding Is Used

Base64 encoding serves two primary technical purposes in the camofox-browser architecture. JSON cannot transport raw binary data, so encoding the PNG buffer to Base64 preserves the image data within a text-safe format that maintains JSON payload validity.

Additionally, the LLM toolchain expects image data in a structured { mimeType, data } format, mirroring the "image block" convention used by OpenClaw and similar systems. This standardization allows seamless integration with language model interfaces that consume both textual snapshots and visual screenshots.

Testing and Validation

The end-to-end test suite in tests/e2e/snapshotScreenshot.test.js validates the Base64 encoding implementation through several assertions:

  • The screenshot property exists and contains a non-empty Base64 string when includeScreenshot=true.
  • Decoded data begins with the PNG magic bytes 0x89 0x50 0x4E 0x47.
  • ARIA snapshot content remains unchanged regardless of screenshot inclusion.

Separate unit tests in tests/unit/screenshotToolResult.test.js cover the /tabs/:tabId/screenshot endpoint, which returns raw binary PNG data rather than Base64-encoded JSON.

Summary

  • Three implementation paths in server.js (lines 1823-1880) handle screenshot generation for cached offsets, Google SERP pages, and standard ARIA snapshots.
  • Playwright capture and Node.js encoding: The page.screenshot({ type: 'png' }) method generates the image, while buffer.toString('base64') handles the encoding.
  • Structured response format: Screenshots appear as { mimeType: 'image/png', data: <base64> } objects within the JSON response.
  • Validation via magic bytes: The test suite confirms PNG validity by checking for the 0x89 0x50 0x4E 0x47 header signature after Base64 decoding.

Frequently Asked Questions

How do I request a Base64-encoded screenshot from camofox-browser?

Append includeScreenshot=true as a query parameter to the /snapshot endpoint request. The JSON response will contain a screenshot object with mimeType set to 'image/png' and data containing the Base64 string.

What does the screenshot object structure look like in the JSON response?

The screenshot field contains an object with two properties: mimeType (always 'image/png') and data (the Base64-encoded PNG string). This structure allows clients to identify the image format and decode the binary data accordingly.

How does the test suite verify the screenshot is a valid PNG?

Tests in tests/e2e/snapshotScreenshot.test.js decode the Base64 string and verify the resulting buffer starts with the PNG magic bytes 0x89 0x50 0x4E 0x47. This confirms the data represents a valid PNG image rather than corrupted or empty content.

Why does the API use Base64 encoding instead of returning raw binary image data?

JSON responses cannot contain raw binary data without corruption or encoding issues. Base64 encoding ensures the image data remains intact within the JSON payload while remaining compatible with LLM toolchains that expect structured { mimeType, data } image blocks.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →