Scenario E: Product and clickstream events¶
Part of Streaming Transformations › Scenarios.
Goal¶
Product analytics needs every event linked to the account’s tier and region, with bot and internal traffic removed, and event counts per tier and region that stay current.
Transformations used¶
- Stream filtering on stream and dimension columns: drop bot traffic, and exclude internal and test accounts.
- Stream enrichment: map the user to the account’s tier and region. The dimension source can be a dynamic table.
- Custom scalar logic: JavaScript UDFs parse the user agent into a device and the URL into a campaign.
- Insert-triggered materialized views: maintain event counts per tier and region.
Source data¶
Stream¶
The example uses these seven click events:
Dimension table¶
The PIPE joins the following dimension table, refreshed periodically:
Target table¶
The PIPE lands transformed and filtered click events in this target table:
Transformation¶
The PIPE lands click events in the target table. Accounts are mapped to their tier and region. JavaScript UDFs parse the user agent into a device and the URL into a campaign. Bot traffic and events from internal and test accounts are dropped by filtering on stream and dimension columns. Event counts per tier and region are computed synchronously via an insert-triggered materialized view.
Result¶
Target table¶
Querying the target table returns these rows:
| EVENT_TS | ACCOUNT_ID | EVENT_NAME | PAGE_URL | DEVICE | CAMPAIGN | TIER | REGION |
|---|---|---|---|---|---|---|---|
| 2026-10-09 09:15:00 | acc-100 | page_view | https://example.com/pricing?utm_campaign=fall_launch | desktop | fall_launch | enterprise | emea |
| 2026-10-09 09:15:04 | acc-200 | click | https://example.com/signup | mobile | NULL | standard | amer |
| 2026-10-09 09:15:09 | acc-300 | page_view | https://example.com/docs?utm_campaign=newsletter&ref=mail | mobile | newsletter | standard | apac |
| 2026-10-09 09:15:12 | acc-100 | click | https://example.com/checkout | desktop | NULL | enterprise | emea |
The Googlebot event is dropped as bot traffic, and the events from the internal account acc-900 and the test account acc-950 are dropped by the dimension filters. The acc-200 and second acc-100 events have no utm_campaign parameter, so their campaign is NULL.
Insert-triggered materialized views¶
The PIPE keeps the view synchronously up to date as it lands rows. Querying click_events_by_tier_region returns the number of landed events per tier and region:
| TIER | REGION | EVENT_COUNT |
|---|---|---|
| enterprise | emea | 2 |
| standard | amer | 1 |
| standard | apac | 1 |
The two acc-100 events land in the same tier and region, so they’re counted in one row.
Considerations¶
- Dimension data is a snapshot that refreshes periodically, so updates can take several minutes to appear. This works well for slow-moving reference data. Dynamic tables can be used as dimension tables.
- In a JavaScript UDF, argument names are uppercase inside the function body.
- Keep UDFs fast. A slow UDF reduces throughput and increases latency.
- Create the materialized views before the pipe. Rows ingested before a view exists aren’t backfilled into it.
See also¶
See Stream filtering, Stream enrichment, Custom scalar logic, and Insert-triggered materialized views for more information on the transformations used in this scenario.
Previous: Scenario D: Security events · Next: Scenario F: Privacy-safe ingestion