Skip to content

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

TemplateUse CaseAuto-Added Fields
clickstreamWeb analytics, user trackingSession, device, geo, domain classification
transactionPayment/purchase dataMCC, fees, region

Clickstream Template

Optimized for web analytics, product analytics, and user behavior tracking.

Features

FeatureDescription
Session trackingSHA-1 deterministic session IDs per user, 30-min gap = new session
Duration computationTime-to-next-event per user (capped at 30 min)
Anti-bot detectionFlags users with >50 hits/min for 4+ consecutive minutes
Stealth blockingFlagged users silently accepted but data dropped (200 OK)
Domain enrichmentBatch lookup for domain categories
Geo/DeviceIP, country, city, region, zip, ISP, ASN, colo, UA parsing

Create Stream

bash
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)

FieldTypeDescription
ustringPage URL
rstringReferrer URL
tint64Client timestamp
bstringPage title
dstringPlatform (web/ios/android)
zstringTimezone
lstringLanguage
sobjectScreen size {w, h}
sidstringSource identifier (app name, SDK instance)
uidstringUser ID

Output Fields (Enriched)

After enrichment, your Parquet files contain:

CategoryFields
Originalurl, referrer, title, timestamp, timezone, language, screen_size, source_id, user_id
URL Parsingdomain, scheme, host
Geoip, country, city, region, zip, isp, asn, colo
Deviceua, os_name, browser_name, device_type
Sessionsession_id, session_start_ts, event_duration
Domain Datadomain_category, domain_subcategory, intent_type
Metadatacreated_at

Example

bash
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

sql
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:

bash
# 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:

sql
SELECT * FROM read_parquet('s3://.../**/*.parquet')
WHERE source_id = 'web_app';

Anti-Bot Detection

Built-in anti-bot detection:

  1. Rate tracking — counts events per user per minute
  2. Scoring — minutes with >50 hits flagged as suspicious
  3. Flagging — 4+ consecutive suspicious minutes → user flagged
  4. Stealth blocking — flagged user's future events return 200 OK but are silently dropped
  5. 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

ParameterValue
Session gap threshold30 minutes
Duration cap30 minutes per event
Session ID algorithmSHA-1({user_id}-{session_start_ts})
Session ID format40-char hex string
State scopePer user, per stream

Transaction Template

Optimized for payment processing, e-commerce, and financial data.

Create Stream

bash
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

FieldTypeDescription
txn_idstringTransaction ID
txn_amountstringAmount
txn_currencystringCurrency code (EUR, USD)
txn_regionstringRegion (INTRA_EEA, etc.)
entity_idstringYour entity ID
scheme_feesobjectCard scheme fee data

Output Fields (Enriched)

CategoryFields
Originaltxn_id, txn_amount, txn_currency, txn_region, entity_id
Parsedamount_cents, currency_code
Feesscheme_fees_json, total_fees
Geoip, country, region
Metadatacreated_at

Example

bash
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

ApproachWhen to Use
TemplateStandard use case (analytics, payments)
Custom FieldsUnique schema, no enrichment needed
None (Schemaless)Quick testing, raw JSON storage

Combining Template + Custom Fields

bash
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.

Serverless data ingestion for developers.