A lead campaign gets cheaper every week. Cost per lead down 40%. Sales, unchanged.
The instinct is to look for a bug — bad tracking, a broken CRM sync, an operator not calling back. Usually there is none. The account is working exactly as instructed.
Facebook optimises toward whatever you tell it success looks like. If the only thing you ever report back is "a form was submitted", it will go and find the people most likely to submit forms cheaply. Those people exist in large numbers. Very few of them buy anything.
The signal you are not sending
Ad platforms are guessing most of the time. Cookies are gone or blocked, click ids get dropped, email matching is probabilistic, attribution windows are a polite fiction. Everyone has made peace with that.
Lead Ads are the exception, and it is worth appreciating how unusual it is.
Every submission arrives with a leadgen_id. When you later send a server-side conversion event carrying that same id, the join is deterministic. Not "we think this hashed email is probably that user" — literally the identifier the platform handed you, given back. No cookie, no pixel in a browser, no identity resolution.
Almost nobody running lead ads uses it.
Two events, and only one of them is interesting
Lead received. Fire when the lead lands and passes validation.
Status changed. Fire when the order actually moves — confirmed, delivered, cancelled.
Teams ship the first one, see no change, and conclude the integration does not work. Of course it does not: "a lead arrived" is the one fact the platform already had. You have told it nothing.
The second event is the whole point, and it is inconvenient in a specific way — it arrives days later, because that is how long it takes a human to answer a phone, confirm an order and have a courier deliver it. An integration that only handles same-request events cannot express it. You need somewhere to write the outcome when it eventually shows up, and something that walks those outcomes and sends them.
Make it idempotent twice
Status transitions repeat. Dispatchers re-scan. Order events get written twice by two paths that both thought they were first. Send a conversion twice and you have quietly doubled a number an optimiser is now steering on.
The pattern that has held up:
dedupe_key = f(lead_id, event_type) -- deterministic, no timestamps
Put a UNIQUE constraint on it in your own table, and hand the same value to the platform as the event id. Now suppression exists in two independent systems: your insert fails on the second attempt, and if one ever slips past, the platform discards it as a duplicate event. Two boring guards beat one clever one.
Deriving the key from anything time-based defeats the entire thing. It has to be a pure function of what happened, not of when you noticed.
The multi-tenant trap
A dataset belongs to one ad account. Send an event about a lead belonging to a different account and you get no error, no warning, no failed response — the data is simply ignored.
This is the worst possible failure mode: everything looks healthy, dashboards show events flowing, and none of them teach anything. If you run this for multiple advertisers, scope every send to the owning account's own dataset with the owner's own credential. A shared or default credential will produce a system that looks fine and does nothing.
What to expect, and how to not misread it
Slowly. The optimiser needs a meaningful number of conversion events to learn from, and that is bounded by real order volume and real fulfilment time — not by your deploy.
Then the shape changes rather than a single number:
- Cost per lead goes up. Fewer cheap form-fillers.
- Number of leads goes down.
- Cost per order goes down, which is the only one that was ever paying anyone.
If cost per lead is still the metric on the wall at that point, this integration will look like it broke the account. Change the metric before you ship the feature, or you will roll back something that was working.
That is the same lesson as everywhere else in this work: the number worth reporting is the one you would defend, not the one that looks best.
We build this at Targenix — free Facebook and Instagram lead automation for Uzbekistan. The Conversions API mechanics are written up in more detail here, the whole platform is mapped here, and the destination list is at targenix.uz/integrations.
Top comments (0)