CDP event debugger and DLQ
Two tabs on the CDP page close the usual operational gaps between “is my SDK sending?” and “why didn’t that event reach the destination”:- Event debugger — a live tail of the raw event stream with per-field filters and payload introspection. Use it to validate instrumentation the moment you ship it, before you declare anything in the tracking plan.
- DLQ — failed destination deliveries — every delivery that failed a destination across all of your subscriptions, grouped by destination, with single-row retry and per-destination bulk replay built in.
1. Events debugger
Open Integrations → CDP → Event debugger. The tab tails the raw stream of events your apps send through the ingest endpoints —track, identify, page, screen, group, alias — refreshing every few seconds while live is enabled.
Pause the poll with the Pause button (or leave it running — “Go live” re-enables it) to hold a payload on screen while you inspect it. The poll is refresh-based: filters are edited in draft fields and applied with Apply filters, so the live tail doesn’t re-fire on every keystroke. Clear resets everything to the unfiltered stream.
Find an event
Each event is a row; the newest sit on top. Point the cursor at any of these to narrow the stream:- Search payload — free-text. Matches against the identity columns and the event’s
properties/contextJSON, so an email, a SKU, a flag value, or a phone number finds the event that carries it. - Type —
track,identify,page,screen,group, oralias. - Event name — the exact
eventstring your SDK sent (case-sensitive). - User ID and Anonymous ID — which identity the event carried.
- Payload storage — where the event body ended up:
inline(stored in the event row),spilled (GCS)(the body exceeded the inline size limit, so it lives in object storage), orpayload lost(the spill failed — see below).
user_id when present, otherwise the anonymous id), and the Source the event arrived through.
Inspect a single event end-to-end
Click a row (or press Enter on it) to expand the full record:- properties and context — the exact JSON your SDK sent, pretty-printed.
contextcarries the environment your SDK attached (page, user agent, library, campaign), which is what destinations use for their own enrichment decisions. - id, message_id, contact_id, anonymous_id — the identity chain, plus the resolved
contact_idwhen the event has already been stitched to a contact.
properties you see below may be truncated, and there is no full body to fetch from anywhere. The payload lost storage filter collects every event in that state so you can find the producers sending oversized payloads.
How destinations see the same event
The debugger surfaces ingest-side truth: what arrived, when, and what it carried. Downstream, each destination subscription evaluates its own event-name filter, sampling rate, and policy gates against every event; the deliveries that fail turn up in the DLQ below. To re-run a successful window of history through destinations (after a schema fix, or to seed a new destination), that’s a separate surface — use the Backfill events card on the same page, not the DLQ.2. DLQ — failed destination deliveries
Open Integrations → CDP → DLQ. One tab shows every failed delivery across all of your subscriptions, so a destination that’s silently broken shows up here before it shows up in your downstream reports.What ends up in the DLQ
A row appears when a destination rejects or fails to receive a dispatch: your endpoint returns a non-2xx status, times out, refuses the connection, or fails TLS. Each row exposes:- Event — the event type of the failed dispatch.
- HTTP — the status code your endpoint returned, when the request got that far (
404for a wrong path,401/403for a rejected signature,5xxfor your handler erroring). Transport failures leave this empty and put the reason in the error column. - Error — the destination’s own explanation, taken from the response: hover the truncated cell for the full text.
- Attempt — how many times the dispatcher has tried this delivery.
- When — the timestamp of the last attempt, in your timezone — the column you cross-check against your server’s own logs.
Retry a single delivery
Each row has a Retry action. It re-dispatches exactly that delivery’s payload through the normal destination pipeline — the same path the live event took, with the same subscription filters and circuit-breaker rules — so one click tells you whether the destination is back. Two replies mean the delivery can’t be re-driven:- 404 — the delivery row is gone or has aged past its retention window. Re-ingest the event at the source instead.
- 422 payload not recoverable — the stored body began to exceed the preview the delivery keeps, so the original event can’t be reconstructed for replay. Re-ingest at the source rather than sending your destination a stub.
Replay a destination’s backlog
Each group header (one per destination with failures) has a Replay failed action. It re-dispatches the most recent failed deliveries for that destination, up to 50 per run, and returns a summary — “Replayed 12, skipped 3 (no recoverable payload)” — so a bulk re-drive after a confirmed outage is one click, not one per row. Skipped rows are always the no-recoverable-payload case above; everything replayable re-enters the normal pipeline. Replay is audit-logged per run (who, when, how many re-dispatched), so a fleet-wide re-drive after a destination outage is traceable.3. End-to-end: push, break, replay
The full loop takes a couple of minutes against a real destination.- Send a synthetic event. From your app’s SDK — or any HTTP client — post to your ingest endpoint (the ingest id and secret come from the source’s card on the same page):
-
Watch it in the debugger. Open the Event debugger tab — the event lands in the tail within seconds. Filter by Event name =
Order Completedor search the payload forord_debug_1, then expand the row to confirm the properties and identity chain arrived as you sent them. - Break the destination. Point your destination webhook at a dead endpoint — or take your receiver down — then send the event once more.
- Watch it arrive in the DLQ. The DLQ tab gains a row for the failed delivery: the event type, the HTTP status or transport error, the attempt count, and the time of the last attempt.
- Fix and replay. Restore the endpoint, then click Retry on the row — or Replay failed on the destination header if you accumulated a backlog. The summary reports how many re-dispatched, and the table empties as the destination starts answering 2xx again.
4. Pick the right tool
These surfaces overlap deliberately, so you land on the right one on your first visit:5. Permissions
- Roles. The CDP read surface (events debugger, DLQ listing) and the write actions (single retry, bulk replay, backfill) are exposed to owner, admin, and developer roles. Replay and retry fan live dispatches out to your endpoints, so there’s no read-only path to them — restrict those roles accordingly.
- API keys. A key-based caller needs the matching scopes. The events debugger returns full
properties+contextpayloads, which routinely carry email, phone, or checkout PII, so an API key without the scope that grants contact-data reads is fenced away from the endpoint — a key that can list subscriptions but not read contact data cannot tunnel payloads out through the debugger. Replay/retry inherits the same subscription-write gates the rest of the CDP API uses.
API surface
The tabs are UI over these endpoints:
For the underlying pipeline — subscriptions, filters, circuit breaker, HMAC signing, and delivery semantics — see Event sinks and destinations, CDP tracking plan, and the CDP event model.