> For the complete documentation index, see [llms.txt](https://docs.adpage.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.adpage.io/app-tracking/testing-and-verification.md).

# Testing and verification

Confirm that app events reach the container and that each platform accepts them, without depending on someone else's device.

## The order to test in

{% stepper %}
{% step %}

## Publish first

Publish the container. A client testing against an unpublished workspace sees the same nothing as a client testing against a broken setup.
{% endstep %}

{% step %}

## Fire the event on a real device

A registration, a purchase, whatever the agreed conversion is. A simulator often lacks an advertising id.
{% endstep %}

{% step %}

## Check GA4 Realtime

The event arriving there confirms that the app reaches the container and that the GA4 tag fires.
{% endstep %}

{% step %}

## Check the outgoing requests

This shows per platform whether the event left and what the platform answered. See below.
{% endstep %}

{% step %}

## Check the platform's own test tool

Meta Test Events, the TikTok testing tool. Use a `test_` prefixed event name while testing, and remove the prefix before going live.
{% endstep %}

{% step %}

## Confirm both platforms

iOS and Android separately, before raising the traffic percentage.
{% endstep %}
{% endstepper %}

## Preview, and why it is often empty

An app event only reaches a preview session when the request carries the `X-Gtm-Server-Preview` header. The Firebase SDK adds it only after the device has been bound to the session by scanning the preview QR code, which opens the app through the `tagmanager.sgtm.c.[bundle-id]` URL scheme. Without that step, preview shows nothing while the events are in fact arriving.

The binding also needs support in the app: a preview activity on Android, and the URL scheme plus the SDK's open-URL handler on iOS. That iOS part is regularly left out, because it affects preview only.

So an empty preview is not evidence that nothing arrives. Two other mistakes produce exactly the same picture: previewing the web container instead of the server container, and testing against a workspace that was never published. Confirm in the outgoing requests before you conclude anything.

Once a session is bound, preview is the right place for one question: what does the client actually deliver. Select the **App tracking** client on the incoming event and read the **Event Data** tab. See **Event data reference**.

## Find app events in the outgoing requests

The container's outgoing requests record what was sent to the platforms, including the payload and the answer. Search on app signals rather than on the event name.

* `event_name` is empty on the server-to-server path, so a filter on the event name alone can come back empty while events were in fact sent.
* A Meta app event is recognisable by `"action_source":"app"` in `raw_body`.
* A GA4 app event is recognisable by `firebase_app_id` or `app_instance_id` in `request_url`.
* `status_code` shows whether the platform accepted it, `raw_response` holds the error.

```sql
SELECT created_at, platform, status_code,
       substring(raw_body, 1, 500)     AS body,
       substring(raw_response, 1, 500) AS response
FROM outgoing_requests
WHERE container_id = '[container-id]'
  AND created_at >= now() - INTERVAL 14 DAY
  AND (raw_body ILIKE '%"action_source":"app"%'
       OR request_url ILIKE '%firebase_app_id%'
       OR request_url ILIKE '%app_instance_id%')
ORDER BY created_at DESC
LIMIT 50
```

Per platform, whether any app traffic goes out at all:

```sql
SELECT platform,
       countIf(raw_body ILIKE '%"action_source":"app"%') AS app_events,
       countIf(status_code >= 400)                        AS errors,
       count()                                            AS total
FROM outgoing_requests
WHERE container_id = '[container-id]'
  AND created_at >= now() - INTERVAL 14 DAY
GROUP BY platform
```

## Reading the result

| Result                           | Meaning                                                                            |
| -------------------------------- | ---------------------------------------------------------------------------------- |
| Rows with a 2xx status           | The app reaches the container and the platform accepts the event                   |
| Rows with a 4xx status           | The app reaches the container, the payload is wrong. Read `raw_response`           |
| No rows at all                   | Nothing leaves. Check the GA4 data stream setting, the App client and the triggers |
| App rows present, nothing in GA4 | The GA4 tag is not triggered on the App client                                     |

{% hint style="warning" %}
`raw_body` is empty for GET requests, which carry their payload in the URL, and on containers that do not log bodies. An empty `raw_body` means "not logged", never "parameter missing".
{% endhint %}

## Going live

* Remove the `test_` prefix and switch to the final event names.
* Raise the GA4 traffic percentage to 100, if it was lowered.
* Hand over a short note: what was configured, which events run, and where to monitor them.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.adpage.io/app-tracking/testing-and-verification.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
