Skip to main content

Event pipelines

An event pipeline is a deterministic flow that receives an inbound event and does fixed work with it: a lead-form submission, a third-party webhook, or an in-app action arrives at the pipeline’s endpoint, gets normalized, and runs through an ordered list of actions — write the row to a dataset, send an email, call a connected integration, broadcast a live update, or return a custom response. Pipelines are how a page captures leads, and how Erdo enriches and routes them without an agent in the loop on every event. Each pipeline has:
  • a slug and name — a stable, human-readable handle (e.g. acme-leads-a1b2c3d4),
  • a stateactive, disabled, or proposed,
  • a source kindbrowser_form, third_party_webhook, custom_http, internal, …,
  • an inbound endpoint URL — where events are POSTed,
  • an auth mode — how inbound events are verified (HMAC, shared secret, provider signature, signed-in viewer, or public),
  • the actions it runs and the datasets it writes to, and
  • an execution log — every event it received, with status (accepted / rejected / failed), a payload preview, the response, and any error.

Where data lands

A pipeline’s dataset.write actions persist rows to a dataset — per-row, SQL-queryable storage. To see captured leads, query the dataset the pipeline writes to (shown as write_target_datasets), not the pipeline itself. The pipeline’s execution log tells you whether events are arriving and being accepted; the dataset holds the rows.

Emails a pipeline sends

A pipeline that emails on an event — a lead alert to your sales inbox, a confirmation back to the person who submitted the form — has Erdo compose the message. The pipeline supplies the content (a heading, the captured fields as label/value rows, a button through to the page the lead came from) and Erdo renders it in the standard Erdo styling, with a plain-text version alongside for clients that block HTML. Addresses and links in the fields become clickable, so a lead alert can be replied to from the notification itself.

Pipeline purpose

Every pipeline declares a purpose — its role — so you can tell capture flows apart from analytics infrastructure without guessing from names:
  • record_capture — a pipeline whose job is persisting submitted records to a dataset (it has at least one dataset.write action). This is how you find which datasets receive a flow’s records: filter pipelines by purpose = record_capture and read their write_target_datasets (each entry is a fully-qualified org-slug.dataset-slug). You can set this explicitly when creating or updating a pipeline; a custom pipeline that writes to a dataset is also promoted to record_capture automatically at save time.
  • page_events — the managed first-party page-analytics pipeline described below. Reserved for Erdo’s own provisioning; you can’t set it.
  • custom — everything else: a webhook or enrichment flow that doesn’t persist records.
To discover which dataset a campaign’s leads land in, list your record_capture pipelines and read their write_target_datasets, then query that dataset. Every dataset.write row is stamped at ingestion with columns your transform doesn’t set: variant, artifact_id, page_url (from the page envelope), plus a set of request signals that let you keep your metrics clean and segment them by who actually showed up:
  • is_test — a boolean, always present. true when the submission was tagged as test traffic (see Marking test traffic below), otherwise false. Filter it out to count real leads and conversions.
  • device_type"mobile", "tablet", "desktop", or empty, classified from the request’s User-Agent at ingestion. Segment funnels by it to compare mobile vs desktop (a page can take most of your spend yet convert zero mobile visitors — this column surfaces that without parsing User-Agents by hand).
  • browser — the coarse browser family ("chrome", "safari", "firefox", "edge", "samsung", "opera", "other", or empty), also from the User-Agent.
  • in_app — the in-app webview container the visit came from ("instagram", "facebook", "tiktok", and similar), or empty for a normal standalone browser. In-app webviews routinely break modals and payment flows, so this separates “converts badly on mobile” from “converts badly inside Instagram’s browser”.
  • language — the visitor’s preferred language, the primary tag of the Accept-Language header (e.g. "pt-BR"), or empty. Check that a Brazilian, Colombian, or French campaign is actually reaching PT/ES/FR speakers.
  • country, region, city — the visitor’s coarse location: ISO-2 country (e.g. "US"), ISO-3166-2 region code (e.g. "NY"), and city name, from the serving edge. Empty when the request reaches the pipeline through an ingress that carries no edge geo. Segment by them to verify geo-targeted campaigns (e.g. “New Yorkers relocating to Miami”) landed where you paid for.
These are stamped only where your transform left the column unset, so a page that maps its own column of the same name always wins. Each is epoch-bound — rows written before the column existed carry it blank, which means “no signal”, not a real value like desktop or zero visitors.

Marking test traffic

QA checks and automated evaluations submit to the same pipelines your real visitors do, so their rows would otherwise inflate lead and funnel counts. Tag a submission as test traffic and it lands with is_test = true, keeping it out of your real-traffic metrics. Two equivalent markers:
  • Send the request header X-Erdo-Test: 1 (1 or true), or
  • Include a top-level "is_test": true field in the JSON body.
The envelope’s marker always wins over the transform, so a transform can never clear a test mark. The marker is trusted as-is: mismarking real traffic as test only hides it from your own dashboards, so there’s no signature to manage. Auto-provisioned page-events datasets ship with a default filter that hides is_test = true rows, so their funnel counts exclude test traffic automatically; add the same is_test not_equals true default filter to your own lead datasets to get the same behaviour on reads.

Auto-provisioned page-events pipelines

Alongside the pipelines you or your agents create, every published page gets one page-events pipeline automatically (its purpose is page_events — see Pipeline purpose above). It receives the page’s first-party analytics events — pageviews, scroll milestones, section views, CTA clicks, form starts, leads, video plays — and writes them to your organization’s shared Page events dataset, stamped with the page, experiment variant, session, campaign attribution, is_test, device_type, browser, in_app, language, and geo (country/region/city). Events with names outside that fixed vocabulary are rejected, which you can see in the pipeline’s execution log. Disabling a page-events pipeline turns first-party analytics off for that page; Erdo won’t re-create it. See Pages → First-party page events for what’s captured and how to query it.

Inspecting your pipelines

You can list your pipelines, read one’s configuration, and review its run history over MCP, the REST API, or the CLI. Everything is org-scoped — a caller only ever sees their own organization’s pipelines — and pipelines are referenced by slug (a UUID is also accepted).

CLI

The CLI authenticates with your Erdo token and the active organization (erdo login, erdo org).

MCP tools

Identity and RBAC ride the request context, so a caller can only reach their own org’s pipelines.

REST

Base URL https://api.erdo.ai. Authenticate with Authorization: Bearer <token> and select the org with X-Organization-ID. These are read endpoints — pipelines are created and edited from the page that owns them. To confirm a pipeline is capturing events end-to-end, check its executions here, then query the dataset it writes to.