Keitaro tracker + CAPI: attribution 62% → 96% and ROAS +18%
Performance agency with an in-house media-buying team and a $400-900k/mo media budget. Six media buyers were working blind: after iOS 17.4 and SKAdNetwork v5, attribution dropped to 62%. Deployed server-side Keitaro + CAPI across three platforms, restored attribution, and removed the daily manual report-building.
Media buyers optimise blind, ROAS lags 36-48 hours
Performance agency with an in-house media-buying team: six media buyers running several niches at once, $400-900k/mo media budget. Buying runs on FB, TikTok and Yandex.Direct simultaneously — each platform with its own attribution quirks.
After Apple rolled out iOS 17.4 and FB hard-switched to SKAdNetwork v5, about 38% of conversions stopped reaching Ads Manager — partly lost to Safari cookie blocking, partly to shared signal loss. Media buyers saw one picture in the ad account, another in Metrika / GA, and a third in CRM.
Every morning each buyer spent 2-2.5 hours reconciling data by hand: FB account → Excel → join with Metrika → join with CRM → decide what to switch off and where to add budget. Across the team — 15+ hours of report-building every day. On top of that, return on ad spend (ROAS) arrived 36-48 hours late — so a creative that had already gone unprofitable kept running for another day and a half.
Keitaro + server-side CAPI fan-out across all 3 platforms
Architecture — "server-side single source of truth". Keitaro receives all clicks and conversions, attaches a unified event_id, and via an nginx+Lua proxy layer fans out to three platforms' CAPIs with proper deduplication. Metabase reads Keitaro directly — live ROAS without manual exports.
Selectel + KingsHost VPS 32GB. 1.2M clicks/day, first-party tracking domains, bot-traffic filtering.
Server-to-server postback from landing / CRM / payment provider. Single event_id.
Dedup by event_id, enrichment with fbclid/ttclid/yclid, building payloads per CAPI.
FB CAPI Gateway + TikTok Events API + Yandex Measurement Protocol — in parallel.
Live ROAS dashboard per buyer, country and creative-landing combination. Telegram alerts when $X is spent with no conversions.
Keitaro as single source of truth
All clicks from all platforms pass through Keitaro: each click gets a unique event_id, sticky cookie + IP fingerprint, bound to campaign / adset / creative. Selectel VPS 32GB handles peak 1.2M clicks per day, KingsHost is the backup edge node for geographic distribution and failover.
Server-side CAPI fan-out
A conversion from landing / CRM / PSP arrives at Keitaro via server-to-server postback with the same event_id. The nginx+Lua layer dedups (FB likes to send the same events via pixel — they must be marked as duplicate), enriches fbclid / ttclid / yclid and builds three parallel payloads per platform. FB CAPI Gateway, TikTok Events API, Yandex Measurement Protocol — all return server-side signals to the platform.
Metabase: live ROAS without exports
Keitaro writes to PostgreSQL, Metabase reads directly. Dashboards per media buyer: ROAS for each creative-landing combination over the last 6 / 24 / 72 hours, broken down by country, creative and placement. Nobody builds the morning report by hand any more — the buyer opens the dashboard and sees what used to take 2.5 hours to assemble in Excel.
Telegram alerts: losing creatives caught in 4 hours, not 36
A scheduled job reads Keitaro every 30 minutes and checks: if more than $X has been spent with no conversions, or cost per lead (CPL) has risen more than Y% against the rolling window, a Telegram alert goes to the buyer. Average time to switch off a losing creative dropped from 36-48 hours to 4 hours.
Server-side all the way
Single source of truth: clicks, conversions, event_id, bot filtering, campaigns
Server-side Conversions API for FB Ads with auto-dedupe against pixel
Server-side events for TikTok Ads, enriched with ttclid and hashed PII
Server-side offline conversions to Yandex.Direct / Metrika without JS
Proxy layer: dedup, enrichment, parallel payload fan-out
Keitaro click/conversion storage — base for Metabase queries
Live ROAS dashboard per buyer, country and creative-landing combination — no manual exports
Primary Keitaro node — handles 1.2M clicks/day
Backup edge for geographic distribution and failover at peak
Buyer alerts: $X spent with no conversions, CPL up Y% against baseline
What changed in 60 days
conversions return to platforms via CAPI
from budget going negative to the creative being switched off
over 60 days at the same media budget
per buyer — Metabase shows the live picture
setup + monthly (hosting + maintenance)
The +18% ROAS effect is the sum of two secondary effects: (1) platforms optimise lookalike audiences on complete data and do better on their own; (2) buyers switch off unprofitable creatives 9× faster. The sum is +18% over 60 days.
A side benefit — a closed data perimeter. After SKAdNetwork v5 many buyers moved to "blind" aggregated event measurement; here the team sees conversions per creative-id with a minute's delay. That's a qualitatively different operating model.
When you need a server-side tracker
Universal pattern — "media budget > $50k/mo and attribution has started to leak". Wherever iOS 17.4 / SKAdNetwork v5 / Safari ITP / Chrome 3rd-party cookie deprecation have broken classic pixel schemes:
- → Performance agencies and in-house buying teams — wherever you need server-side conversion delivery and end-to-end attribution from click to payment
- → E-commerce brands with in-house media buying — FB + TikTok + Yandex simultaneously
- → Subscription services and media — where ad platforms cut client-side tracking and optimisation goes blind without server-side data
- → SaaS with a complex funnel — where conversion = trial → paid in 14-30 days (cookies died long ago)
- → App developers — FB + TikTok on iOS/Android, SKAd v5 doesn't cover 100% of cases
- → Lead-gen funnels — where conversion = call center call (2-7 days after click)
- Keitaro deployment on first-party tracking domains with bot-traffic filtering
- FB CAPI Gateway + TikTok Events API + Yandex MP connection
- nginx+Lua proxy layer with event_id deduplication
- Metabase dashboards: live ROAS per buyer, country and creative-landing combination
- Telegram alerts: switch a creative off, or add budget to it
- Team training + runbook for typical failover incidents
If media budget is > $50k/mo and attribution is leaking — server-side fixes it
780k setup + 38k/mo maintenance. By week 6 media buyers have live ROAS, by day 60 — measurable uplift. Suitable for in-house media-buying teams + performance agencies. Guaranteed > +12% to attribution even on conservative funnels.
Related cases
Speech-to-Creative: speech recognition + language swap + lip-sync
Whisper transcribes speech → GPT-4o translates into 5+ languages and rewrites the lines for the on-screen…
GMBSPYLAB — collecting the public FB Ad Library into my own Telegram feed
Async Python and Postgres 16: 30–75k raw cards a day, perceptual dedup leaves 5–12k unique ones, arq queues…
End-to-end attribution: from ad click to order
A stdlib middleware takes Shopify webhooks, verifies HMAC, fires an S2S postback to the tracker and a…
The 9,900 ₽ audit — with a concrete report and quote
I'll tell you what to deploy in your business first, what the payback looks like, and whether you need AI for the task at all (sometimes you don't).
Or just send your question — I reply within 2 hours