Enrichment (Geo, Device, IP)
Adds context an event didn't arrive with — location, device details, and network information — before it's stored.
High-Level Design
Enrichment adds consistent context so no downstream team reimplements it.
💼 Business Context
- "Users in Mumbai on iOS" style personalization and analytics constantly need geo/device context that raw events rarely include on their own
- Doing enrichment once, centrally, means every downstream team gets consistent geo/device fields instead of reimplementing their own lookup
- Owned by Platform Engineering
🔌 Technical Overview
Enrichment runs as a .NET Core middleware step in the Ingestion API pipeline: IP address resolves to geo (country/city) via a MaxMind-style lookup service cached in Azure Cache for Redis; device/browser fields are parsed from the User-Agent header (client-supplied device fields on mobile are trusted directly); and the raw IP is then discarded rather than persisted, keeping the stored event privacy-minimized while still geo-enriched.
Fields Added
💾 Enriched Context Block
"context": {
"geo": { "country": "IN", "city": "Pune" },
"device": { "type": "mobile", "os": "iOS 18", "browser": null }
}
🔗 Integration Points
- Azure Cache for Redis — cached IP-to-geo lookup table for low-latency enrichment
- .NET Core Ingestion API middleware — enrichment runs inline before publishing to Event Hubs
- User-Agent parsing library — device/browser classification
- Identity & Profile Service — enriched geo/device fields feed the unified profile's device graph
🧰 Services Consumed
- Owning microservice —
Cxos.Ingestion.Application(see the Full Application Service Map) - Database — Azure Cache for Redis (cache only, no system-of-record database)
⚠️ Non-Functional Considerations
- Scale: enrichment lookups are cache-backed to keep per-event latency low even at high throughput
- Latency: adds low-single-digit milliseconds via the Redis cache; a cache miss falls back to a slower lookup without blocking the request
- Reliability: enrichment failures never block ingestion — an event proceeds with partial context rather than being rejected
- Security/Privacy: raw IP addresses are discarded immediately after geo resolution — only the derived country/city is persisted
🎯 Enterprise Example
A retailer's Analytics API can answer 'which cities are driving mobile conversion this week' without any team having written custom geo-lookup code — every event already arrived enriched, consistently, from day one.