# Difference Between serverFetch and browserFetch in Ego-Lite HTTP Module

> Understand the difference between serverFetch and browserFetch in Ego-Lite. Learn how serverFetch uses Nodejs for requests and browserFetch leverages CDP for browser-context fetching.

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

---

**The difference between `serverFetch` and `browserFetch` is that `serverFetch` executes HTTP requests in the Node.js runtime with a forced browser-like User-Agent, while `browserFetch` executes requests inside the active browser page via Chrome DevTools Protocol (CDP), inheriting the page's cookies, authentication state, and relative URL resolution.**

The Ego-Lite browser automation framework provides two complementary HTTP helpers in its `ego-browser` package that serve distinct execution contexts. Understanding the difference between `serverFetch` and `browserFetch` is essential for choosing the right tool for server-side data extraction versus browser-context API interactions. Both functions are implemented in [`src/http.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/http.ts) and offer identical interfaces but operate through fundamentally different networking stacks.

## Execution Environment and Context

The primary distinction lies in where the HTTP request physically executes.

### serverFetch (Node.js Runtime)

`serverFetch` runs directly inside the Node.js process hosting the Ego-Lite harness. According to the source code in [`src/http.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/http.ts) (lines 11-27), this helper retrieves the native `fetch` implementation from `globalThis` and invokes it from the server side. Because it bypasses the browser entirely, it requires **absolute URLs** and cannot access cookies or session state from the active page.

### browserFetch (Browser Page Context)

`browserFetch` executes within the **current browser page** that the harness is driving. As implemented in [`src/http.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/http.ts) (lines 35-52), this function packages the request parameters into a JSON payload and uses the `evaluate()` helper from [`src/cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/cdp-eval.ts) to run an async IIFE inside the page context. The request utilizes the browser's native `fetch` API, inheriting all automatic behaviors including CORS handling, cookie transmission, and authentication headers.

## Key Implementation Differences

Beyond execution context, these helpers diverge in four critical areas:

- **User-Agent Handling**: `serverFetch` explicitly forces a browser-like `User-Agent` header (`"Mozilla/5.0"`) to ensure remote services treat the request as a standard web browser. `browserFetch` makes no such override, allowing the request to use the page's native user-agent string.

- **URL Resolution**: `serverFetch` accepts **absolute URLs only** and fails with relative paths. `browserFetch` accepts **relative URLs**, resolving them against the active page's `location` before transmission.

- **Timeout Mechanism**: `serverFetch` uses `AbortSignal.timeout` for request cancellation, while `browserFetch` instantiates an `AbortController` inside the evaluated page script to manage timeouts.

- **Error Handling**: Both methods throw custom errors when `response.ok` is false, but `browserFetch` propagates exceptions from the browser context back to the Node.js harness through the CDP evaluation layer.

## Practical Code Examples

### Using serverFetch for Absolute URLs

Use `serverFetch` when you need to bypass the browser's sandbox or require a consistent user-agent across environments:

```javascript
import { serverFetch } from 'ego-browser/src/http.js';

const html = await serverFetch('https://api.example.com/data.json', {
  method: 'GET',
  timeout: 10,  // seconds
  headers: { 
    'Accept': 'application/json',
    'Authorization': 'Bearer token123'
  },
});

// Returns raw response text; throws if status >= 400
console.log(html);

```

### Using browserFetch for Relative Endpoints

Use `browserFetch` when interacting with APIs that rely on the page's authentication state or when fetching resources relative to the current URL:

```javascript
import { browserFetch } from 'ego-browser/src/http.js';

const profileData = await browserFetch('/api/user/profile', {
  method: 'POST',
  body: JSON.stringify({ id: 123 }),
  headers: { 'Content-Type': 'application/json' },
});

// Automatically includes cookies and auth headers from the active page session
console.log(profileData);

```

## When to Use Each Method

**Use `serverFetch`** when:
- The target endpoint requires a specific browser-like User-Agent that differs from the automation browser
- You need to fetch resources outside the current page's origin without triggering CORS policies
- The request must complete even if the browser page crashes or navigates

**Use `browserFetch`** when:
- The API endpoint requires cookies or session tokens set by previous page interactions
- You need to interact with relative URLs (e.g., `/api/endpoint` vs `https://domain.com/api/endpoint`)
- The server implements anti-automation measures that detect requests originating outside the browser context

## Summary

- **`serverFetch`** executes in the Node.js runtime, forces a Mozilla User-Agent, requires absolute URLs, and uses `globalThis.fetch` with `AbortSignal.timeout`.
- **`browserFetch`** executes inside the active browser page via CDP evaluation, inherits the page's User-Agent and cookies, supports relative URLs, and uses `AbortController` within the page context.
- Both functions return response bodies as plain text and throw on non-OK HTTP statuses.
- Source implementations reside in [`src/http.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/http.ts) (lines 11-27 for `serverFetch`, lines 35-52 for `browserFetch`), with `browserFetch` relying on [`src/cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/cdp-eval.ts) for script injection.

## Frequently Asked Questions

### Can browserFetch access cookies from the current page?

Yes. Because `browserFetch` executes inside the active browser page via the Chrome DevTools Protocol, it automatically includes all cookies, session storage, and authentication headers associated with the page's current domain. This makes it ideal for authenticated API calls that rely on browser-established sessions.

### Does serverFetch support relative URLs?

No. `serverFetch` operates in the Node.js runtime outside the browser context and therefore lacks a base URL for resolution. It requires fully qualified absolute URLs (e.g., `https://example.com/path`). Attempting to pass a relative URL will result in a resolution error.

### What timeout mechanism does each method use?

`serverFetch` utilizes Node.js's `AbortSignal.timeout` to cancel requests that exceed the specified duration. `browserFetch` instantiates an `AbortController` inside the evaluated browser script and passes its signal to the page's native `fetch` call, achieving identical timeout behavior but through the browser's API surface.

### How does error handling differ between the two methods?

Both methods follow the same error pattern: they check `response.ok` and throw a custom error containing the HTTP method and status code if the response indicates failure. However, `browserFetch` must serialize errors across the CDP boundary from the browser context back to the Node.js harness, while `serverFetch` throws immediately within the host process.