Skip to main content

List-Hygiene Projection: DNC Suppression on the Pre-Flight Preview

The campaign dry-run answers “how many recipients will actually receive this send, and what will it cost?” before you launch. Until the list-hygiene projection landed, one dimension was missing from that answer: the Do-Not-Call gate the send path enforces. The dry-run already shows reachability (suppression, opt-out, missing address) and a spend projection — but a number on a DNC or suppression list still counted as “deliverable,” was dropped at dispatch, and the spend projection included it. The list hygiene section closes that gap: it samples your deliverable recipients through the same DNC/suppression chain the send path enforces, projects the hit ratio onto the whole cohort, and turns the result into an avoided-spend estimate — all before the campaign launches.
This page describes Orbit’s platform controls. It is not legal advice. Whether contacting a given number is restricted depends on your jurisdiction, your recipients, and what you send — confirm with qualified counsel.

The dimension the dry-run used to miss

Launch a phone-shaped campaign (SMS, MMS, voice, RCS, Viber, WhatsApp, and the other E.164 channels) and the send path checks every recipient against your DNC sources — the contact DNC flag, your DNC and suppression lists, recorded consent opt-outs, and the synced national registries — before anything goes out. A recipient matched on any of them is silently skipped. Before this projection existed, that skip was invisible at planning time:
  1. The dry-run resolved audience.suppressed, audience.opted_out, and audience.unreachable (no deliverable address for the channel) and netted all three out of audience.deliverable — so the preview already discounted the recipients it could see wouldn’t receive the send.
  2. DNC-listed numbers never got that treatment. A number listed on your DNC list or a synced national registry counted as deliverable, the cost projection charged for it, and the send gate dropped it at dispatch without ever telling you the drop was coming.
  3. The result was a discovery loop on every launch: launch the campaign, watch recipients vanish at the send gate, find out after the fact how much spend the list would have wasted.
The list-hygiene projection points the same DNC chain at a bounded sample of the deliverable cohort during the dry-run itself, so the operator sees “the send gate will skip roughly N of these recipients, and scrubbing them avoids roughly $X of spend” before launch. A bulk single-number or 500-at-a-time pre-flight scrub is still available when you want per-number verdicts; the projection is for the campaign preview where a full scrub on every preview refresh would be wasteful.

How the projection is computed

POST /api/v1/campaigns/:id/dry-run evaluates both the DB-bound sampling step and the pure ratio math in one response:
  1. Sample the deliverable cohort. The dry-run samples up to 200 phone numbers from the campaign’s audience (list, segment, CSV roster, or the contact book), ordered by contact ID — the same deterministic bounded-sample strategy the quiet-hours projection uses.
  2. Run the same DNC chain the send gate enforces. Each sampled number goes through the same batch DNC/suppression check used at dispatch time: contact DNC flags, tenant DNC lists, cross-channel STOP suppression lists, recorded consent opt-outs, plus the platform-level federal/state/TCR and international registry feeds.
  3. Project the ratio onto the cohort. The blocked ratio observed in the sample (blocked_estimate = sample_blocked / sample_size × deliverable, rounded, and capped at the deliverable count) is extrapolated onto the full deliverable cohort. A clean sample exactly reports zero, never a phantom hit.
  4. Convert to avoided spend. The projected block count is multiplied by the same per-message unit price the dry-run’s cost estimate is built with — the projection never invents a second rate — and formatted as a "$X.XX USD" savings figure.
Only phone-shaped channels are projected: DNC has no meaning for email, so an email-only channel reports the DNC check as not run. A sampling or pricing failure degrades the same way — the probe reports checked: false and the preview carries a warning rather than fabricating a zero. Read-only throughout: the projection samples data the send path already consults and writes nothing. It never dispatches a message, touches a carrier, or charges anything — it is pure bookkeeping over the compliance sources you own as a tenant.

Reading the response

The block appears in the dry-run response under list_hygiene:
  • dnc.checked — whether the DNC sample actually ran. false means the dimension was not evaluated (email-only channel, no channel configured, or the probe failed) — never read it as “checked and clear.” When it is false, treat DNC exposure as unknown.
  • dnc.sample_size / dnc.sample_blocked — the raw sample stats. A high sample_blocked / sample_size ratio on a small cohort is your sign to run the full batch scrub for per-number verdicts instead of relying on the projection.
  • dnc.blocked_estimate — the projected count of the full deliverable cohort the send gate will drop.
  • estimated_savings_cents / formatted_savings_usd — the spend that would have been wasted on recipients the send gate would have skipped anyway. null when the dry-run could not resolve a unit price.
In the dashboard, the launch preview renders the same block as a “List hygiene” panel: “DNC suppressed N (~$X saved)” when the sample found hits, or a clear sample acknowledgement (“no Do-Not-Call matches in the 200-recipient sample”) when it found none. When checked is false, the panel shows nothing — a preview that could not run the check never claims the list is clean. The dry-run also folds the finding into its warnings array, e.g. “Approximately 359 of 11,960 deliverable recipients are on a Do-Not-Call list and will be skipped at send time — an estimated $4.66 USD in avoided spend.” Warnings are informational, so they do not block ready_to_launch — the point is to surface the skew before launch, not to gate the send.

How it contrasts with the other dry-run projections

Three pre-flight projections now read off the same resolved audience: All three fold into one audience-resolution pass, so the counts stay consistent. The differences to keep straight:
  • Reachability is exact, samples are estimates. Suppression / opt-out / addressability counts run over the full audience, so deliverable is exact. The DNC and quiet-hours projections sample — a bounded trade-off that keeps a 100K-recipient preview cheap. Use sampling for planning, and run the endpoint-level index checks below for per-number answers before launch.
  • DNC skips are avoided spend; quiet-hours skips are deferred spend. A DNC-blocked recipient never receives this send (the check is read-only — the number is not added to or removed from any list). A quiet-hours recipient is re-queued for the next allowed window.
  • Warnings are informational. None of the three block ready_to_launch — they exist so a skewed list surprises you before dispatch, not after.

Tenant-owned bookkeeping only

The projection is a read over your own compliance data expressed in planning numbers:
  • It never contacts a carrier, and it never sends. The same invariant that governs the whole campaign preview applies here — no outbound traffic is placed to compute it.
  • It writes nothing. Sampling is read-only; the scrub verdicts consult your DNC lists, suppression lists, consent records, and synced national registries without mutating them.
  • The DNC checks it runs are the same tenant-scoped sources the send gate enforces — there is no global country or registry gate layered in. What you can do with the answer (route flagged numbers to suppression, remove them from the segment, re-check consent) is the workflow covered in Batch DNC Pre-Flight Scrubbing.

See also: