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.
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
npm install @walkeros/server-source-fetchThe 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
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.
Configuration
This source uses the standard source config wrapper (consent, data, env, id, ...). For the shared fields see source configuration. Package-specific fields live under config.settings and are listed below.
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
This package does not define custom rule-level settings. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.
Examples
Batch POST
A fetch POST with a batch array produces one walker elb event per batched item preserving order.
{
"method": "POST",
"url": "http://localhost/collect",
"body": {
"batch": [
{
"name": "page view",
"data": {
"title": "Home"
}
},
{
"name": "button click",
"data": {
"id": "cta"
}
}
]
}
}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.
{
"method": "GET",
"url": "http://localhost/collect?e=page+view&d=%7B%22title%22%3A%22Home%22%7D"
}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.
{
"method": "POST",
"url": "http://localhost/collect",
"body": {
"name": "page view",
"data": {
"title": "Docs",
"url": "https://example.com/docs"
}
}
}elb({
"name": "page view",
"data": {
"title": "Docs",
"url": "https://example.com/docs"
}
})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
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
This source builds the shared request scope, 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 |
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
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
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' } },
],
}),
});