Architecture
This page is the map. It shows how the parts of Qinto connect, so that the pages on the ID graph, implementation and apps have a place to sit. It does not tell you how to set anything up. Start with Getting started for that.
Qinto runs on Cloudflare’s network. Every piece below is a Cloudflare Worker, a Durable Object or a storage product in a Cloudflare account, and the account is either one Blotout manages or your own.
One bubble per customer
Section titled “One bubble per customer”Most SaaS products are one big service. Every customer’s traffic lands on the same hostname, the same servers read it, and one database holds every customer’s visitors in one table with a customer id on each row. The customer trusts the vendor’s code to keep the rows apart.
Qinto does the opposite. Each site gets its own bubble of resources, and nothing in that bubble is shared with another customer.
Inside, every bubble has the same shape.
- A first-party hostname. The site runs on a subdomain of your own domain, such as
jiezrq.example.com. The tag loads from it, the browser opens its WebSocket to it, and your servers call its HTTP API. The visitor cookie is set on your domain, so the browser treats Qinto as part of your site and not as a third party. - Its own process. One Worker serves your hostname and nothing else. It holds your site’s settings and the list of your apps, and it runs no other customer’s code.
- Its own ID graph. Every visitor profile and every person profile is a Durable Object with its own storage, and every object belongs to one site. There is no shared table to query across customers, because there is no shared table. Sites of one team can share a graph through a storage link, and that is the only way two sites ever see the same person.
- Its own apps, with their own storage. Each app you install runs as its own process inside your bubble and keeps its data in resources that belong to that app on that site. The next two sections cover this.
The bubble has two possible homes. With managed hosting, Blotout creates it in a Cloudflare account Blotout runs, and you need no Cloudflare account of your own. With self-hosting, you connect your own Cloudflare account and a zone in it, and the Blotout platform creates the same bubble there. Your traffic, your visitors’ data and your apps’ storage then live in an account you own and pay for. The Blotout platform deploys and configures the bubble there, and it reads from it when you use the platform, for example to show a profile under User data or a chart under Analytics. The site behaves the same in both, and every page in these docs applies to both. Hosting explains how to choose.
Apps are blocks
Section titled “Apps are blocks”Everything a site does beyond collecting events is an app. Sending a purchase to Meta is an app. Masking personal data before it is stored is an app. A nightly job that syncs profiles to a CRM is an app. A tool your AI agent calls to look up a customer is an app.
An app describes itself in a manifest: which events it wants, which fields of the visitor it may read, which variables an install needs, which query parameters and cookies it captures from the page, which resources it owns, and which of its functions run as transforms, destinations, endpoints, scheduled jobs, UI or agent tools. When you install the app, the platform reads the manifest and wires the app into your bubble.
A block declares what it does in its manifest. The site reads the manifest at install and wires the block in: the events it wants, the fields it may read, the captures it needs, its consent category, and its browser code, UI, schedules and tools.
- The site process starts sending it the events it asked for, with the person behind each one already resolved by the ID graph.
- The tag starts capturing the click ids and campaign parameters the app declared, and stores them on the visitor profile for the app to read later.
- The consent gate starts applying the app’s category, so a destination app receives no event from a visitor who
refused it. A transform app is the exception: it runs whether or not the visitor consented, because its job, such as
masking, must happen before anything is stored. Two things still skip a transform: Global Privacy Control, which turns
off transforms in the
marketingandsalesOfDatacategories for that browser, and an install’s geo filter, which turns the install off for visitors outside the regions you chose. Keep a masking app unfiltered and in a category Global Privacy Control does not cover if it must run for everyone. - Its browser code, if it has any, becomes part of the one
q.jsbundle your pages already load. - Its UI, endpoints, schedules and tools appear in the Blotout platform, on your hostname and to your agent.
You change no tracking code to add or remove an app. The site sends each event once, and the set of installed apps decides where it goes. An app can be installed more than once on one site, for example one Facebook install per pixel, and each install has its own label and variables while all installs share one process.
Apps also compose. A transform app runs before a destination app sees the event, so a masking app and a Facebook app work together with no knowledge of each other. An app can emit an event of its own, which goes through the same pipeline and reaches the other apps. And an app can call another app directly when both declare the contract and you approve the grant. The app store has blocks for the tools most businesses run, and when the block you need does not exist, you build it with the same manifest and the same SDK.
Each app is isolated
Section titled “Each app is isolated”An app is third-party code running next to your visitors’ data, so the platform treats it the way an operating system treats a program. It gets its own process, its own resources and a narrow channel to the rest of the bubble.
Its own process. Every app on a site is a separate Worker. A bug or a slow request in one app cannot read another app’s memory, hold up another app or crash the site process. Each app has a time budget per event. A transform that runs past its budget fails the event closed, so a broken transform can never let unmasked data through. A destination that runs past its budget is dropped for that event, and the other apps and the browser never notice.
Its own resources. An app declares the storage it needs in its manifest, and the platform creates it per app and per site when the app is installed. The kinds are a KV store, a D1 database, an R2 bucket, Durable Objects, Workflows, an analytics dataset, a vector index, a Hyperdrive connection, a pipeline, browser rendering and a worker loader. The Facebook app on your site cannot open the Klaviyo app’s database, and the Facebook app on another customer’s site has its own database with nothing of yours in it. Uninstalling the app deletes its resources after a short grace period. See Resources.
Its own secrets. The variables and secrets an install needs, such as a pixel id and an access token, are stored in the Blotout platform’s vault and injected into that app’s process alone. The site process never holds them, and no other app can read them.
Its own context. What an app learns about a visitor beyond identity goes into a context with two levels. The private level only that app can read. The shared level every app on the site can read, and an app pushes to it only when its manifest asks for the shared context capability. Each entry is attributed to the app that wrote it, nothing moves from private to shared on its own, and an app’s shared entry disappears when the app leaves the site or loses the visitor’s consent. See Context.
A narrow channel. An app never touches the ID graph’s storage. For each event, the site process hands it an envelope with the event, the fields of the person its manifest declared, the visitor’s consent and the captures it asked for. Fields it did not declare are not in the envelope. When an app looks a person up on its own, through the SDK’s identity and facts reads, the request goes through the site process, which checks the same declared capabilities before it answers. What the app returns is also bounded: it can emit a limited number of events and push a limited number of changes to the visitor’s profile, and the platform validates each one before applying it. An app reaches another app only through a contract both declared and you approved.
A kill switch. Every app and every install has an enabled switch in the Blotout platform. Turning an app off makes the platform redeploy your site without the app, and the app stops receiving events as soon as that deployment lands. You deploy nothing yourself and change nothing on your pages.
The result is that the security of your bubble does not depend on the care of every app developer. It depends on the walls between the processes, and those are the platform’s.
How an event flows
Section titled “How an event flows”The diagram follows one purchase from a visitor’s browser to Meta through the Facebook app. Every other destination app follows the same path.
From the browser to the app.
- The visitor landed from a Meta ad a week ago. The tag saw the
fbclidin the URL, because the Facebook app’s manifest declares it, and stored it on the visitor profile with the time it was seen. Today the visitor pays. The page callstrack('Purchase', …)and the tag sends the event over the open WebSocket to your hostname. - The site process at
jiezrq.example.comreads the first-party cookie, finds the visitor’s id and hands the event to that visitor’s object in the ID graph. Nothing else runs here. - The visitor’s object runs the transform apps first, in install order. If a masking app is installed, this is where it edits the payload. Then the object saves the purchase on the person profile and sends the acknowledgement back to the browser. The page is done. Everything after this point runs in the background.
- The object works out which apps get this event: those that declared
Purchase, whose consent category the visitor allowed, and that have at least one active install. The Facebook app qualifies. It receives one envelope with the event, the person’s traits, the consent state and the storedfbclid, and only the fields its manifest declared.
From the app to the destination.
- Inside its own process the Facebook app hashes the email and phone, builds
fbcfrom the stored click id, and reads the pixel id and access token from the install’s variables. Then it sends one request per active install tograph.facebook.com, using the event id from step 1 so Meta deduplicates against anything the browser pixel sent. The request leaves from the app’s process directly. The site process and the ID graph never talk to Meta. - The app records the result. Analytics in the Blotout platform shows the event per app, and a rejected request appears under the app’s errors with Meta’s response, so you debug a destination without reading its code.
The same shape holds for a server call. A webhook that posts a refund to /v1/track with an edge token enters at step
2 instead of step 1, names the person by an identifier instead of a cookie, and continues through the same graph, the
same apps and the same destinations.