Binding vs REST

NEW

The same Quick Action called two ways: over the REST API with a bearer token, and directly through the Workers browser binding. Same result, materially less setup.

env.BROWSER.quickAction() vs POST /markdown

REST API
javascript
// Needs CF_ACCOUNT_ID + CF_API_TOKEN as secrets, and the
// request leaves Cloudflare's network and comes back.
const resp = await fetch(
  `https://api.cloudflare.com/client/v4/accounts/${accountId}/browser-rendering/markdown`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${apiToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ url }),
  }
);
const { result } = await resp.json();
Workers binding
javascript
// No account id, no token, no external hop.
const resp = await env.BROWSER.quickAction('markdown', { url });
const { result } = await resp.json();

Runs sequentially, not in parallel — two concurrent renders of the same URL would double the billed browser time for no extra insight.

Use Cases

No Credential to Manage

The binding authenticates implicitly. There is no API token to provision, rotate, scope, or accidentally commit.

No External Hop

The Worker talks to Browser Run over Cloudflare’s own network instead of making an outbound HTTPS request to the public API.

Same Surface

Eight of the Quick Actions are available on the binding. /crawl stays REST-only, and it is the one place you still need a token.

Types lag the docs here. The shipped BrowserRun type declares eight actions and does not yet include accessibilityTree, nor formats on the snapshot options — both of which the REST API accepts today. Until the types catch up, reach for those two over REST.

Both paths hit the same service and return the same envelope. The binding removes the API token, the account id, and the outbound HTTP request. Treat the timings as illustrative rather than a benchmark — see the note below the results.