Tenant Isolation & Scope
Tenant isolation is the central contract of the CDP API. The CDP runs on one shared Unomi cluster across every brand, so isolation is enforced in software on every request, not by physical separation.
How scope is resolved
Section titled “How scope is resolved”When a read request arrives:
- The credential is resolved to an authenticated context (a
brand_id). - The brand’s shop domain is resolved from its connected Shopify integration (either the LiveRecover integration id or the CDP-app integration id).
- A scope-bound client is constructed for that shop domain, and the handler is invoked with only that client.
The scope is always the one resolved from your credential — never anything you can pass
in. A handler structurally cannot issue an unscoped read: the raw, unscoped client is never
reachable from request code. Every response echoes the resolved scope so you can confirm
which shop a read was bound to.
What isolation guarantees
Section titled “What isolation guarantees”- A key for shop A can never read shop B’s data. Every profile / event / session / segment read AND-injects the shop-scope predicate; cross-shop rows are never returned.
- Single-profile reads fail closed. Requesting a profile id that belongs to another
brand returns the same
404as a non-existent id — a brand cannot even probe for the existence of another brand’s ids. - Merged profiles only surface your data. A profile merged across shops only ever
surfaces this brand’s events and sessions; a merged master is labelled
merged, never silently presented as one confirmed human. - Segments cannot span brands. Segment membership cannot span shops (the scope predicate is AND-ed into every condition), and segments are visible only to the owning brand.
- Cursors are scope-bound. A deep-pagination cursor embeds the scope it was minted
under; presenting another brand’s cursor is rejected (
403) and never used to select a scope. See Pagination.
Ingest scope
Section titled “Ingest scope”The credential-free ingest proxy binds every payload scope to the requesting storefront
Origin: a script on storefront A cannot post events tagged with shop B’s scope. Every
tenancy-bearing scope in the payload must equal the shop bound to the request Origin, or
the request is rejected (403). See Ingest.