# What's the Difference Between serverFetch and BrowserFetch in ego-browser?

> Discover the difference between serverFetch and browserFetch in ego-browser. Learn how serverFetch uses Node.js fetch while browserFetch leverages the controlled browser's context for HTTP requests.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: deep-dive
- Published: 2026-07-27

---

**`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/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/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/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.server`** when 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.browser`** when 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:

```typescript
// 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

```

```typescript
// 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/src/helpers.ts)](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts#L28-L31).

## Summary

- **`serverFetch`** runs in the Node.js host process with no browser context, requiring absolute URLs and emulating a browser via User-Agent headers.
- **`browserFetch`** executes inside the controlled page via `evaluate`, 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/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/src/format.ts)](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/format.ts#L886-L925).
- **Timeout strategies differ**: `serverFetch` uses `AbortSignal.timeout` while `browserFetch` uses `AbortController` with 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.