Skip to main content

CDP clean rooms

A clean room lets two parties answer one question — how much of your audience is also ours?without either side ever seeing the other’s customer list. Orbit’s clean room is part of the CDP: it compares sets of hashed identifiers, returns only counts and rates, and withholds every number when the overlap is small enough to single out a person. The result is co-marketing-sized analytics — an overlap count, a match rate per side, a similarity score — with zero data egress: no customer rows move between you and your partner, and none are written to storage. This page covers the model and the day-to-day operation of it: what a clean room is on Orbit, how the Clean room tab on the CDP page works, what the match engine will and will not return, the operator workflow from first share to closing a collaboration, and how the consent you already record travels with the data into every match.

What a clean room is on Orbit

In Orbit’s CDP your first-party audience already resolves to profiles with identifiers (identity resolution) and groups into segments (CDP segments). A clean room is the sandboxed sharing surface on top of that audience: it lets you run a join against a partner’s audience — a retailer against a brand, a brand against a media publisher — and get an evaluation back, without revealing the underlying rows on either side. Three properties define the room:
  • Identifiers, never rows. The only thing compared is a set of SHA-256 digests of email and phone identifiers. Names, addresses, purchase histories, and profile traits never enter the match.
  • Aggregations only. The result of a match is counts and rates — the overlap size, each side’s match rate, a Jaccard similarity score — plus the intersection digests, which are digests you already hold (they came from your own list). There is no query shape that returns a partner’s rows.
  • k-anonymity. Below a minimum overlap threshold the whole quantitative result is suppressed, so a one-member probe can never confirm a single person’s membership in the partner’s audience.
The compute is stateless: the match runs in-request, the inputs are discarded when the response is sent, and the only persistence is a counts-only audit entry (overlap size and identifier counts — never an identifier or a digest). Nothing about the partner’s set is stored, and nothing about yours is either beyond what your CDP already holds.

The hashing contract both sides follow

A match only intersects when both sides hash identically, so the contract is fixed and public:
  • Email — normalized (trimmed, lowercased) exactly the way ad-audience exports normalize before hashing, then SHA-256. A digest you produce for an ad network and a digest a partner produces for a clean room line up.
  • Phone — canonicalized to E.164 with the leading +, then SHA-256. A partner hashing bare digits without the + simply never matches — a data-prep error on their side, never a privacy leak.
  • Server-side hashing — when you paste cleartext identifiers on your own side, the server normalizes and hashes them in memory. Cleartext never leaves the process, is never persisted, and is never logged. Your partner supplies pre-computed digests only — they never send cleartext at all, which is what makes the collaboration privacy-safe.

The Clean room tab

The surface lives at Integrations → CDP → Clean room. Everything it does is also available server-to-server on POST /api/v1/cdp/clean-room/match (owner, admin, or developer role with the contacts:read scope), so your CI or an agency partner’s tooling can drive the same match without a dashboard. The tab is a two-pane share configuration plus a result card:
  1. Your audience. Paste your identifiers — emails or phones, one per line (commas also work). A token containing @ is treated as an email, anything else as a phone. These are cleartext in the textarea only; the server hashes them and never stores them. The counter shows how many identifiers you have staged.
  2. Partner digests. Paste the SHA-256 digests your partner sent you, one per line. They are lowercased and deduplicated as you paste — this is canonicalization, not validation; anything that is not a 64-character hex digest is rejected (and counted as skipped) server-side.
  3. Minimum match threshold. The k-anonymity floor, default 50. When the overlap is below the threshold, every quantitative field in the result is withheld. You can raise it for stronger privacy; you cannot disable suppression — the effective threshold never drops below 1.
  4. Labels. Optional free-text annotations (Q3 loyalty list, Acme Media) that land on the audit entry so the collaboration is identifiable later.
Each side is capped at 50,000 identifiers per request — chunk larger lists into multiple matches. The result card reports what the share produced:
  • Meets threshold / below threshold, with a badge.
  • When the threshold is met: the overlap count, your match rate, the partner’s match rate, and the Jaccard similarity (|∩| / |∪|).
  • Per-side identifiers and skipped counts — records dropped before hashing because they failed normalization, carried an explicit opt-out, or were malformed digests. Skips are counted, never itemized.
  • When the threshold is met, the matched intersection digests are flagged as ready to activate — they are digests you already hold, so mapping them back to your own profiles reveals nothing about the partner’s non-overlapping members.

