Enrichment Templates
Enrichment templates automatically transform and enhance your data during ingestion. Instead of defining custom fields, you specify a template and we handle the schema, parsing, and enrichment.
Available Templates
| Template | Use Case | Auto-Added Fields |
|---|---|---|
clickstream | Web analytics, user tracking | Session, device, geo, domain classification |
transaction | Payment/purchase data | MCC, fees, region |
Clickstream Template
Optimized for web analytics, product analytics, and user behavior tracking.
Features
| Feature | Description |
|---|---|
| Session tracking | SHA-1 deterministic session IDs per user, 30-min gap = new session |
| Duration computation | Time-to-next-event per user (capped at 30 min) |
| Anti-bot detection | Flags users with >50 hits/min for 4+ consecutive minutes |
| Stealth blocking | Flagged users silently accepted but data dropped (200 OK) |
| Domain enrichment | Batch lookup for domain categories |
| Geo/Device | IP, country, city, region, zip, ISP, ASN, colo, UA parsing |
Create Stream
curl -X POST https://enrich.sh/streams \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"stream_id": "clicks",
"template": "clickstream"
}'Input Fields (Your Data)
| Field | Type | Description |
|---|---|---|
u | string | Page URL |
r | string | Referrer URL |
t | int64 | Client timestamp |
b | string | Page title |
d | string | Platform (web/ios/android) |
z | string | Timezone |
l | string | Language |
s | object | Screen size {w, h} |
sid | string | Source identifier (app name, SDK instance) |
uid | string | User ID |
Output Fields (Enriched)
After enrichment, your Parquet files contain:
| Category | Fields |
|---|---|
| Original | url, referrer, title, timestamp, timezone, language, screen_size, source_id, user_id |
| URL Parsing | domain, scheme, host |
| Geo | ip, country, city, region, zip, isp, asn, colo |
| Device | ua, os_name, browser_name, device_type |
| Session | session_id, session_start_ts, event_duration |
| Domain Data | domain_category, domain_subcategory, intent_type |
| Metadata | created_at |
Example
curl -X POST https://enrich.sh/ingest \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"stream_id": "clicks",
"data": [{
"u": "https://example.com/pricing",
"r": "https://google.com/search?q=example",
"t": 1738776000,
"b": "Pricing - Example",
"d": "web",
"uid": "user_123"
}]
}'Query Enriched Data
SELECT
session_id,
domain,
browser_name,
country,
COUNT(*) as page_views
FROM read_parquet('s3://bucket/customer/clicks/2026/02/05/**/*.parquet')
GROUP BY 1, 2, 3, 4
ORDER BY page_views DESC;Multiple Sources → Same Stream
Send data from multiple apps or SDKs into the same clickstream stream. Each source sends its own sid, and individual users are identified by uid:
# Web app
curl -X POST https://enrich.sh/ingest \
-H "Authorization: Bearer sk_live_your_key" \
-d '{"stream_id": "clicks", "data": [{"u": "...", "sid": "web_app", "uid": "user_a"}]}'
# Mobile app (same stream, different source)
curl -X POST https://enrich.sh/ingest \
-H "Authorization: Bearer sk_live_your_key" \
-d '{"stream_id": "clicks", "data": [{"u": "...", "sid": "ios_app", "uid": "user_b"}]}'Filter by sid when querying:
SELECT * FROM read_parquet('s3://.../**/*.parquet')
WHERE source_id = 'web_app';Anti-Bot Detection
Built-in anti-bot detection:
- Rate tracking — counts events per user per minute
- Scoring — minutes with >50 hits flagged as suspicious
- Flagging — 4+ consecutive suspicious minutes → user flagged
- Stealth blocking — flagged user's future events return
200 OKbut are silently dropped - RAM-only — blocked IDs stored in DO RAM, reset on DO eviction
INFO
Anti-bot detection happens during flush (enrichment time), not during ingest. There may be a brief window where bot events are buffered before the user is flagged.
Session Tracking Details
| Parameter | Value |
|---|---|
| Session gap threshold | 30 minutes |
| Duration cap | 30 minutes per event |
| Session ID algorithm | SHA-1({user_id}-{session_start_ts}) |
| Session ID format | 40-char hex string |
| State scope | Per user, per stream |
Transaction Template
Optimized for payment processing, e-commerce, and financial data.
Create Stream
curl -X POST https://enrich.sh/streams \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"stream_id": "payments",
"template": "transaction"
}'Input Fields
| Field | Type | Description |
|---|---|---|
txn_id | string | Transaction ID |
txn_amount | string | Amount |
txn_currency | string | Currency code (EUR, USD) |
txn_region | string | Region (INTRA_EEA, etc.) |
entity_id | string | Your entity ID |
scheme_fees | object | Card scheme fee data |
Output Fields (Enriched)
| Category | Fields |
|---|---|
| Original | txn_id, txn_amount, txn_currency, txn_region, entity_id |
| Parsed | amount_cents, currency_code |
| Fees | scheme_fees_json, total_fees |
| Geo | ip, country, region |
| Metadata | created_at |
Example
curl -X POST https://enrich.sh/ingest \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"stream_id": "payments",
"data": [{
"txn_id": "txn_abc123",
"txn_amount": "99.99",
"txn_currency": "EUR",
"txn_region": "INTRA_EEA",
"entity_id": "merchant_xyz",
"scheme_fees": {
"visa": {"total_fee": "0.25", "currency": "EUR"}
}
}]
}'Choosing the Right Approach
| Approach | When to Use |
|---|---|
| Template | Standard use case (analytics, payments) |
| Custom Fields | Unique schema, no enrichment needed |
| None (Schemaless) | Quick testing, raw JSON storage |
Combining Template + Custom Fields
curl -X POST https://enrich.sh/streams \
-H "Authorization: Bearer sk_live_your_key" \
-d '{
"stream_id": "hybrid",
"template": "clickstream",
"fields": {
"custom_score": { "type": "float64" },
"experiment_id": { "type": "string" }
}
}'Template fields are applied first, then your custom fields are added.
