Instrumenting a product for 10M merchants
Event design that survives its first million users.
ON THIS PAGE
Analytics debt is the quietest kind. Nothing breaks; you simply cannot answer questions about your own product, and by the time you notice, the events you needed were never written.
Events are a schema, not a log
Teams treat events as free-form logging and then discover that six services emit the same event with four different property names. A schema reviewed like an API contract costs an afternoon and saves a quarter.
{
"event": "listing_published",
"actor": {"type": "merchant", "id": "m_18422"},
"surface": "web|app|api",
"listing": {"id": "l_99", "category_id": 412},
"emitted_at": "2025-11-04T09:12:33Z"
}Name the actor
At ten million merchants, half of your interesting questions are about who acted — the merchant, their staff account, an integration, or your own support team. An event without an actor type cannot answer any of them, and retrofitting one is a migration across every producer.
- Actor type on every event, always
- Surface on every event — web, app, API
- Server-side emission for anything financial
- One owner per event, named in the schema
None of this is sophisticated. It is a contract, agreed before the first line of tracking code, and it is the difference between a data set you can ask questions of and one you can only apologise for.