How a partner receives the invitation

There is no in-product messaging between the two parties — deliberately. You and your partner agree the collaboration out of band (email, a data-sharing agreement, your existing channel). Your partner computes SHA-256 digests of their identifiers locally, using the published contract above, and hands you the digest list — never the cleartext. You paste those digests into the tab (or post them to the API) and run the match. The partner never touches your Orbit tenant, and the only thing that ever crosses between you is the digest list and the resulting counts.

Query and output restrictions — what can run in the room

The room runs exactly one query shape: set intersection over hashed identifiers, with aggregate outputs. There is no general query language in the room and no path from a match to a partner’s rows. Two enforcement points make the blocked column hard, not just policy:
  • Server-side suppression. Below the effective threshold the API returns meets_threshold: false with every quantitative field null — the numbers do not exist in the response, so no client can display them.
  • Intersection-only output. The result includes only digests present in both sets. Since you submitted yours, receiving the intersection back tells you nothing you could not already compute locally — which is exactly what “no data egress” means.
A match result is a measurement, not an export. The matched digests can seed an audience activation against your own profiles; they are not a copy of any partner data, and no example on this page should be read as one.

Operator workflow: create, share, match, close

The room is stateless, so “creating” and “closing” it are operational boundaries you draw, not objects to provision.
  1. Agree the scope with the partner. Decide which identifiers both sides will hash (email, phone, or both), confirm the partner can produce digests per the contract, and set a threshold both sides are comfortable with (the default of 50 is a reasonable floor for mid-market audiences).
  2. Open the tab at Integrations → CDP → Clean room and stage your audience — export the relevant segment’s identifiers, or paste a list directly. Annotate the share with your label.
  3. Grant the partner access to the share by handing them the hashing contract and receiving their digest list back. Nothing in your tenant changes hands; the digests are the entire invitation.
  4. Run the match. Paste the partner digests, confirm the threshold, and compute. If the result is below threshold, the overlap was too small to report safely — match against a larger list or agree a different floor with the partner rather than lowering it toward 1, which erodes the privacy guarantee for both sides.
  5. Act on the result. When it meets the threshold, use the overlap count and match rates to size the campaign, and the matched digests to assemble the activation audience from your profiles.
  6. Close the room. Discarding the pasted inputs closes the collaboration — nothing was persisted to remove. The counts-only audit entry stays in your audit log as the record that a match ran, with your labels attached.

End-to-end example: retailer ↔ brand co-marketing

A retailer wants to run a co-marketing campaign with a brand, targeting customers who buy from both — without the retailer handing over its customer list and without the brand revealing its loyalty members.
  1. The retailer exports its loyalty segment’s email identifiers and pastes them into Your audience — say 12,400 identifiers.
  2. The brand hashes its loyalty members locally (same contract: normalized email → SHA-256) and sends the retailer a digest list — say 8,900 digests. The brand’s cleartext never leaves its own systems.
  3. The retailer runs the match with the default threshold of 50. The result meets the threshold: overlap 2,140 members, match rate 17.3% (yours), 24.0% (partner), Jaccard 0.11.
  4. The retailer maps the 2,140 matched digests back to its own profiles and builds the co-branded campaign audience. The brand learns the aggregate counts — and nothing about which retailer customers did not match.
  5. Had the overlap come back below 50, the result would have been withheld entirely — the campaign idea gets revisited, and no small-sets probe ever leaks a single member.
Neither list changed hands. The analytics were shared; the customers were not. The protections you maintain in the consent and suppression model travel with your data into every match:
  • Explicit opt-out. Marking a record consent: false (in the API body) drops it before hashing — it is counted as skipped and can contribute nothing to any overlap. A member who withdrew consent can never be matched into a collaboration.
  • Skipped, always counted. Opt-outs, unnormalizable identifiers, and malformed partner digests all surface in the per-side skipped counts, so you can see suppression working rather than trusting it silently.
  • Revocation between matches. The room is stateless, so a re-run always evaluates your current list. When a contact opts out in the consent model, remove them from the staged list (or exclude them at export) and the next match excludes them — there is no stale room holding their identifier.
  • Tenant-owned controls. As with the send side, consent capture and honoring are your responsibilities: Orbit carries the mechanism (opt-out drop, k-anonymity suppression, hashing-only comparison) and the audit trail; it does not make the underlying sharing arrangement lawful for you.

See also