serverFetch vs browserFetch in ego-lite: Choosing the Right HTTP Context
Use serverFetch when executing HTTP requests from the Node.js runtime without browser state, and browserFetch when requests must preserve page cookies, credentials, and same-origin policy.
The ego-browser package in the citrolabs/ego-lite repository exposes a unified fetch façade through helperContext() that enables agents to perform HTTP requests from either the server or browser context. Choosing between serverFetch and browserFetch determines whether your request executes within the Node process or inside the active browser page via Chrome DevTools Protocol (CDP).
Execution Environment Comparison
The fundamental difference lies in where the HTTP request is executed and what environment-specific data it carries.
serverFetch (Node Context)
serverFetch runs inside the Node.js process that hosts the ego-lite runtime. According to the implementation in src/http.ts, it binds to the native globalThis.fetch available to the server and automatically injects a browser-like User-Agent header ("Mozilla/5.0").
Best for:
- Accessing third-party APIs that do not depend on the current page's cookies or origin
- Performing large-scale data pulls with custom headers
- Fetching absolute URLs regardless of the displayed page
browserFetch (Browser Context)
browserFetch executes inside the active browser page via CDP's evaluate() method. The implementation packages request parameters into a JSON payload and runs an async IIFE within the page's JavaScript engine, using the page's native fetch implementation.
Best for:
- Calling endpoints that rely on the page's session cookies or CSRF tokens
- Fetching relative URLs (e.g.,
/api/data) that resolve against the current base URL - Respecting the same-origin policy enforced by the browser
Implementation Details
In src/http.ts, the two implementations diverge in their timeout and execution strategies:
-
serverFetch: UsesAbortSignal.timeoutfor configurable timeouts and returns the response body as a string. It throws a plainErrorif the response status is notok, including the HTTP method and status code in the message. -
browserFetch: Creates its ownAbortControllertimer and executes the fetch within the page context. Because it runs inside the page, CORS failures and network errors surface as JavaScript errors from theevaluate()call.
The fetch façade is registered in src/helpers.ts (lines 818‑820), exposing fetch.server and fetch.browser to agent scripts.
Practical Code Examples
Server-Side Requests with serverFetch
Use fetch.server when you need a fast, deterministic request without browser overhead:
// Retrieve HTML from an external site without involving the browser page
const html = await fetch.server('https://example.com', {
timeout: 10, // seconds
headers: { 'Accept': 'text/html' },
});
console.log('Fetched HTML length:', html.length);
This request originates from the Node runtime using a static User-Agent. No cookies from the current page are transmitted, making it ideal for third-party API calls.
Browser-Context Requests with browserFetch
Use fetch.browser when the request requires browser state:
// Call a relative API endpoint that requires session cookies
const data = await fetch.browser('/api/user/profile', {
method: 'GET',
headers: { 'Accept': 'application/json' },
timeout: 5,
});
console.log('User profile:', JSON.parse(data));
Because this executes inside the active page, the request automatically includes the page's cookies and resolves /api/user/profile against the current page's base URL.
Combining Both fetch Modes
You can securely mix both approaches to extract tokens from the browser and use them server-side:
// Obtain CSRF token from the page, then post data from the server
const csrf = await fetch.browser('/api/csrf-token');
await fetch.server('https://api.example.com/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrf,
},
body: JSON.stringify({ foo: 'bar' }),
});
This pattern leverages browserFetch to access page-stored credentials, then uses serverFetch for the subsequent submission, maintaining security boundaries while enabling flexible data gathering.
Error Handling and Timeouts
Both methods enforce identical error semantics: they throw a plain Error if the response is not ok (status outside 200-299). The error message includes the HTTP status code and method used.
With browserFetch, additional error types may surface from the page context, such as CORS violations or network failures specific to the browser's environment, which are captured from the CDP evaluate() execution.
Summary
- Use
serverFetch(viafetch.server) for Node-side requests that require custom headers, absolute URLs, or no browser state. Implemented insrc/http.tsusingglobalThis.fetch. - Use
browserFetch(viafetch.browser) for requests that must execute within the page context to preserve cookies, handle relative URLs, and respect same-origin policy. Implemented using CDPevaluate(). - Both methods support configurable timeouts (
AbortSignal.timeoutfor server,AbortControllerfor browser) and throw errors on non-ok responses. - The façade is registered in
src/helpers.ts, making both methods available through the helper context provided to agent scripts.
Frequently Asked Questions
What is the primary difference between serverFetch and browserFetch in ego-lite?
serverFetch executes in the Node.js runtime using the server's native fetch, while browserFetch runs inside the active browser page via Chrome DevTools Protocol's evaluate() method. The key distinction is that browserFetch preserves the page's cookies, origin, and credentials, whereas serverFetch operates independently of browser state.
Can I use relative URLs with serverFetch?
No. serverFetch requires absolute URLs because it executes in the Node context without a base URL reference. Use browserFetch for relative URLs (e.g., /api/data), as it resolves paths against the current page's location within the browser environment.
How does error handling compare between the two methods?
Both methods throw a plain Error if the HTTP response status is not ok, including the status code and method in the error message. However, browserFetch may also surface page-specific errors such as CORS violations or network failures from the browser's JavaScript engine, while serverFetch errors originate from the Node runtime.
When should I combine serverFetch and browserFetch in a single script?
Combine them when you need to extract authentication tokens or CSRF values from the browser state using browserFetch, then transmit data to external APIs using serverFetch. This pattern keeps sensitive credentials within the browser context while allowing server-side requests to third-party endpoints that don't require browser sessions.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →