Add the SDK and Signals starts collecting.
Signals collects behavioral events from your web, mobile and server apps and checks each against its schema. There is no event stream to build first.
The same enriched row, in your cloud.
Real-time projects stall on the event pipeline.
Feature stores assume good events already exist. A DIY build starts with Kafka, a tracker, a schema registry and a team to run them. So responding to live behavior becomes a data-platform project, and the first use case waits on it.
Events arrive validated and attributes compute on them.
We host it, or it runs in your own AWS or GCP account. Signals collects events with its own SDKs, updates what it knows within a second of each event, and answers a read in 6ms at the median and 10ms at p95, in-region.
per event type. Checked on the way in, before anything computes on it.
to build or run before your first attribute
Add one SDK to your web, mobile or server app.
Page views, clicks and form activity are tracked automatically. Custom events are one tracking call with the fields you choose. Point your coding agent at the Snowplow MCP server and it creates your events, writes the tracking call and checks the first events arrive.
Each event is checked against its schema as it arrives.
A schema is the shape you expect an event to have. Events that do not match are set aside with the reason, so attributes compute only on events that pass.
The event is in the stream and in your warehouse.
Live attributes update in <1s from the event arriving. The same event is written to Snowflake, BigQuery or Databricks for history, so streaming and batch see one record.
- Snowflake
- BigQuery
- Databricks
- AWS
- Google Cloud
Collection built in, so the project starts at the attribute.
"type": "object", "properties": { "sku": { "type": "string" }, "price": { "type": "number" } }, "required": ["sku", "price"], "additionalProperties": false
Matches view_price 1-0-0. Enriched and passed on to attributes and the warehouse.
sku string, price numberKept in failed events, not dropped. It never reaches an attribute.
>Track when a price is shown on the product page.
I'll add a view_price event with sku and price, register it, and wire up the call.
snowplow · create_schema_version
vendor "com.acme" name "view_price" version "1-0-0" type "event"
✓ Valid. Deployed to dev: iglu:com.acme/
snowplow · create_event_specification
name "View Price" eventSource "iglu:com.acme/
✓ Created event specification View Price
Edit src/components/PriceTag.tsx +6
trackSelfDescribingEvent({
event: {
schema: 'iglu:com.acme/
data: { sku: product.sku, price: product.price },
},
});
snowplow · get_event_spec_metrics
✓ View Price: 14 events, last seen 12s ago
snowplow · get_failed_events_metrics
✓ 0 failed events for view_price 1-0-0
First events arrived: 14 view_price events from the product page, 0 failed.
- user_ipaddress
- 203.0.113.42
- useragent
- Mozilla/5.0 (iPhone; CPUiPhone OS 18_0 ...) Safari/604.1
- page_referrer
- https://www.google.com/
- page_url
- https://acme.shop/p/trl-2201?utm_source=google&utm_medium=cpc&utm_campaign=spring_trail
- geo_country
- "US"
- geo_region
- "CO"
- geo_city
- "Denver"
- deviceClass
- "Phone"
- agentName
- "Safari"
- refr_medium
- "search"
- refr_source
- "Google"
- mkt_source
- "google"
- mkt_medium
- "cpc"
- mkt_campaign
- "spring_trail"
- Web
- iOS
- Android
- Server
Receives events from every app
Recorded by the tracker with each event
Schemas checked, fields added
Computed and served to your apps and agents.
Every event loaded as a row.
You describe the shape of each event once. Anything that does not match is kept aside with the reason, so events from a broken release do not reach an attribute.
"type": "object", "properties": { "sku": { "type": "string" }, "price": { "type": "number" } }, "required": ["sku", "price"], "additionalProperties": false
Matches view_price 1-0-0. Enriched and passed on to attributes and the warehouse.
sku string, price numberKept in failed events, not dropped. It never reaches an attribute.
Define the events and fields your product needs. Add a field, version the schema, and old events keep their meaning. Design and instrument it from Claude Code or Cursor through the Snowplow MCP server.
>Track when a price is shown on the product page.
I'll add a view_price event with sku and price, register it, and wire up the call.
snowplow · create_schema_version
vendor "com.acme" name "view_price" version "1-0-0" type "event"
✓ Valid. Deployed to dev: iglu:com.acme/
snowplow · create_event_specification
name "View Price" eventSource "iglu:com.acme/
✓ Created event specification View Price
Edit src/components/PriceTag.tsx +6
trackSelfDescribingEvent({
event: {
schema: 'iglu:com.acme/
data: { sku: product.sku, price: product.price },
},
});
snowplow · get_event_spec_metrics
✓ View Price: 14 events, last seen 12s ago
snowplow · get_failed_events_metrics
✓ 0 failed events for view_price 1-0-0
First events arrived: 14 view_price events from the product page, 0 failed.
Device, geography, referrer and campaign fields are added to each event before it reaches an attribute, so you do not join them in later.
- user_ipaddress
- 203.0.113.42
- useragent
- Mozilla/5.0 (iPhone; CPUiPhone OS 18_0 ...) Safari/604.1
- page_referrer
- https://www.google.com/
- page_url
- https://acme.shop/p/trl-2201?utm_source=google&utm_medium=cpc&utm_campaign=spring_trail
- geo_country
- "US"
- geo_region
- "CO"
- geo_city
- "Denver"
- deviceClass
- "Phone"
- agentName
- "Safari"
- refr_medium
- "search"
- refr_source
- "Google"
- mkt_source
- "google"
- mkt_medium
- "cpc"
- mkt_campaign
- "spring_trail"
Consent is recorded with each event at the collection point, before anything is computed or served. In your own cloud, collection, validation and enrichment run inside your account.
- Web
- iOS
- Android
- Server
Receives events from every app
Recorded by the tracker with each event
Schemas checked, fields added
Computed and served to your apps and agents.
Every event loaded as a row.
Collect an event once, build on it four ways.
view_priceevent_id 7f3a91validatedenriched- Live attribute
7f3a91prices_viewed: 3The page reranks this visit.Real-time personalization - Trigger
7f3a91basket_idle firedYour app steps in before they leave.Act on live behavior - Agentic context
7f3a91"viewed TRL-2201 3 times"Your agent opens knowing the visit.Customer context for AI agents - Warehouse
7f3a91row in training_setYour model trains on what production reads.Real-time features for ML
Frequently asked questions.
We already collect events with another tool. Do we have to replace it?
No. Signals computes on events collected by the Snowplow SDKs, so you add one beside the tracker you run now, and that tool keeps working as it does. If you already run Snowplow, Signals reads the pipeline you have.
Do we need Kafka or an event stream of our own?
No. Collection is built into Signals. The SDK sends events to a collector that validates and enriches them, and attributes compute on the result, so there is no stream to build or run before your first attribute.
What happens to events that fail validation?
Each one is set aside with the reason it failed, such as a price sent as a string where the schema expects a number. Events that fail do not reach an attribute, so a broken release does not change what your app reads from Signals.
Can we keep using our warehouse?
Yes. Signals writes each validated event to Snowflake, BigQuery or Databricks with the same event_id the live attributes computed on, so analysis and model training read the records production used. Streaming-only deployments are supported if you do not want a warehouse.
Start collecting, then define one attribute.
Connect the Snowplow MCP server and let your coding agent do the instrumenting. Then define one attribute and watch it update as you use your own product. The free tier runs on the real engine: no card, no sales call.