Event Warehouse
Write collected events to your data warehouse for long-term storage and analysis.
Overview
When a forwarding rule targets a warehouse source (BigQuery, Snowflake, Databricks), events are batched, serialized, uploaded to staging, and bulk-loaded into per-event-type tables. Every event carries its originating source identity, consent state, and is partitioned on its event timestamp for efficient time-range queries.
Configuration
- Navigate to Streams > Forwarding
- Click Create Forwarding Rule
- Select the event source and choose a warehouse source as the target
- Configure the warehouse settings:
- Schema name (default:
signalsmith_events) — target dataset/schema - Custom table name (optional) — override the auto-derived table name
- Partition column (default:
timestamp) — column used for day-partitioning/clustering
- Schema name (default:
- Click Save
Table Naming
Zeotap creates one table per event type. The table name depends on whether the forwarding rule is scoped to a specific source and whether a custom table name is configured.
| Event Type | Source Prefix | Table Name |
|---|---|---|
track | none | tracks |
identify | none | identifies |
page | none | pages |
screen | none | screens |
group | none | groups |
track | ”Web App” | web_app_tracks |
identify | ”Mobile App” | mobile_app_identifies |
purchase (custom) | none | purchases |
app.install (custom) | none | app_installs |
Source prefixes are derived from the event source (write key) name: lowercased, non-alphanumeric characters replaced with underscores, and truncated to a safe length. Custom event types are pluralized idempotently (names already ending in s are left alone).
To override the auto-naming, set Custom Table Name on the forwarding rule. This is useful when downstream consumers expect a specific table name.
Table Schema
Every event table has the same columns regardless of warehouse dialect:
| Column | Type | Description |
|---|---|---|
id | string | Message ID (unique per event) |
workspace_id | string | Workspace identifier |
write_key_id | string | Which event source sent this event |
write_key_name | string | Human-readable source name for quick inspection |
user_id | string | Identified user ID |
anonymous_id | string | Anonymous user ID |
event | string | Event name (for track) |
properties | JSON / VARIANT | Event properties |
traits | JSON / VARIANT | User traits (for identify) |
context | JSON / VARIANT | Event context (page, device, campaign, etc.) |
timestamp | timestamp | When the event occurred (client-provided) |
received_at | timestamp | When Zeotap received the event |
sent_at | timestamp | When the client sent the event |
group_id | string | Group ID (for group events) |
name | string | Page/screen name |
category | string | Page/screen category |
server_ip | string | Client IP address |
consent_string | string | IAB TCF v2 consent string |
us_privacy | string | IAB CCPA US Privacy string (e.g., 1YNN) |
consent_categories | JSON / VARIANT | Granted consent categories as a JSON object |
Partitioning and Clustering
New event tables are partitioned (or clustered, depending on the warehouse) on the timestamp column so time-range queries scan only the relevant partitions:
| Warehouse | Strategy |
|---|---|
| BigQuery | Day-partitioned on timestamp via TimePartitioning |
| Snowflake | CLUSTER BY (timestamp) after table creation |
| Databricks | CLUSTER BY (timestamp) on Delta tables |
You can override the partition/clustering column per forwarding rule by setting Partition Column in the rule config. This is useful when you have a custom event timestamp field that better reflects your query patterns.
Note: BigQuery cannot retroactively partition existing tables. If you need to change the partition column or enable partitioning on a pre-existing table, you must drop and recreate it.
Consent Persistence
Every event row carries structured consent context extracted from context.consent:
consent_string— IAB TCF v2 consent string or your own consent stringus_privacy— IAB CCPA US Privacy stringconsent_categories— JSON object of granted categories (e.g.,{"analytics": true, "marketing": false})
This lets you query consent-aware cohorts directly in SQL:
-- Count users who opted out of marketing
SELECT COUNT(DISTINCT user_id)
FROM web_app_tracks
WHERE JSON_EXTRACT(consent_categories, '$.marketing') = false
AND timestamp >= '2026-01-01';Schema Evolution
- The column list is fixed — new event properties are stored inside the
propertiesJSON column - Query JSON columns using your warehouse’s JSON functions (
JSON_EXTRACT,->,::variant) - Custom event types automatically get their own table on first event arrival
API Reference
See Events API for warehouse configuration endpoints.
Next Steps
- Event forwarding — Configure routing rules
- Consent management — Set up consent categories
- Sending events — Include consent in event payloads