<!-- Kind: Integration guide. Status: Preview. Maintained with: sdk/event-collection and internal/eventcollection. Served at /user-metrics/verification and /user-metrics/verification.md. -->

# Verify and troubleshoot

Check delivery and lifecycle behavior before releasing your integration. For a custom client, apply these checks to your own persisted queue and diagnostics.

## Verify your integration

1. Enable collection for the selected game and initialize after consent.
2. Track one custom action and start two progression attempts. Complete one and fail the other.
3. Flush, check accepted delivery in SDK diagnostics, then check the daily charts after the next dbt run. Open the authenticated [example integration](/static/event-collection-demo/) with `?product=<your Coal project ID or slug>` appended to its URL.
4. Check acknowledged and pending counts in SDK diagnostics, then verify daily session and progression counts after dbt publishes. A successful collector response means the batch committed durably.
5. Use the example's offline transport control: enqueue an action while offline, verify `pending` increases, then reconnect and flush. Raw events should arrive once per event ID.
6. Reload with pending events, grant consent again, and initialize. Verify the persisted queue recovers.

The example page reads the selected game's setup and displays SDK diagnostics and daily dbt aggregates. A hosted player build needs only the public ingestion key; the SDK supplies the collector endpoint. Coal displays the resulting daily metrics.
## Verify your metric inputs

Use an empty **local** game scope for these repeatable checks.

| Check | Expected daily result |
| --- | --- |
| One consenting installation sends one new session on a UTC day. | One new installation, one active installation and one session. |
| The same session sends cumulative durations of `0`, `30000` and `60000` in reserved session events. | One session with 60 seconds observed active time. For the SDK, compare against its actual measured foreground duration. |
| One `tutorial` attempt starts and completes. | One tutorial attempt and one completion. |
| Two `level_1` attempts start; one fails and one completes. | Two level attempts, one failure and one completion. |
| A later new session reuses the same installation ID. | The session count increases; the installation count stays the same. Respect the SDK's 30-minute away boundary when testing a new session. |
| That installation sends activity on the following UTC day. | It is active on the return day and qualifies as a D1 return. The D1 report appears only after that return day ends. |

Check each local result after dbt publishes. Start/outcome events must use matching installation, attempt and stage IDs. Follow [Events and metrics](/user-metrics/event-design) for the underlying calculation and [Direct API retry rules](/user-metrics/api#durable-queues-and-acknowledgments) for custom clients.

Also check that a restarted app retains its installation and outstanding attempt state, foreground time stops increasing while backgrounded, reporting-off stops delivery, and an offline queued batch survives restart and is acknowledged after reconnection. A repeated delivery should acknowledge the same events as duplicates.

## Troubleshooting

| Symptom | What to check |
| --- | --- |
| `init()` rejects | Explicit consent, a nonempty key (and a valid endpoint if overriding it), browser support, and accessible IndexedDB. Catch the initialization error. |
| Browser CORS error | The shared collector supports all origins. Check network access, the endpoint if overridden, and any proxy or host restrictions. |
| `pending` grows while offline | Expected. Reconnect and allow retry time; the bounded queue continues to retain events. |
| `batch_rejected`, status 403 | Game enabled, key active, owning account eligible, and collector access renewed by Coal. Delivery pauses. |
| `batch_rejected`, status 400/409 | Invalid payload or conflicting reuse of an event ID. Correct the cause; preserve the diagnostic before clearing. |
| HTTP 429 | Rate or concurrency limit. The SDK backs off automatically. |
| HTTP 503 | Durable commit unavailable. The SDK retries the same IDs. |
| `persistence_error` | Browser storage transaction failed. Inspect browser storage restrictions and report the loss. |
| `queue_overflow` / `queue_expired` | Queue bounds were exceeded or offline events aged out. Inspect `dropped` / `expired`. |
| No final session event | Unload delivery is best effort; use the last observed cumulative heartbeat duration. |

Diagnostics contain `enqueued`, `acknowledged`, `dropped`, `expired`, `retries`, `permanentErrors`, `persistenceErrors`, `pending`, `enabled`, `blocked`, and `retryAt` (Unix milliseconds). Counters describe this SDK instance; `acknowledged` can include recovered events from earlier instances. A healthy queue can temporarily have pending events between flushes.
