How delivery works
A destination receives your attributed installs. You set each one up by pasting the platform’s own credentials: there is no “connect” sign-in. Every destination starts in test mode, shows you the exact payload it would send, and goes live only when you say so.
| Destination | Status | What it receives | You provide |
|---|---|---|---|
| Google Analytics 4 | Available | A cli_install_completed or cli_first_run event on the visitor's GA4 client ID | Measurement ID, API secret |
| Google Ads | Available | An offline click conversion through the Data Manager API | Service account key (JSON), customer ID, conversion action, consent signals |
| Meta | Available | A Conversions API event with fbc and fbp | Pixel ID, access token |
| TikTok | Available | An Events API web event with ttclid and ttp | Pixel code, access token |
| X Ads | Available | A Conversions API conversion with twclid | Pixel ID, event ID, consumer key and secret, access token and secret |
| Webhooks | Available | A signed JSON event for every install, attributed or not | An https URL |
#Plans
Destinations are part of the Standard and Enterprise plans. On Free they cannot be created, tested or switched live (402, plan_required), and nothing reported while on Free is ever sent later. A website can have up to 10 destinations on Standard and 20 on Enterprise. After a downgrade, destinations over the new limit are paused, whatever their own mode, until the owner picks which to keep; nothing is deleted. See Plans and limits.
#Modes
| Mode | What happens |
|---|---|
| Test | The default. Each new install gets its payload prepared and listed under Install events with the status dry_run. Nothing is sent. |
| Live | New installs are queued and sent. |
| Paused | New installs are not queued. Anything already queued waits until the destination is live again. |
Going live applies to installs recorded from then on. Test-mode payloads and installs from before the destination existed are never sent later.
#Send a test
Send test checks the credentials you saved without sending a real install:
- GA4 sends a sample event to GA4's validation server. GA4 checks the event format but does not confirm API secrets.
- Google Ads sends a validate-only request, which checks access to the account and conversion action. Nothing is recorded.
- Meta and TikTok need the test event code from the platform's Events Manager and send an event named
CLItrailConnectionTest. - X Ads sends a signed request with an empty list of conversions: X checks the credentials, and nothing can be recorded. X has no test events, so read the prepared requests under Install events in test mode.
- Webhooks send a signed
test.pingand show the status code your endpoint returned.
#Go live
Go live is refused until the destination can deliver:
| Requirement | Applies to | Error when missing |
|---|---|---|
| A Standard or Enterprise plan, within its destination limit | All | plan_required, plan_limit |
| Every credential saved | All; a webhook’s signing secret is generated for you | destination_missing_credentials |
| You confirm the platform's terms and your notice and consent duties. The time and your email are recorded. | Google Ads, Meta, TikTok, X Ads | consent_confirmation_required |
| The website's primary domain is verified | Google Ads, Meta, TikTok, X Ads | domain_verification_required |
#Which installs are sent
- Events. Each destination sends the event types you tick. Ad platforms default to completed installs; GA4 and webhooks also send first runs.
install_startedis an attempt, not a conversion: only webhooks receive it, and the other destinations refuse it (unsupported_event). - Resolution. GA4 and the ad platforms receive matched installs. They receive reconstructed (probable) installs only when you turn on Include reconstructed installs on that destination. Webhooks receive every install with its resolution.
- Global Privacy Control. Google Ads, Meta, TikTok and X Ads never receive a touch recorded under GPC.
- Identifiers. Each platform needs its own ID on some touch of the journey: a GA4 client ID for that measurement ID, a Google click ID or session attributes,
fbcorfbp,ttclidorttp, atwclid. Without one, nothing is queued for that platform. Each platform follows your attribution policy: its most recent identifier under latest visit, its earliest under first visit. A click is dated by its own evidence (the visit whose URL carried it, the_gcl_awor_fbccookie time, Google's session start or the TikTok click date), so a cookie re-read on a later visit never outranks a newer click on another domain.
#Retries and time limits
| Destination | Per request | Retries | Expires | Deduplicated on |
|---|---|---|---|---|
| GA4 | 1 | Never. An unknown outcome becomes uncertain. | 72 hours after the install | not applicable |
| Google Ads | up to 2,000 | Up to 8 attempts | 30 days after the install, or 90 days after the click | transactionId |
| Meta | up to 1,000 | Up to 8 attempts, within 48 hours | One hour short of 7 days after the install | event_id and event_name, 48 hours |
| TikTok | up to 50 | Up to 8 attempts, within 48 hours | 7 days after the install | Pixel, event name and event_id, 48 hours |
| X Ads | up to 500 | Up to 8 attempts, within 48 hours | 90 days after the install | conversion_id against your X pixel, 48 hours |
| Webhooks | 1 | Up to 10 attempts | 3 days after the install | webhook-id |
Retries wait 1 minute, 5 minutes, 15 minutes, 1 hour, 3 hours, 6 hours, 12 hours, then 24 hours, or longer when the platform sends Retry-After (up to a day). Every retry reuses the same event ID, so Google Ads, Meta, TikTok and your webhook endpoint can ignore a copy they already have. Meta and TikTok retries stop before their 48-hour deduplication window closes, checked when each batch is sent; a resend that could arrive at 48 hours or later is marked uncertain instead of risking a double count. X Ads retries stop at the same 48 hours, but X documents deduplication only against its pixel, not between two API sends, so X Ads resends only requests X answered with an error or never answered.
- When a platform refuses the whole request, CLItrail resends the events one at a time so one bad event cannot block the others (Google Ads, Meta, TikTok, X Ads).
- When a platform refuses a credential, the events stay queued within the platform's own time limit and are tried about once an hour; refusals do not use up attempts or start the deduplication window. Replacing the credential or correcting the account or pixel resumes delivery at once. The destination's health shows the error.
- A send interrupted by a restart or crash is retried for Google Ads, Meta, TikTok and webhooks, which deduplicate it, and for X Ads within its 48 hours, where such a resend can count twice; it becomes
uncertainfor GA4. A Node server that is shutting down starts no new batch and waits for the requests in flight. - Destinations are delivered side by side, each one run at a time, so a slow endpoint or a large backlog holds up only its own queue. An endpoint that does not answer holds its queue for a minute, or its
Retry-After. - A webhook that answers
410 Gonepauses its destination;401,403,404,408,429and5xxare retried. The change is recorded in the audit log. - Redirects are never followed; a 3xx answer counts as a failed delivery.
X Ads follows its own rules, on the X Ads page.
#Delivery statuses
| Status | Meaning |
|---|---|
dry_run | Prepared in test mode. Never sent. |
pending | Queued for a live destination. |
sending | Being sent now. |
retry | A temporary failure; another attempt is scheduled. |
submitted | The platform accepted the request. For GA4 this is an HTTP success, not confirmed processing. |
rejected | The platform refused it. The error is shown. |
uncertain | The outcome is unknown and a resend could count twice (GA4, or past a platform's deduplication window), so it is not resent. |
expired | Too old for the platform before it could be sent. |
failed | All attempts used on temporary failures, or the queued event could not be read. A refused credential never uses up attempts. |
cancelled | The destination was removed before sending. |
Each destination card shows its health (ok, error, auth_error, or never before the first delivery), the last error with any secret removed, and counts per status for the last 30 days.
#Managing destinations
- One destination per target: one per GA4 measurement ID, Meta pixel, TikTok pixel, X pixel event, Google Ads conversion action or webhook URL (
duplicate_destination). - Members create and edit destinations; admins and owners remove them. See roles.
- Credentials are write-only and kept in a separate secret store. See Security and secrets.
- Every request sent to a platform is recorded in Logs with its exact body, credentials redacted.
- Removing a destination deletes its credentials and cancels everything it had not sent.
- Every change is recorded in the website's audit log in Settings, without secret values.