browserFetch vs serverFetch in ego-lite: Execution Context and Use Cases Explained

The fetch.browser() helper runs HTTP requests inside the active browser page (inheriting cookies and origin), while fetch.server() executes requests directly from the Node.js agent process outside the browser context.

In citrolabs/ego-lite, these two complementary helpers solve distinct automation challenges. Understanding when to use each prevents authentication failures, CORS errors, and unexpected behavior in your agent scripts. Both functions are implemented in src/http.ts and exposed through the helpers registry in src/helpers.ts.

What browserFetch Does: In-Page Request Execution

fetch.browser() executes fetch() inside the currently loaded page using Chrome DevTools Protocol (CDP) evaluation.

How It Works

According to the source code in src/http.ts (lines 35-52), browserFetch sends a script via evaluate that runs the native fetch API within the page's JavaScript context. This gives it three critical properties:

  • Cookie inheritance: Requests include the page's stored cookies automatically
  • Origin respect: Same-origin policy applies as if the user clicked a button
  • Relative URL resolution: Paths like /api/data resolve against the page URL

When to Use browserFetch

Use fetch.browser() when you need to interact with endpoints that depend on the page state:

  • Authenticated API endpoints requiring session cookies
  • CSRF-protected forms
  • Relative URLs that only make sense in the page context
  • Endpoints that check Origin or Referer headers
// POST to a relative endpoint with automatic cookie handling
const response = await fetch.browser('/api/v1/user/profile', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'updated' })
});

What serverFetch Does: Agent-Side Request Execution

fetch.server() runs HTTP requests from the Node.js process driving the browser, completely outside the page context.

How It Works

The serverFetch implementation in src/http.ts (lines 11-27) calls globalThis.fetch with a browser-like User-Agent header and timeout controller. Since it runs in Node, it operates without browser security constraints.

Key Characteristics

  • No cookie jar: Requests are stateless unless you manually attach headers
  • No origin restrictions: Can reach any URL regardless of CORS policies
  • Direct network access: Bypasses any page-level proxies or interceptors

When to Use serverFetch

Use fetch.server() for operations independent of page state:

  • Downloading static resources (images, PDFs, binaries)
  • Calling external APIs unrelated to the current session
  • Fetching data before navigating to a target page
  • Bypassing CORS restrictions that block browser requests
// Fetch a resource directly from the agent
const html = await fetch.server('https://cdn.example.com/data.json');
console.log('Fetched bytes:', html.length);

Side-by-Side Comparison

Aspect fetch.browser() fetch.server()
Execution location Inside active browser page (evaluate) Node.js agent process
Source file src/http.ts lines 35-52 src/http.ts lines 11-27
Cookie handling Automatic (page's cookie jar) None (manual header required)
Relative URLs Resolve against page URL Invalid (requires absolute URL)
CORS policy Enforced by browser Ignored
Use case Page-dependent API calls External resource fetching

Implementation Details from Source Code

Both helpers are registered in src/helpers.ts where the documentation string explains their API surface (lines 818-819). Their public signatures are declared in src/format.ts for the help() system:

  • "fetch.server": { signature: "fetch.server(url, options?) => Promise<string>", ... } (lines 886-904)
  • "fetch.browser": { signature: "fetch.browser(url, options?) => Promise<string>", ... } (lines 906-925)

Both return Promise<string> containing the response body, not a Response object. The options parameter accepts standard fetch init properties (method, headers, body, etc.).

Common Mistakes to Avoid

Using fetch.server() for authenticated endpoints : Server requests lack the page's session cookies. APIs requiring login will return 401 errors.

Using fetch.browser() for cross-origin external APIs : Browser CORS policies block requests to unrelated domains unless the server allows them.

Passing relative URLs to fetch.server() : Server fetch has no page context; always use absolute URLs.

Summary

  • fetch.browser() runs inside the loaded page via CDP evaluate, inheriting cookies, origin, and security policies—ideal for authenticated page APIs.
  • fetch.server() executes from the Node agent with direct network access, bypassing CORS and browser constraints—ideal for external resources and pre-navigation fetching.
  • Both helpers live in src/http.ts, are registered in src/helpers.ts, and documented in src/format.ts.
  • Both return Promise<string> and accept standard fetch options.

Frequently Asked Questions

Can I use fetch.server() to bypass CORS restrictions?

Yes. Since fetch.server() runs in Node.js outside the browser context, it is not subject to CORS policies. This makes it useful for accessing APIs that deny cross-origin browser requests. However, any authentication or session state must be manually provided in the headers option.

Why does fetch.browser() fail with a relative URL error on some pages?

fetch.browser() resolves relative URLs against the current page URL. If no page is loaded (or the page URL is about:blank), resolution fails. Ensure you've navigated to a valid page with browser.goto() before calling fetch.browser() with relative paths.

Do these helpers support streaming responses?

No. According to the signature declarations in src/format.ts, both helpers return Promise<string>—the full response body as a string. For large binary downloads, use fetch.server() and consider the memory implications, or implement chunked handling at the agent level.

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 →