# How Ego Lite's HTTP Fetch Façade Distinguishes Server vs Browser Origin Requests

> Learn how Ego Lite's HTTP fetch facade distinguishes server vs browser origin requests using explicit wrapper functions for Node.js and in-page execution.

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

---

**Ego Lite uses two explicit wrapper functions—`serverFetch` for Node.js agent-side requests and `browserFetch` for in-page execution—to separate server-origin from browser-origin HTTP traffic.**

The **ego-browser** package provides a thin abstraction over native `fetch` that lets automation scripts choose exactly where each request originates. Rather than auto-detecting the environment, callers invoke the appropriate helper to control origin semantics, cookie inheritance, and request headers.

## The Core Distinction: Two Wrappers, Two Execution Contexts

Ego Lite's HTTP fetch façade exports separate functions that target fundamentally different runtime environments:

| Wrapper | Execution Context | Origin Behavior |
|---------|-------------------|---------------|
| `serverFetch` | Node.js agent process | Request sent from server; custom `User-Agent` injected |
| `browserFetch` | JavaScript context of the controlled page | Request inherits page origin, cookies, and browser state |

This explicit design appears in [`package/ego-browser/src/http.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/http.ts), where both implementations are defined side-by-side with distinct strategies for initiating network calls.

## Server-Origin Requests with `serverFetch`

The **server-origin fetch** runs directly in the Node.js process hosting the ego-browser SDK. It delegates to `globalThis.fetch` provided by the runtime, then layers on automation-friendly defaults.

Per the source in [`http.ts`](https://github.com/citrolabs/ego-lite/blob/main/http.ts) at lines 11-27, `serverFetch` performs the following:

1. Verifies `globalThis.fetch` exists
2. Merges supplied options with a default `"Mozilla/5.0"` **User-Agent** header
3. Applies an `AbortSignal.timeout` for request cancellation
4. Throws on non-`ok` responses with HTTP status details

```typescript
// Server-origin request (agent-side execution)
import { serverFetch } from "ego-browser";

const response = await serverFetch("https://api.example.com/data", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ query: "info" }),
});
// Request originates from Node.js; User-Agent header is injected automatically

```

The `User-Agent` spoofing helps requests blend with browser traffic, but the TCP connection still emanates from the server environment—critical for IP-based rate limiting or geographic routing scenarios.

## Browser-Origin Requests with `browserFetch`

The **browser-origin fetch** executes inside the actual web page through Chrome DevTools Protocol (CDP) evaluation. This approach preserves full browser fidelity for requests that must match user-session state.

According to [`http.ts`](https://github.com/citrolabs/ego-lite/blob/main/http.ts) at lines 35-52, `browserFetch` works by:

1. Serializing URL, options, and timeout into a JSON payload
2. Injecting an async IIFE via the `evaluate` helper into the page context
3. Creating an `AbortController` inside the page's JavaScript environment
4. Calling the page's native `fetch` with resolved relative URLs
5. Returning response text or propagating errors to the caller

```typescript
// Browser-origin request (in-page execution)
import { browserFetch } from "ego-browser";

const data = await browserFetch("/api/user/profile", {
  headers: { Accept: "application/json" },
});
// Request executes inside the page; cookies and origin headers match the loaded site

```

Because the `fetch` call runs in the page's execution context, relative URLs resolve against the page's URL, and **all browser state**—cookies, `localStorage`, service workers, and CSP policies—applies naturally.

## How the Façade Exposes Both Helpers

The dual-fetch architecture is surfaced to automation scripts through explicit exports. In [`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts), both `serverFetch` and `browserFetch` are listed among **legacy global helpers**, making them available without explicit imports in certain agent configurations.

The re-export chain traces through:

- [`http.ts`](https://github.com/citrolabs/ego-lite/blob/main/http.ts) — core implementations
- [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts) — re-exports for global exposure
- [`index.ts`](https://github.com/citrolabs/ego-lite/blob/main/index.ts) — registration with the legacy helper system

No automatic environment detection occurs. The distinction between server and browser origin is made **exclusively by which function the caller invokes**.

## When to Use Each Fetch Variant

Choose `serverFetch` when you need:

- **Direct server-to-API communication** bypassing page constraints
- **Custom header injection** not permitted by page CSP
- **Stable network conditions** independent of page load state
- **IP-level control** for request routing

Choose `browserFetch` when you need:

- **Authenticated session continuity** using page cookies
- **Same-origin policy compliance** for protected APIs
- **Relative URL resolution** against the current page
- **Browser fingerprint consistency** with user traffic

## Summary

- Ego Lite's HTTP fetch façade provides **explicit opt-in wrappers** rather than automatic environment detection
- `serverFetch` in [`http.ts`](https://github.com/citrolabs/ego-lite/blob/main/http.ts) calls `globalThis.fetch` from Node.js with injected User-Agent headers
- `browserFetch` uses CDP `evaluate` to run `fetch` inside the page's JavaScript context
- Both functions are exported globally via [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts) and [`index.ts`](https://github.com/citrolabs/ego-lite/blob/main/index.ts) for agent script access
- Origin semantics, cookie behavior, and header inheritance differ based on which wrapper you call

## Frequently Asked Questions

### Does Ego Lite automatically detect whether to use server or browser fetch?

No. The library requires **explicit selection** through `serverFetch` or `browserFetch` function calls. There is no runtime environment sniffing or automatic context switching. This design gives automation scripts predictable control over request origin semantics.

### Can `browserFetch` bypass Content Security Policy restrictions?

No. Because `browserFetch` executes inside the page's JavaScript context, it is **subject to all page-level policies** including CSP, CORS, and mixed-content restrictions. Use `serverFetch` for requests that require headers or destinations blocked by the page's security policy.

### Why does `serverFetch` inject a Mozilla User-Agent header?

The `User-Agent` spoofing in `serverFetch` helps requests **appear browser-originated** to remote servers that filter or modify responses based on client identification. However, the TCP connection still originates from the Node.js process, so IP-based detection methods will identify it as server traffic.

### How does timeout handling differ between the two fetch wrappers?

Both wrappers use **`AbortSignal.timeout`** for cancellation, but the signal is created in different environments. In `serverFetch`, the timeout signal is generated in Node.js; in `browserFetch`, an `AbortController` is instantiated inside the page's context and configured with the same timeout value passed from the agent.