# serverFetch vs browserFetch in ego-browser: Key Differences Explained

> Discover the key differences between serverFetch and browserFetch in ego-browser. Understand how each executes HTTP requests from the Node.js host or browser page.

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

---

**serverFetch executes HTTP requests from the Node.js host process while browserFetch runs requests inside the controlled browser page, inheriting cookies, authentication state, and same-origin policies.**

The `ego-browser` package in the **citrolabs/ego-lite** repository exposes a unified `fetch` façade that abstracts two distinct HTTP strategies. Understanding the **difference between serverFetch and browserFetch** is essential for writing automation scripts that interact with both external APIs and authenticated web applications.

## Execution Context and Architecture

### Server-Side Requests with serverFetch

As implemented in [`ego-browser/src/http.ts`](https://github.com/citrolabs/ego-lite/blob/main/ego-browser/src/http.ts) (lines 11-27), **serverFetch** operates entirely within the Node.js runtime that hosts the ego-lite agent. It calls the native Node.js `fetch` implementation directly, making it suitable for retrieving resources that do not require the browser's session context. Because it runs server-side, it only accepts absolute URLs and has no access to the page's cookies or local storage.

### Browser-Side Requests with browserFetch

Conversely, **browserFetch** (defined in [`ego-browser/src/http.ts`](https://github.com/citrolabs/ego-lite/blob/main/ego-browser/src/http.ts), lines 35-52) executes code inside the active browser tab via the `evaluate` helper from [`src/cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/cdp-eval.ts). This method creates an async IIFE within the page’s JavaScript context, allowing the request to inherit the page’s origin, CSRF tokens, and authentication cookies. It supports relative URLs, which resolve against the current page's location.

## Source Code Implementation Details

Underlying these differences are distinct timeout mechanisms and header handling strategies:

- **serverFetch**: Uses `AbortSignal.timeout` (requires Node.js ≥ 16) for request cancellation. It merges caller-provided headers with a default `User-Agent: Mozilla/5.0` to emulate browser requests, and validates that URLs are absolute.

- **browserFetch**: Implements manual timeout handling via `setTimeout` and an `AbortController` injected into the page context. It relies on the browser's native `fetch`, automatically including the page's default headers, cookies, and security policies.

The unified façade exposing both methods is defined in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) (lines 28-31), while public type signatures and comprehensive documentation reside in [`src/format.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/format.ts) (lines 886-925).

## Key Differences Comparison

| Feature | serverFetch | browserFetch |
|---------|-------------|--------------|
| **Execution Environment** | Node.js host process | Active browser page via CDP |
| **URL Support** | Absolute URLs only | Absolute and relative URLs |
| **Authentication State** | No inherited cookies or sessions | Full cookie and session inheritance |
| **User-Agent Handling** | Injected `Mozilla/5.0` | Native browser header |
| **Timeout Mechanism** | `AbortSignal.timeout` | `AbortController` with `setTimeout` |
| **Error Handling** | Throws on non-OK HTTP statuses | Throws on non-OK HTTP statuses |

## Practical Code Examples

Use **serverFetch** when retrieving external resources from third-party APIs that do not require session authentication:

```typescript
// Server-side: Fetch external data with custom timeout
const html = await fetch.server('https://api.example.com/data', {
  timeout: 10,
  headers: { 'Accept': 'application/json' }
});

```

Use **browserFetch** for authenticated endpoints that rely on the current page's security context:

```typescript
// Browser-side: Call API using current page's cookies and origin
const userData = await fetch.browser('/api/user/profile', {
  method: 'GET',
  headers: { 'Accept': 'application/json' },
  timeout: 5
});
// Relative URL '/api/user/profile' resolves against window.location

```

## When to Use Each Method

**Choose serverFetch** for operations such as downloading static assets from CDNs, scraping public HTML pages, or calling external REST APIs where browser session state is irrelevant. This avoids the overhead of browser execution and bypasses Content Security Policy restrictions that might block requests within the page context.

**Choose browserFetch** when interacting with endpoints protected by CSRF tokens, session cookies, or strict same-origin policies. This method executes requests as if the user triggered them manually, preserving the authentication and security context of the active tab.

## Summary

- **serverFetch** runs in Node.js via [`ego-browser/src/http.ts`](https://github.com/citrolabs/ego-lite/blob/main/ego-browser/src/http.ts) (lines 11-27), requires absolute URLs, and uses `AbortSignal.timeout`
- **browserFetch** executes inside the browser page via [`src/cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/cdp-eval.ts), inherits cookies, resolves relative URLs, and uses `AbortController`
- Both methods throw errors for non-OK HTTP statuses and are exposed through the unified façade in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)
- serverFetch adds a default Mozilla User-Agent; browserFetch uses native browser headers

## Frequently Asked Questions

### Can browserFetch access cookies from the current browser session?

Yes. Because **browserFetch** executes via the `evaluate` helper in [`src/cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/cdp-eval.ts), it runs the `fetch` call within the page's JavaScript context. This means it automatically includes all cookies, authentication headers, and browser state associated with the current origin, behaving exactly like a user-initiated request.

### Why does serverFetch require absolute URLs while browserFetch supports relative paths?

The **serverFetch** implementation in [`ego-browser/src/http.ts`](https://github.com/citrolabs/ego-lite/blob/main/ego-browser/src/http.ts) runs in the Node.js environment, which has no concept of a "current page" or base URL for resolution. Therefore, it cannot resolve relative paths. **browserFetch** executes inside the browser where the native `fetch` resolves relative paths against `window.location`.

### Which method should I use for downloading large files?

Use **serverFetch** for large external downloads to avoid consuming browser memory and to bypass potential Content Security Policy restrictions within the page. serverFetch streams data directly through the Node.js process, while browserFetch executes within the browser context and inherits all page-level limitations.

### Does serverFetch support custom headers?

Yes. According to the implementation in [`ego-browser/src/http.ts`](https://github.com/citrolabs/ego-lite/blob/main/ego-browser/src/http.ts), serverFetch merges caller-provided headers with its default `User-Agent`. You can pass any valid headers object to override defaults or add API keys for external services, though the request will not include any cookies from the browser session.