The debug pyramid
Most teams debug server-side tracking upside down. They open Meta Events Manager, see nothing useful, and start changing payloads before they know whether the event even reached TrackLayer. That usually creates more noise than signal. A better approach is a five-layer pyramid that mirrors the real delivery path from source event to attributed conversion.
Work top-down. Each layer depends on the one before it. If Layer A fails, Layers B through E are irrelevant. If Layer C is clean but Layer D rejects the payload, the platform dashboard is not the primary debugging tool. This order reduces guesswork, shortens incident time, and makes support tickets much easier to resolve.
Is the event arriving at TrackLayer?
If the event never appears in the live stream, stop there. Nothing downstream can recover it. This is where you validate SDK initialization, API key validity, browser-to-server transport, queue backpressure, and whether the request is being rate-limited before TrackLayer stores the event.
Is TrackLayer enriching properly?
An arriving event can still fail quietly if normalization mutates identifiers, drops user_data fields, or generates the wrong event_id. Review enrichment output for normalized email, phone, currency, order identifiers, consent state, and hashed fields to confirm the platform-ready payload is coherent.
Is delivery attempted to the platform?
Delivery status answers whether TrackLayer actually tried to send the event to Meta, TikTok, Google Ads, Klaviyo, or another destination. If no delivery record exists, the routing rule, consent rule, destination toggle, or event mapping is usually the real problem.
Is the platform accepting it?
A delivery attempt is not the same thing as acceptance. The raw destination response tells you whether the payload was accepted, partially accepted, rejected, throttled, or ignored due to schema errors. This is where you catch 400 payload problems, 401 auth issues, 403 permissions, and 429 retry storms.
Is the platform attributing it correctly?
Even an accepted event can show weak or delayed attribution if dedup is wrong, click IDs are missing, cookies are absent, consent suppresses matching identifiers, or the platform decides the event is out of attribution window. This last layer is about reporting quality, not transport success.
5 tools for each layer
Each layer has one best inspection surface. The goal is not to use every screen. The goal is to use the smallest number of screens that let you compare intent, actual payload, delivery behavior, and platform feedback with minimal interpretation.
Chrome DevTools network tab + TrackLayer live event stream
Open DevTools, reproduce the action, and inspect the request that should create the event. Confirm status code, payload size, request timing, and whether retries or CORS failures appear. Then compare the same moment in TrackLayer live stream. If DevTools shows a request but `/events` stays silent, focus on auth, edge rejection, or queueing.
`/events` detail drawer → raw payload JSON
Use the detail drawer to compare the inbound payload against the enriched payload. This is the fastest place to catch malformed `event_name`, missing `event_id`, wrongly cased currency, unnormalized email, and unexpected null values. When match quality is low, this drawer usually shows why in one screen.
`/deliveries` status chip
The `delivered`, `failed`, and `pending` chips tell you whether routing is alive and whether retries are still in flight. A pile of `pending` deliveries usually points to worker backlog or destination throttling. A clean event with no delivery row usually means the destination rule never matched.
`/api-logs` response body inspection
Read the full response body instead of stopping at the HTTP code. Many platforms return structured warnings such as missing `fbp`, invalid `event_time`, unsupported parameter names, or partially accepted user_data. Those details tell you whether to fix transport, schema, or identity.
Meta Events Manager → Test Events → Diagnostics
Use the destination dashboard only after the first four layers are clean. In Meta, Test Events confirms real-time arrival, while Diagnostics explains match quality issues, dedup collisions, or parameter mistakes. Apply the same pattern on other platforms: verify arrival, then verify attribution health.
Common symptom → likely cause
This table is a triage tool, not a substitute for logs. Use it to decide which layer to inspect next. The fastest investigations are the ones where the symptom immediately narrows the search surface.
| Symptom | Check | Likely cause |
|---|---|---|
| No events in live stream | API key, rate limit, SDK init | The request is never authenticated or never leaves the page or backend worker in the first place. |
| Events arrive but match quality stuck at 4 | Email hash normalization | Whitespace, casing, or pre-hashed values often prevent the platform from matching what should be strong identifiers. |
| Purchase events but Meta doesn’t count | event_id dedup + fbp cookie forwarding | Accepted events can still fail attribution when Meta sees a dedup conflict or lacks browser identifiers for matching. |
| Event visible in `/events` but no `/deliveries` row | Destination routing rule | The event is stored but not eligible for the destination because mapping, consent, or toggle conditions skip it. |
| Delivery stuck on pending for minutes | Worker backlog or 429 retries | The delivery queue is alive but delayed, usually because the destination is throttling or workers are saturated. |
| High failed-delivery count after a deploy | Secret rotation and environment vars | A rotated token, wrong project environment, or missing secret often appears immediately after deployment changes. |
| Google Ads enhanced conversions accepted but weak | User-provided data formatting | Phone, email, and address inputs must be normalized consistently before hashing or Google will accept low-quality identifiers. |
| Events duplicate across Pixel + CAPI | Shared event_id across browser and server | If the browser and server generate different IDs for one action, the platform counts two conversions instead of one deduped event. |
| Only some orders reach the destination | Consent branch and order-source filters | Mixed consent states, channel-specific routing, or source-based exclusions can make the issue look random when it is rule-driven. |
| Test event works but production attribution lags | Attribution window and click IDs | Test tools confirm transport, but production credit still depends on fresh click identifiers and valid attribution timing. |
| Refund or cancellation events never appear | Canonical event mapping | Non-standard internal event names often never map to the destination event type expected by the integration. |
| Klaviyo receives profile updates but not purchase metrics | Metric payload shape and metric name | Profiles can be valid while event creation still fails because the metric object or event time is malformed. |
The dedup diagnostic
The classic complaint is simple: “my Pixel + CAPI are double-counting.” The underlying causes are usually simple too, but only if you debug one conversion at a time. A clean dedup investigation should prove whether browser and server are talking about the same action, whether they share one `event_id`, and whether the destination had enough identifiers to merge them.
Start with one known order
Pick a single checkout from a test user and collect the browser event timestamp, Pixel request, server event timestamp, and TrackLayer event_id. Debugging dedup with a broad date range is slow because noise hides the exact collision you need.
Compare event_id on both paths
Open the browser payload and the TrackLayer delivery payload side by side. The `event_name` and `event_id` must describe the same user action. If the browser sends `purchase_click_123` and the server sends `order_987_paid`, Meta treats them as different conversions.
Check arrival timing, not just content
Large timing gaps can produce misleading diagnostics. If the browser fires immediately but the server arrives much later after retries, the platform may still dedup, but reporting can look unstable for a while. Review both timestamps before concluding that content is wrong.
Inspect platform diagnostics for dedup warnings
Meta Diagnostics and Test Events usually show whether the browser event or server event was favored and whether identifiers were insufficient. That tells you whether to fix ID parity, browser cookie forwarding, or simply delivery latency.
Fix ID generation at the source
Do not patch dedup downstream with ad hoc rewrites. Generate one durable `event_id` when the business action is created, store it on the order or checkout entity, and reuse it everywhere: pixel, webhook, replay, and TrackLayer delivery.
The consent diagnostic
Consent bugs are easy to misread because the system may be doing exactly what policy says while the operator expects marketing attribution behavior. The right way to debug consent is to trace a single user journey from banner choice to event payload to routing decision to platform outcome. That separates genuine bugs from intended suppression.
Record the banner decision
Start at the consent banner and capture exactly what the user accepted or rejected. If analytics consent is denied but marketing consent is granted, your routing behavior should show that distinction explicitly instead of collapsing everything into a generic blocked state.
Confirm consent state on the event
Open the event in `/events` and inspect the consent fields captured at collection time. If consent is missing here, the problem is not destination delivery. It is state propagation between the frontend banner, backend session, and TrackLayer ingestion.
Inspect the routing decision
In `/deliveries`, verify whether the destination was intentionally skipped, delayed, or allowed. A skipped delivery with a clear consent reason is correct behavior. A missing reason usually means the routing rules are opaque or incomplete.
Validate what was stripped before send
Some merchants permit event forwarding without marketing identifiers when consent is limited. In that case the payload may be sent but with hashed identifiers, cookies, or click IDs removed. The event will arrive but match quality will drop, which is expected and should be visible in logs.
Cross-check the platform result
Finally, open the platform diagnostics and confirm that the event behavior matches the consent policy you intended. If the policy says send a purchase with limited identity, you should see the event with weaker attribution, not a completely missing conversion.
Platform-specific diagnostic URLs
Keep a bookmark list for the destination entry points you actually use. These links are the fastest way to move from a TrackLayer event into the platform screen where arrival, diagnostics, and attribution behavior become visible.
Meta Events Manager
Open diagnostic workspace →Google Ads Conversions
Open diagnostic workspace →GA4 DebugView
Open diagnostic workspace →TikTok Events Manager
Open diagnostic workspace →Snap Events Manager
Open diagnostic workspace →Pinterest Conversions
Open diagnostic workspace →LinkedIn Conversions
Open diagnostic workspace →Reddit Events Manager
Open diagnostic workspace →X Event Manager
Open diagnostic workspace →Microsoft Ads Conversions
Open diagnostic workspace →Klaviyo Metrics Activity
Open diagnostic workspace →Taboola Conversions
Open diagnostic workspace →When to open a TrackLayer support ticket
Open a ticket after you have isolated the layer, not before. A vague “Meta is missing purchases” report forces everyone to re-run the same checks. A precise ticket gives TrackLayer enough context to inspect worker history, destination formatting, or internal retries immediately.
You can reproduce the issue with one specific event_id and TrackLayer shows behavior that conflicts with its own logs.
The platform response is ambiguous or contradictory, for example accepted in `/api-logs` but never visible in test tools after repeated controlled sends.
The problem spans multiple merchants or multiple destinations at the same time, which usually points to infrastructure or shared routing changes.
You have already isolated the layer and need TrackLayer to inspect internal worker state, retry history, or destination-specific formatter output.
Include the following fields every time so the investigation can start from one concrete event instead of a time range.
- event_id
- timestamp
- merchant_id
- affected platform
- expected vs actual
Common questions
What is the first screen I should open when a conversion is missing?
Open `/events` first. If the event is not there, every later dashboard is noise. The live stream tells you whether TrackLayer ever received the action you are trying to debug.
Why do accepted events still fail to show up in reporting?
Acceptance only means the API received the payload. Reporting still depends on attribution rules, click identifiers, cookies, consent state, dedup behavior, and the platform’s own processing delay.
Should I debug in the platform before TrackLayer?
No. That reverses the dependency chain and wastes time. Start at collection, then enrichment, then delivery, then API response, and only then attribution dashboards.
How long should I wait before calling an event missing?
For real-time testing, give the destination a few minutes unless the API explicitly rejected it. For attribution reports, some platforms lag longer, so use Test Events or diagnostics rather than waiting on aggregated reporting.
What is the most common root cause in double-counting investigations?
Different `event_id` values for the browser and server version of the same conversion. The second most common cause is forwarding the server event without the browser identifiers needed for confident dedup.
Related implementation guides
Deduplication explained
How to keep one user action equal to one counted conversion across browser and server paths.
Read guide →Identity resolution guide
Build consistent identifiers so debugging starts from clean input instead of unstable customer data.
Read guide →Meta CAPI setup guide
A destination-specific companion for testing, matching, and attribution diagnostics inside Meta.
Read guide →