Engineering notes for embedded analytics
What we shipped, what broke, what we learned. Long-form technical writing on ClickHouse query planning, tenant isolation, embed session security, and the un-photogenic side of running a self-hosted analytics product your customers see.
- ·7 min read
How tenant-scoped embeds prevent customer data leaks
The whole appeal of embedded analytics is that your customer's customers see only their own data. The only way that holds up is if the tenant id is server-signed and the database query refuses to widen it. Here is what that looks like in Emban.
securityembedgoRead - ·8 min read
ClickHouse rollups for customer-facing dashboards: raw, hourly, daily
A customer-facing dashboard that takes 4 seconds to load is a churn signal. The fix is rollups — but the planner that picks between raw, hourly, and daily tables is where the real engineering lives. Here is how Emban's planner decides, and what we deliberately keep on raw events.
clickhouseperformancegoRead - ·5 min read
Why customer analytics shouldn't be priced per viewer
Per-viewer pricing made sense for internal BI in 2010. For analytics that you embed inside your product and resell, it scales the wrong direction — your bill grows with your customer's success. Here's the math, and what to look for instead.
pricingembedsaasRead - ·5 min read
Building a query result cache that doesn't poison itself
An in-memory query cache cut our dashboard fanout latency 7x — and shipped a subtle bug that survived two passes of review. Here's the bug, the fix, and why returning a pointer from a cache is almost always wrong.
goclickhousecachingRead - ·4 min read
Don't fall back to demo_workspace silently: a small tale of a feature flag
Our backend silently fell back to a tenant called demo_workspace whenever the request didn't specify one. It also ran a synthetic event generator on every server start. Both were fine for the public demo and quietly broken for self-hosted installs. Here's the flag we should have shipped on day one.
goconfigRead - ·5 min read
Why your Paddle webhook handler should accept 5-minute skew, not 5 seconds
Our webhook signature verification used a 5-second replay window. Paddle's retry behavior alone could miss it. Here's the bug, the test that catches it, and why the security trade-off goes the other way than you'd guess.
securitybillinggoRead