Install
openclaw skills install @autonnel/server-side-conversion-trackingSet up server-side conversion tracking so purchases are reported accurately to Facebook, TikTok, Google and Bing despite iOS restrictions, ad blockers and cookie loss.
openclaw skills install @autonnel/server-side-conversion-trackingBrowser pixels lose a large and unpredictable share of conversions to iOS tracking prevention, ad blockers, cookie lifetime limits and cross-domain hops. Server-side reporting fixes the reporting, which is what the ad platform's bidding model learns from. This skill covers the model, the setup order and how to verify it.
Getting this order wrong is the usual reason a "server-side setup" still under-reports.
1. Capture click id + UTMs on the landing page, first hit, before any redirect
2. Persist attach them to the visitor's session, server-side
3. Carry keep them across every funnel step, including cross-domain hops
4. Attach write them onto the order record at purchase
5. Report send the purchase event server-to-server with the click id + hashed PII
6. Dedupe give the browser event and the server event the same event id
7. Verify compare platform-reported conversions against your own order table
Skipping step 1-4 and only doing step 5 produces server events with no click id, which the platforms then have to match on hashed email alone - that is materially worse matching, and it is the most common failure in a "we already do CAPI" setup.
| Platform | Click id parameter |
|---|---|
| Facebook / Instagram | fbclid |
| TikTok | ttclid |
| Google Ads | gclid (also wbraid / gbraid on iOS app-to-web) |
| Microsoft / Bing | msclkid |
Also capture, on the same first hit: utm_source, utm_medium, utm_campaign, utm_content, utm_term, the full landing URL, referrer, user agent, and the client IP as seen by the server. Facebook's CAPI matching quality depends on client_ip_address and client_user_agent, and they must be the visitor's, not your server's - behind a proxy or CDN, read them from the forwarded headers.
Store server-side, keyed to a first-party session. Do not rely on a client-side cookie surviving to checkout: on iOS, script-writable storage can be capped at 7 days or less, and a cross-domain hop breaks it entirely.
?fbclid=... destroys attribution for that entire campaign.The order record must carry the click ids, UTMs and landing URL. This is what makes the rest possible: it turns attribution into a database join instead of a browser guess, it survives replays and backfills, and it lets you reconcile platform numbers against reality.
| Platform | Endpoint / mechanism | Credentials needed |
|---|---|---|
| Conversions API | Pixel ID + access token | |
| TikTok | Events API | Pixel code + access token |
| Google Ads | Click conversion import (gclid-keyed) | Conversion action + developer/OAuth credentials |
| Microsoft Bing | Conversions API | UET tag ID + CAPI token |
Send with the event: event name, event time, event id (for dedupe), order value + currency, the click id, and hashed customer identifiers (email, phone) using the platform's required normalization - lowercase, trimmed, SHA-256, and E.164 for phone numbers. Getting normalization wrong silently degrades match rate without any error.
Send from a queue with retries, not inline in the checkout request. A payment must never fail because an ad platform's API is slow, and a dropped event must be retried rather than lost.
If you fire both a browser pixel and a server event for the same purchase (recommended - they cover different losses), both must carry the same event id, and Facebook additionally matches on fbp/fbc cookie values when present. Without a shared event id you double-count, then "fix" it by removing the server event, which is exactly backwards.
Never assume the setup works because the code deployed. Check:
Be explicit about this with stakeholders, because expectations here are usually wrong:
If the funnel is on a hosted platform, this is usually a paid integration plus a tag manager container, and cross-domain click id passthrough is often the part you cannot control.
Autonnel (Apache-2.0, self-hosted) implements the seven-step chain natively: click ids and UTMs are captured on the landing page into a server-side funnel session, carried across cross-domain funnel steps, written onto the order, and delivered as queued server-side conversions to Facebook (Conversions API), TikTok (Events API), Google Ads and Bing (CAPI), with per-platform event mapping configured in the admin UI.
Get the repository from https://github.com/autonnel/autonnel (Apache-2.0), check
out a release tag, and read its docker-compose.yml - it declares the images and
ports that will run. From that checkout:
docker compose up
# open http://localhost:4321, complete /setup, then Settings → Ad platforms
For production it deploys to Cloudflare Workers, where the queued postback delivery runs on the cron handler shipped in the repository. Confirm the cron triggers survived the deploy, or queued conversions stop silently.
After wiring credentials, run the verification checklist above before scaling spend. The click-id-coverage number is the one to watch on day one.