Skip to main content

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.
Both live in the dashboard at Integrations → CDP. Everything below also works from the API.

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 / context JSON, so an email, a SKU, a flag value, or a phone number finds the event that carries it.
  • Typetrack, identify, page, screen, group, or alias.
  • Event name — the exact event string 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), or payload lost (the spill failed — see below).
Set several at once; they’re AND-combined. Enter in any text field also applies the draft filters. The table shows, per row: Received (timestamps render in your zone), Type, Event name, Identity (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. context carries 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_id when the event has already been stitched to a contact.
A red banner on the expanded row means the original payload is unrecoverable: the event exceeded the inline size limit and the upload to object storage failed. The event still persists and fans out to destinations, but the values past the storage failure were dropped and replaced with placeholders — so the 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 (404 for a wrong path, 401/403 for a rejected signature, 5xx for 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.
Failed deliveries are also what trip a destination’s circuit breaker: after enough consecutive failures a subscription is marked open and excluded from new dispatches until you reset it. Replay routes through the same circuit-breaker check, so a destination you haven’t fixed yet won’t accept a flood of re-dispatches.

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.
  1. 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):
  1. Watch it in the debugger. Open the Event debugger tab — the event lands in the tail within seconds. Filter by Event name = Order Completed or search the payload for ord_debug_1, then expand the row to confirm the properties and identity chain arrived as you sent them.
  2. Break the destination. Point your destination webhook at a dead endpoint — or take your receiver down — then send the event once more.
  3. 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.
  4. 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 + context payloads, 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.
Every replay and retry lands in the audit log with the actor’s user id and IP, so access reviews stay grounded in the audit log, not the dashboard.

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.