> Part of the walkerOS documentation. Project overview and full index: <https://www.walkeros.io/llms.txt>

<!-- -->

[Server](#)[ ](https://github.com/elbwalker/walkerOS/tree/main/packages/server/sources/fetch)

<!-- -->

[Source code](https://github.com/elbwalker/walkerOS/tree/main/packages/server/sources/fetch)[ ](https://www.npmjs.com/package/@walkeros/server-source-fetch)

<!-- -->

[Package](https://www.npmjs.com/package/@walkeros/server-source-fetch)

# Fetch

Web Standard Fetch API source for walkerOS. Platform-agnostic `(Request) => Response` signature that runs on Cloudflare Workers, Vercel Edge, Deno, Bun, and Node.js 18+. Supports batch processing, configurable CORS, and pixel tracking via a 1x1 transparent GIF for GET requests.

<!-- -->

Where this fits

The Fetch source is a **server source** in the walkerOS flow:

It receives events via the Fetch API and forwards them to your destinations. Works on any platform supporting Web Standards.

## Installation[​](#installation "Direct link to Installation")

```
npm install @walkeros/server-source-fetch
```

path setting renamed to paths

The `path` setting has been renamed to `paths` (array). The old `path` still works but is deprecated and will be removed in the next major version.

```
// Before (deprecated)

settings: { path: '/events' }



// After

settings: { paths: ['/events'] }
```

* Integrated
* Bundled

### Cloudflare Workers[​](#cloudflare-workers "Direct link to Cloudflare Workers")

```
import { sourceFetch } from '@walkeros/server-source-fetch';
import { startFlow } from '@walkeros/collector';

const { sources } = await startFlow({
  sources: {
    fetch: {
      code: sourceFetch,
      config: {
        settings: { paths: ['/collect'], cors: true },
      },
    },
  },
});

export default { fetch: sources.fetch.push };
```

Add to your `flow.json` sources:

```
"sources": {
  "fetch": {
    "package": "@walkeros/server-source-fetch",
    "config": {
      "settings": {
        "paths": ["/collect"],
        "cors": true
      }
    }
  }
}
```

Server sources require platform-specific handlers. For containerized deployments, see [Docker](https://www.walkeros.io/docs/apps/docker.md).

[See bundled mode setup](https://www.walkeros.io/docs/getting-started/modes/bundled.md) | [CLI reference](https://www.walkeros.io/docs/apps/cli.md)

## Configuration[​](#configuration "Direct link to Configuration")

This <!-- -->source<!-- --> uses the standard <!-- -->source<!-- --> config wrapper (consent, data, env, id, ...). For the shared fields see [source<!-- --> configuration](https://www.walkeros.io/docs/sources.md#configuration). Package-specific fields live under `config.settings` and are listed below.

## Settings[​](#settings "Direct link to Settings")

| Property         | Type                | Description                                                                                            | More |
| ---------------- | ------------------- | ------------------------------------------------------------------------------------------------------ | ---- |
| `path`           | `string`            | Deprecated: use paths instead                                                                          |      |
| `paths`          | `Array<any>`        | Route paths to handle. String shorthand accepts GET+POST. RouteConfig allows per-route method control. |      |
| `cors`           | `boolean \| object` | CORS configuration: false = disabled, true = allow all (default), object = custom                      |      |
| `maxRequestSize` | `integer`           | Maximum request body size in bytes                                                                     |      |
| `maxBatchSize`   | `integer`           | Maximum events per batch request                                                                       |      |

## Mapping[​](#mapping "Direct link to Mapping")

This package does not define custom rule-level settings. For the standard rule fields (consent, condition, data, batch, name, policy) see [mapping](https://www.walkeros.io/docs/mapping.md).

## Examples

### Batch POST

A fetch POST with a batch array produces one walker elb event per batched item preserving order.

Event

```
{
  "method": "POST",
  "url": "http://localhost/collect",
  "body": {
    "batch": [
      {
        "name": "page view",
        "data": {
          "title": "Home"
        }
      },
      {
        "name": "button click",
        "data": {
          "id": "cta"
        }
      }
    ]
  }
}
```

Out

```
elb({
  "name": "page view",
  "data": {
    "title": "Home"
  }
});

elb({
  "name": "button click",
  "data": {
    "id": "cta"
  }
})
```

### Pixel GET

A fetch GET with query parameters in the URL is parsed into an elb event payload for pixel-style tracking.

Event

```
{
  "method": "GET",
  "url": "http://localhost/collect?e=page+view&d=%7B%22title%22%3A%22Home%22%7D"
}
```

Out

```
elb({
  "e": "page view",
  "d": "{\"title\":\"Home\"}"
})
```

### POST event

A fetch POST request with a JSON body becomes a single walker elb event in a fetch-based server.

Event

```
{
  "method": "POST",
  "url": "http://localhost/collect",
  "body": {
    "name": "page view",
    "data": {
      "title": "Docs",
      "url": "https://example.com/docs"
    }
  }
}
```

Out

```
elb({
  "name": "page view",
  "data": {
    "title": "Docs",
    "url": "https://example.com/docs"
  }
})
```

## Responses[​](#responses "Direct link to Responses")

| Status | Meaning                                                                                                                                      |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| 200    | Event processed                                                                                                                              |
| 400    | Rejected client input: the pipeline declared the event invalid. The body echoes the validation message, for example `Event name is required` |
| 500    | The pipeline failed to process a valid event, or an unexpected server fault                                                                  |
| 207    | Batch request where some events succeeded and others failed. The body carries per-index errors                                               |

Invalid input is counted on `collector.status.sources.<id>.rejected` rather than inflating `status.failed`, and is logged at warn with the reason instead of as an error with a stack trace.

## Ingest metadata[​](#ingest-metadata "Direct link to Ingest metadata")

Extract request metadata and forward it through the pipeline.

`config.ingest` must use the `map` operator. Keys are output field names; values are direct field paths on the `Request` (no `req.` prefix), or `{ fn }` for header access via `.get()`. A bare object like `{ url: 'url' }` is silently inert: without the `map` operator the source passes the whole request through and no field is extracted.

```
const { sources } = await startFlow({
  sources: {
    fetch: {
      code: sourceFetch,
      config: {
        settings: { cors: true },
        ingest: {
          map: {
            ua: { key: 'headers.user-agent' },
            origin: { key: 'headers.origin' },
            path: { key: 'path' },
          },
        },
      },
    },
  },
});
```

### Available ingest paths[​](#available-ingest-paths "Direct link to Available ingest paths")

This source builds the shared [request scope](https://www.walkeros.io/docs/sources/scope.md), so every contract field resolves by key.

| Path             | Description                 |
| ---------------- | --------------------------- |
| `method`         | Uppercase HTTP method       |
| `url`            | Absolute request URL        |
| `path`           | Pathname, no query string   |
| `query.<name>`   | Query parameter             |
| `headers.<name>` | Header, lowercased name     |
| `body`           | Parsed request body         |
| `raw`            | The WHATWG `Request` itself |

note

`ip` is absent on this source: a Fetch `Request` reports no client IP and walkerOS does not guess one. Read `headers.x-forwarded-for` if your proxy sets it.

## Usage[​](#usage "Direct link to Usage")

### Single event[​](#single-event "Direct link to Single event")

```
fetch('https://your-endpoint.com/collect', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: 'page view',
    data: { title: 'Home', path: '/' },
  }),
});
```

### Batch events[​](#batch-events "Direct link to Batch events")

```
fetch('https://your-endpoint.com/collect', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    batch: [
      { name: 'page view', data: { title: 'Home' } },
      { name: 'button click', data: { id: 'cta' } },
    ],
  }),
});
```
