browserFetch vs serverFetch in ego-lite: HTTP Client Context Explained
serverFetch runs HTTP requests from the Node.js host process, while browserFetch executes requests inside the active browser page, inheriting cookies, authentication, and same-origin policies.
The ego-lite browser automation framework provides a unified fetch façade that conceals two fundamentally different execution strategies. Understanding when to use browserFetch versus serverFetch is essential for building reliable web agents that handle both external API calls and authenticated page interactions.
Execution Context: The Core Distinction
The primary difference between these two methods is where the HTTP request actually executes.
-
serverFetch— Runs inside Node.js on the host machine. It uses Node's nativefetch(available in Node 16+) to perform server-side requests with no browser context. -
browserFetch— Runs inside the active page's JavaScript environment. The request executes as if the user clicked a button or submitted a form, inheriting all browser state.
According to the ego-lite source code in package/ego-browser/src/http.ts, this distinction determines everything from cookie handling to URL resolution.
serverFetch: Server-Side HTTP Requests
Located at lines 11-27 in src/http.ts, serverFetch is designed for retrieving external resources independent of any page state.
Key Characteristics
| Feature | Implementation |
|---|---|
| URL handling | Requires absolute URLs only |
| Headers | Merges caller headers with default User-Agent: Mozilla/5.0 |
| Timeout | Uses native AbortSignal.timeout |
| Error behavior | Throws on non-OK HTTP statuses |
Code Example: Scraping External HTML
// Retrieve raw HTML from a third-party site
const html = await fetch.server('https://example.com/docs', {
timeout: 10, // seconds
headers: {
'Accept': 'text/html',
'Authorization': 'Bearer token123'
},
});
// Returns response body as string
Use serverFetch when you need to download files, query external APIs, or scrape content that doesn't require page authentication.
browserFetch: Authenticated Page Context Requests
Located at lines 35-52 in src/http.ts, browserFetch leverages the evaluate helper from src/cdp-eval.ts to run code directly inside the controlled browser tab.
Key Characteristics
| Feature | Implementation |
|---|---|
| URL handling | Supports relative URLs resolved against current page |
| Headers & cookies | Automatically includes the page's native browser headers and cookies |
| Timeout | Manual implementation via setTimeout + AbortController |
| Context | Respects same-origin policies and CSRF protections |
Code Example: Calling Authenticated APIs
// Current page is logged into a web application
const userData = await fetch.browser('/api/v1/user/profile', {
method: 'GET',
headers: { 'Accept': 'application/json' },
timeout: 5,
});
// Request includes the page's session cookies automatically
Use browserFetch when interacting with endpoints that require the user's active session, CSRF tokens, or same-origin protections.
Technical Implementation Differences
serverFetch Implementation Details
The serverFetch function in src/http.ts wraps Node's native fetch with minimal overhead:
// Simplified from src/http.ts lines 11-27
async function serverFetch(url: string, options: FetchOptions): Promise<string> {
const response = await fetch(url, {
...options,
headers: {
'User-Agent': 'Mozilla/5.0 ...', // Default browser-like UA
...options.headers,
},
signal: AbortSignal.timeout(options.timeout * 1000),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.text();
}
browserFetch Implementation Details
The browserFetch function constructs an async IIFE that runs inside the page via evaluate:
// Simplified from src/http.ts lines 35-52
async function browserFetch(url: string, options: FetchOptions): Promise<string> {
return evaluate(`
(async () => {
const controller = new AbortController();
const timeoutId = setTimeout(
() => controller.abort(),
${options.timeout * 1000}
);
try {
const response = await fetch('${url}', {
method: '${options.method || 'GET'}',
headers: ${JSON.stringify(options.headers)},
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) throw new Error('HTTP ' + response.status);
return await response.text();
} catch (e) {
clearTimeout(timeoutId);
throw e;
}
})()
`);
}
When to Use Each Method
Choose your fetch strategy based on these criteria:
-
Use
serverFetchwhen:- Accessing external APIs or third-party websites
- No authentication or page context is needed
- You need reliable timeout handling via
AbortSignal.timeout
-
Use
browserFetchwhen:- The endpoint requires the page's cookies or session
- CSRF tokens or same-origin policies apply
- You need to call APIs relative to the current page URL
Summary
serverFetchexecutes in Node.js with browser-like User-Agent headers; ideal for external API calls and scrapingbrowserFetchruns inside the active page viaevaluate, preserving authentication, cookies, and origin constraints- Both methods throw errors on non-OK HTTP statuses and support configurable timeouts
- Relative URLs work only with
browserFetch;serverFetchrequires absolute URLs - The unified
fetchfaçade is exposed throughsrc/helpers.tslines 28-31
Frequently Asked Questions
Can I use browserFetch without an active page?
No. browserFetch requires an active browser tab controlled by ego-lite because it relies on the evaluate function from src/cdp-eval.ts to inject JavaScript into the page context. Without a loaded page, there's no execution environment for the fetch call.
Does serverFetch share cookies with the browser?
No. serverFetch maintains completely separate cookie storage from the browser. According to the implementation in src/http.ts, it uses Node's native fetch with only a hardcoded User-Agent header. Any cookies must be manually provided in the headers option.
Why does browserFetch use a manual timeout instead of AbortSignal.timeout?
Browser compatibility. The browserFetch implementation targets the JavaScript environment inside the controlled page, which may run on older browser versions without native AbortSignal.timeout support. The manual setTimeout + AbortController pattern ensures consistent behavior across all Chrome versions.
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 →