What's the Difference Between serverFetch and BrowserFetch in ego-browser?
serverFetch executes HTTP requests from the Node.js host process using native fetch, while browserFetch runs requests inside the controlled browser page via JavaScript evaluation, inheriting the page's cookies, authentication state, and origin policies.
The ego-browser package from the citrolabs/ego-lite repository exposes a unified fetch façade that abstracts two distinct networking strategies. Understanding the difference between serverFetch and browserFetch in ego-browser ensures your automation scripts make requests from the correct execution context, whether hitting external APIs or interacting with authenticated web applications.
Execution Context: Server vs Browser
The fundamental distinction lies in where each method executes the HTTP request.
Node.js Host Process (serverFetch)
serverFetch operates inside the Node.js runtime that drives the ego-lite automation framework. According to the source code in [src/http.ts](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/http.ts#L11-L27), this method calls the global fetch available to Node directly, making it ideal for server-side data retrieval. Because it runs outside the browser tab, it has no access to the page's JavaScript context, cookies, or storage.
Active Page Context (browserFetch)
Conversely, browserFetch executes within the active browser tab that the agent controls. As implemented in [src/http.ts](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/http.ts#L35-L52), this method sends a payload to the browser via the evaluate helper (defined in [src/cdp-eval.ts](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/cdp-eval.ts)), creating an async IIFE that runs the native fetch inside the page. This allows the request to inherit the page's origin, cookies, and browser-level state.
Implementation Differences
Beyond execution context, the two methods differ in their underlying implementation and capabilities.
Request Headers and User-Agent
serverFetch merges caller-provided headers with a default User-Agent: Mozilla/5.0 header to emulate browser requests when contacting external servers. In contrast, browserFetch uses the page's native fetch implementation, automatically including any default headers the browser would send, such as cookies, Accept headers, and CSRF tokens.
URL Resolution
serverFetch requires absolute URLs because the Node process has no concept of a "current page" against which to resolve relative paths. browserFetch accepts relative URLs, which are resolved against the current page's URL, mirroring standard browser navigation behavior.
Timeout Handling
The server implementation uses AbortSignal.timeout (Node ≥ 16) to enforce request timeouts. The browser implementation implements manual timeout handling via setTimeout and an AbortController within the page context.
Practical Use Cases
Choose the appropriate fetch method based on your automation requirements:
-
Use
fetch.serverwhen retrieving external resources not tied to the page, such as downloading JSON from third-party APIs or scraping remote HTML pages that don't require session authentication. -
Use
fetch.browserwhen the request must be made as if the user performed it, such as calling endpoints that rely on the page's authentication cookies, CSRF tokens, or same-origin policies.
Code Examples
The following examples demonstrate the practical difference between these methods:
// Server-side fetch: Retrieve raw HTML from an external site
const html = await fetch.server('https://example.com', {
timeout: 10, // seconds
headers: { 'Accept': 'text/html' },
});
// html contains the page source as a string
// Browser-side fetch: Call an API requiring the page's cookies
// Assumes the current tab is logged into a web application
const data = await fetch.browser('/api/user/profile', {
method: 'GET',
headers: { 'Accept': 'application/json' },
timeout: 5,
});
// data contains the JSON response from the authenticated endpoint
Both methods throw errors for non-OK HTTP statuses and are exposed to agent scripts through the unified fetch façade defined in [src/helpers.ts](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts#L28-L31).
Summary
serverFetchruns in the Node.js host process with no browser context, requiring absolute URLs and emulating a browser via User-Agent headers.browserFetchexecutes inside the controlled page viaevaluate, inheriting cookies and authentication while supporting relative URL resolution.- Implementation location: Both methods are implemented in [
src/http.ts](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/http.ts), with public signatures documented in [src/format.ts](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/format.ts#L886-L925). - Timeout strategies differ:
serverFetchusesAbortSignal.timeoutwhilebrowserFetchusesAbortControllerwith manual timeout handling.
Frequently Asked Questions
Can I use relative URLs with serverFetch?
No. Because serverFetch executes in the Node.js host process, it has no concept of a current page URL and requires absolute URLs. If you pass a relative URL to serverFetch, it will fail to resolve the request.
Does browserFetch automatically include the page's cookies?
Yes. Since browserFetch executes the fetch call inside the browser page via the evaluate helper, it automatically includes all cookies, authentication headers, and browser state associated with the current tab. This makes it ideal for interacting with authenticated APIs.
Which method should I use for scraping external websites?
Use fetch.server for scraping external websites. This method runs from the Node process, allows you to specify custom headers, and doesn't require loading the target site in a browser tab. It also adds a browser-like User-Agent header by default to avoid bot detection.
How does timeout handling differ between serverFetch and browserFetch?
serverFetch uses Node's native AbortSignal.timeout mechanism (available in Node 16+), while browserFetch implements timeouts manually using setTimeout and an AbortController within the page's JavaScript context. Both accept a timeout value in seconds, but the underlying cancellation mechanism differs based on the execution environment.
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 →