Conversions go to the ad platforms straight from the server, and the team's report builds itself
Apple limits tracking in iOS and Safari, so the pixel on the page misses some purchases, and the media buying team makes decisions on incomplete data. In this setup Keitaro, a system that tracks clicks and sales, collects every click and conversion on your own server. From there, conversions go to Facebook, TikTok and Yandex Metrica through their server-side interfaces (CAPI). The Metabase reporting tool shows return on ad spend, and Telegram alerts tell the team about losing ads.
The team sees how the ads did only the next morning
For the estimate, take a team of six media buyers. Ads run on Facebook, TikTok and Yandex Direct at the same time, and each platform counts conversions in its own way.
Safari shortens the life of cookies, and on the iPhone many people tell apps not to track them. Some purchases never reach the ad account. The ad account shows one picture, Yandex Metrica another, and the CRM a third. Exactly how many go missing varies from business to business.
Every morning each media buyer reconciles the data by hand: exports stats from the ad account to Excel, checks them against Metrica and the CRM, and only then decides what to switch off and where to add budget. Say this takes 2–2.5 hours. Decisions happen once a day, and an ad that has stopped paying off keeps spending until the next reconciliation.
One source of data on your own server
Keitaro receives every click and conversion and gives each event its own ID (event_id). A layer on nginx with Lua filters out duplicates and sends the events to the three platforms through their server-side interfaces. Metabase reads Keitaro's data directly, so return on ad spend is visible right away, with no manual exports.
Keitaro runs on your own server, receives every click and filters out bots. Tracking runs on dedicated domains. A second server backs up the main one.
The landing page, CRM and payment provider report the sale straight from the server, with the same event ID.
Filters out duplicates by event ID, adds the fbclid, ttclid and yclid click IDs and prepares data for each platform.
Facebook Conversions API, TikTok Events API and Yandex Metrica's Measurement Protocol receive the events at the same time.
A return-on-ad-spend report for each media buyer, country and ad set. If spend passes a threshold with no conversions, a Telegram alert goes out.
Keitaro is the single source of data
All clicks from all platforms go through Keitaro. Each click gets its own ID and a browser cookie, and is tied to its campaign, ad set and creative. Keitaro runs on your own VPS, and I size the server to your click volume. A second server with another hosting provider backs up the main one if it fails.
Conversions go to the platforms straight from the server
The landing page, CRM or payment provider reports a conversion to Keitaro from its own server. The nginx and Lua layer filters out repeated notifications about the same sale, adds the click IDs fbclid, ttclid and yclid and prepares three sets of data, one for each platform. Facebook Conversions API, TikTok Events API and Yandex Metrica's Measurement Protocol receive them directly. Facebook also sees the same purchase through the pixel on the page. The server event and the pixel event share one event ID, so Facebook counts the purchase once.
I've already set up similar delivery for two Shopify stores: Keitaro receives the sale from the server, and the purchase goes to Facebook with the same event ID as the pixel. The details are in the case study End-to-end attribution for two Shopify stores.
Metabase shows returns right away, with no exports
Metabase connects directly to Keitaro's statistics database, which also pulls in spend from the ad accounts. Each media buyer has their own report: return on ad spend for each ad set over the last 6, 24 and 72 hours, broken down by country, creative and placement. A media buyer opens the report and sees at once what would otherwise take a manual pass in Excel.
Telegram alerts: a losing creative shows up the same day
Every 30 minutes a script checks fresh spend in the ad accounts against conversions in Keitaro. The media buyer gets a Telegram alert in two cases: spend has passed a threshold with no conversions, or a lead has become noticeably more expensive than the average for recent days. The team sets both thresholds.
Tracking on the server from click to payment
The single source of data: clicks, conversions, event IDs, bot filtering, campaigns
Sends conversions to Facebook ads from the server; duplicates from the pixel are filtered out by the shared event ID
Sends events to TikTok ads from the server, with the ttclid and hashed user data
Sends conversions from the server to Yandex Metrica and Direct
The middle layer: filters duplicates, adds click IDs, sends to all three platforms at once
Stores clicks and conversions; the Metabase reports are built from it
Return on ad spend by media buyer, country and ad set, with no manual exports
Runs Keitaro; sized to your click volume
Sits with another hosting provider and backs up the main one if it fails
Alerts to media buyers: spend over the threshold with no conversions, or cost per lead too high
What to expect after launch
The figures are worked out for the same team of six media buyers. Each card shows how it usually goes today, then the target. For your team I'll recalculate everything after a review.
per media buyer: the Metabase report builds itself
a day freed up across six media buyers, if each spends 2–2.5 hours reconciling
between checks: a losing ad shows up the same day
How many conversions server-side tracking will bring back can't be calculated in advance. It depends on how many buyers come from iPhones and Safari, whether orders carry an email or phone number, and which platform the ads run on. So the work starts with a reconciliation: I take a month of orders from the CRM and compare them with the conversions in each ad account. The gap is what the browser pixel is missing.
When a platform receives more conversions, its algorithm learns from fuller data and finds similar buyers more accurately. The whole history of clicks and conversions stays on your own server, and you can build a new report from it at any time.
How long the launch takes and what it requires
from the start of work to launch. The exact time depends on the number of platforms and on how the CRM and payment provider report a sale
worked out after a review: how many platforms, where conversions come from and how much traffic you get
to the ad accounts, CRM and payment provider, plus a Keitaro license
When you need server-side conversion tracking
It helps wherever tracking limits in iOS and Safari have broken the usual setup with a pixel on the page and decisions about ads are made every day:
- → Ad agencies and in-house buying teams that need server-side conversion delivery and end-to-end tracking from click to payment
- → Online stores that buy ads on Facebook, TikTok and Yandex at the same time
- → Media and content projects, where ad accounts get limited data from the browser and miss some conversions without server-side data
- → Subscription services with a trial period, where payment comes 14–30 days later and the browser cookie is long gone by then
- → App developers advertising on Facebook and TikTok: on iOS, Apple's built-in attribution (SKAdNetwork) doesn't see everything
- → Sales through a call center, where the conversion is a call 2–7 days after the click
- I deploy Keitaro on your own domains and set up bot filtering
- I connect Facebook Conversions API, TikTok Events API and Yandex Metrica's Measurement Protocol
- I add a middle layer on nginx with Lua that filters out duplicate events
- I build Metabase reports: return on ad spend by media buyer, country and ad set
- I set up Telegram alerts for spend without conversions and for leads that have become too expensive
- I train the team and leave a runbook: what to do in typical failures and how to switch to the backup server
Related cases
Weekly client reports that put themselves together
Every Monday a workflow in n8n, an automation tool, pulls the numbers for all eight clients from Facebook…
From speech to a finished ad: transcription, translation, a new voice-over and lip-sync
Whisper transcribes the speech, GPT-4o translates the script and rewrites it for the market, ElevenLabs…
GMBSPYLAB: from the Facebook Ad Library to a Telegram feed
Async Python and Postgres 16. Every day 30–75k ads come in from the public Facebook Ad Library, and each…
Tell me where your ads run and where you track sales. I'll map out the tracking setup for your team
You can start with the 5,000 ₽ audit: a written report and a payback estimate.
Or just ask a question. During business hours I reply within 2 hours