CRM-LOGAM · META ADS / CONVERSIONS API

How Logam CRM feeds Meta Ads, and why it beats the usual setups

The CRM tells Meta which ad leads became real customers, so Meta finds more people who buy, not just more people who fill in forms.

As of 31 Oct 2026 · built from the code in lib/meta-capi.js, services/lead.service.js, lib/constants.js
i

Every pipeline move a rep makes sends a server-side Conversions API event to the account's own Meta pixel: Contact → Prospect → ConversionLead → Purchase, with the deal value. Meta then optimises campaigns for qualified leads and sales, and Ads Manager shows real ROAS instead of zero.

The problem it solves

"Our ads bring 500 leads a month but half are junk. Meta keeps finding more of the same people, because the only thing it ever sees is that someone filled in a form."

01· How leads arrive

Every lead is tagged with its source when it is created. The source decides which match signals the CRM can later send back to Meta.

SourceHow it reaches the CRMSignal that ties it back to the ad
Meta Instant Form
META_INSTANT_FORM
Meta's leadgen webhook in real time, plus a sync every minute as a safety netMeta lead_id (Meta's strongest signal for form leads) + hashed phone and email
Website form
WEBSITE_FORM
The site's form posts to the CRM; the browser pixel fires on the pagefbc / fbp cookies; fbclid rebuilt into fbc when the cookie is missing
Click-to-WhatsApp ad
WHATSAPP_AD
WhatsApp Cloud API webhook, or the Interakt routectwa_clid, the only link back to the ad, since these leads have no browser cookies at all
Pabbly, webhooks, portals, CSV, manualPer-account webhook URL, file import, or typed in by a repHashed phone, email, name, city, state, postcode, gender, date of birth where present

Campaign, ad set and ad names are resolved from Meta when the lead is created, so every lead in the CRM shows which ad it came from.

02· The feedback loop

Lead arrivesLeadReceived for form leads, Lead for sources Meta never saw
→
ContactedContact
→
Pre-QualifiedProspect
→
QualifiedConversionLead, the event Meta's Conversion Leads goal optimises for
→
ConvertedPurchase + deal value and currency

That is the default stage map. Each account can remap any of its statuses, including custom ones, to a Meta event in Settings → Meta. Junk, Disqualified and other negative statuses send nothing.

ASERVER TO SERVERgraph.facebook.com · v21.0

Events go from the CRM's server straight to Meta. No browser is involved, so ad blockers, iOS tracking limits and cookie banners cannot drop them.

BMARKED AS CRM EVENTSaction_source: system_generated

Each event carries event_source: crm and lead_event_source: Logam CRM, the shape Meta's CRM funnel expects. Meta joins it to the original lead through lead_id.

CDEDUPLICATEDevent_id = <lead id>_<event name>

The id is fixed per lead and event, never a timestamp. A retried send carries the same id, so Meta counts it once.

DSALE VALUEPurchase · value + currency

When a lead reaches the Purchase status, the rep is asked what the sale was worth. Skipping uses the account's default value, so the status change is never blocked. Before this, every conversion reached Meta as zero and ROAS read nothing.

03· Every lead counted once

A Meta Instant Form lead is already counted by Meta the moment the form is submitted. Website leads are counted by the browser pixel. So the CRM never sends Lead for those two sources. It sends the stages that follow, which is the part Meta cannot see.

17,380
duplicate conversions in 30 days when the CRM used to re-send Lead for form leads
10,590
real leads in the same 30 days
0
duplicates now: the second Lead is simply not sent

This cannot be fixed with deduplication. Meta's on-Facebook lead is not a dataset event and has no event_id to match against, so the only fix is not to send the second one.

LEAD COVERAGELeadReceived

Meta's Conversion Leads optimisation needs at least 60% of form leads to have a CRM event. With only stage events, leads left in New or closed as Junk sent nothing, and coverage sat around 20%. Now every Instant Form lead sends one LeadReceived on arrival. It is a funnel stage, not a new lead, so Ads Manager's lead count does not change. Leads synced more than a week late (such as history pulled in when a form is first connected) do not send it.

04· Match quality

An event only helps if Meta can match it to a person. What the CRM sends is normalised the way Meta hashes it, then SHA-256 hashed.

05· Reliability and safety

NEVER BLOCKS THE REP

The status change saves first. The CAPI send runs in the background, tracked so it finishes even after the response goes out. A Meta outage never stops a rep updating a lead.

RETRIES/api/cron/capi-retry · every 15 min

Each send tries up to 3 times with a 10-second timeout. Every attempt is written to CAPILog. A failed send is retried by the cron after 15, 30, 60, 120, 240 and 480 minutes, up to 6 times, then marked abandoned. The fixed event_id makes every retry safe.

YOUR PIXEL OR NOTHING

Events go only to the pixel or dataset configured on that account. With none set, nothing is sent; there is no shared fallback. One business's conversions never train another's ads.

SECRETS AND PRIVACY

Access tokens are stored encrypted, and the send refuses to run if a token is still ciphertext. Phone numbers, emails and tokens are never written to logs. Broadcast audience uploads send nothing, because those people did not just convert.

06· Setup per account

StepWhereWhat it does
1. Connect the Facebook Page and pick lead formsSettings → MetaLeads start flowing in real time
2. Add the Pixel / Dataset ID and access tokenSettings → MetaTurns CAPI on for this account only
3. Check the stage mapSettings → MetaDecides which status sends which event; custom statuses can be mapped too
4. Set currency and default purchase valueSettings → MetaMakes ROAS real when a rep skips the value prompt
5. Map form questions to match fieldsSettings → Meta → Form Field MatchingRaises match quality
6. Put LeadReceived first in the sales funnelMeta Events ManagerLets Conversion Leads optimisation count coverage correctly

Super admins see each account's CAPI health (missing pixel or token, failure rate with Meta's own error, unmapped custom statuses) and can test the pixel live with Check now.

07· Why this beats the usual setups

Most businesses running Meta lead ads use one of three setups. The comparison below is by approach, based on how each one works, not on any one vendor.

What mattersPixel onlyZapier-style relay to CAPITypical CRM with a Meta add-onLogam CRM
Tells Meta which leads became salesNo, sees only the form fillOnly if every stage is wired by handOften one "converted" eventEvery stage, mapped per account
Avoids counting form leads twiceYesOften re-sends LeadVariesNever sends Lead for form or website leads
Reaches the 60% lead coverage Meta needsNoRarelyVariesLeadReceived for every form lead
Survives ad blockers and iOS limitsNoYesYesYes, server to server
Click-to-WhatsApp ad leadsNo cookies to trackUsually missedRarely supportedSends ctwa_clid
Sale value for ROASNoIf added by handSometimesAsked at Purchase, default fallback
Retries without duplicatesNot applicableRetry often creates a second eventVaries6 retries, fixed event_id
Match quality tuningBrowser data onlyRaw fields as typedBasic hashingMeta's normalisation + form field mapping + coverage report
Extra cost and moving partsNonePer-task fees, another tool to breakAdd-on feesBuilt in
!

The difference that matters most: the CRM is where reps actually qualify leads, so it is the only place that knows which leads were good. Sending that straight from the CRM, counted once and tied to Meta's own lead_id, is what lets Meta optimise for buyers instead of form-fillers.

08· Limits to know

Sources: lib/meta-capi.js · services/lead.service.js (lead creation, status change, retry) · lib/constants.js (DEFAULT_STAGE_MAP) · app/api/cron/capi-retry · FEATURES.md §12. The duplicate figures (17,380 vs 10,590) are from the comment in services/lead.service.js recording the 30 days before the fix.