Most local businesses running ads have exactly one conversion wired up. The contact form. Somebody fills it out, the ad platform counts a conversion, everybody nods.
Then the ad account starts doing something quietly expensive. It goes and finds you more of whatever produced that form fill, because that is the only outcome you ever told it to care about. Tire kickers count the same as a signed job. A wrong number counts the same as a $9,000 install.
You end up with a beautiful cost per lead and a business that is not making more money.
The fix is not a better ad. It is telling the ad platform what actually happened after the lead came in. This guide covers the whole thing, for both Google Ads and Meta, in two parts. Part one is lead tracking, so the platform knows a real human arrived. Part two is ROI tracking, so it knows how much money that lead turned into.
The three signals worth tracking
Every lead reaches you one of two ways, and every lead either turns into money or does not. That gives you three things to report back.
| Signal | Fires when | Value sent |
|---|---|---|
| Lead from a form | Somebody submits a form | Optional or estimated |
| Lead from a call | A tracked call runs long enough to be real | Optional or estimated |
| Customer Paid | An invoice actually gets paid | The real amount collected |
- Fires when
- Somebody submits a form
- Value sent
- Optional or estimated
- Fires when
- A tracked call runs long enough to be real
- Value sent
- Optional or estimated
- Fires when
- An invoice actually gets paid
- Value sent
- The real amount collected
The first two tell the platform "this ad produced a human." The third tells it "this ad produced money." Smart Bidding on Google and Advantage bidding on Meta can only optimize toward what you feed them, so if you stop at the first two, you have asked them to buy leads, not customers.
Seedly is built to send all three, from forms, from tracked phone calls, and from paid invoices, to Google and to Meta. Here is how to turn it on.
Part 1. Lead tracking
Step 1. Connect your ad accounts
Google Ads. Open Settings and Integrations, find the Google Business card, and connect your Google account. That single connection covers Analytics, Search Console, and Ads. Once it is connected, pick which Ads account to link. The connected user needs standard or admin access on the Google Ads account, not read-only.

Meta. Open Settings and Integrations, find the Meta Conversions API card, and paste two values. Your Pixel ID (Meta now labels this a Dataset ID inside Events Manager, it is the same number) and a CAPI access token. Both live in Meta Events Manager under your dataset's Settings tab. Use the Send test event button to confirm the connection lands before you go further.

Step 2. Create the conversion actions
This part happens inside Google Ads and Meta, not inside the CRM, and it is where most people go wrong.
Google Ads
A conversion action is the bucket Google counts into. You create it. The CRM fires at it.
Because Seedly sends conversions from your server (not from a browser tag), you have to create the right type of conversion action. In Google Ads, go to Goals, Conversions, New conversion action, and choose Import, then Manual import using the API or uploads. This creates an offline conversion action of the type the CRM can send to.
Do not create a Website or a Phone-call conversion action. Those cannot receive server-sent conversions, and the CRM will not be able to deliver to them.
Make two.
- Lead, for form fills and qualifying calls. A good goal category here is Qualified lead or Converted lead.
- Customer Paid, for actual revenue.
While you are in the settings for each action, set the count to Every, leave the click-through conversion window at its default (Google commonly allows up to 90 days), and choose Data-driven or Last click attribution. Once you have a steady flow of paid customers, mark Customer Paid as your primary conversion so bidding targets return on ad spend.
[📷 Screenshot 3: Google Ads, New conversion action, the Import then "Manual import using the API or uploads" choice. Take this in your own Google Ads account.]
[📷 Screenshot 4: The Google Ads conversion action settings panel, Count set to Every and the attribution model. Take this in your own Google Ads account.]
Meta
Meta does not use per-account conversion actions the way Google does. It uses standard event names on your dataset. You do not create anything ahead of time. The CRM sends a Lead event for form fills and qualifying calls, and a Purchase event when an invoice is paid, and those events show up in Events Manager on their own.
One thing to turn on in Google Ads while you are there, because it raises your match rate. In your Google Ads account settings, accept the customer-data terms and turn on enhanced conversions for leads. That lets Google match a conversion back to the click using hashed contact details instead of relying purely on cookies. Meta does the equivalent automatically when you send hashed details, which the CRM already does.
Step 3. Capture the click, or nothing else matters
Before any conversion can be credited to an ad, the lead has to arrive carrying the click identifier. On Google that is the gclid (plus gbraid and wbraid on newer campaign types). On Meta it is the fbclid. Without one of these, the platform has no way to tie the conversion back to the ad click, and the conversion is dropped.
Two things make sure that identifier arrives.
Turn on auto-tagging in Google Ads. In your Google Ads account settings, confirm auto-tagging is on. This is what appends the gclid to your landing page URL.
Install the tracking template. In the CRM, open Settings and Integrations, go to the connected Google card, find the Conversion Tracking section, and copy the Tracking template. Paste it into Google Ads under Settings, Account Settings, Tracking, Tracking template. This one field captures the click ID and your campaign names on every ad click, so the CRM can match conversions back to the exact campaign later.
![]()
The Conversion Tracking section only appears after you have selected an active Ads account, so pick your account first if you do not see it.
Meta's fbclid rides in on the ad URL automatically, and the CRM captures it. There is no template to paste for Meta.
Step 4. Form fills
This is the easy part and it needs no automation at all.
Open the form in the builder, go to the Settings tab, and open the Tracking section. Turn on the platform you want.
- Google Ads. Turn on "Send conversion when this form is submitted" and pick your Lead conversion action from the dropdown, which is populated live from your Google Ads account.
- Meta. Turn on "Send Meta CAPI event when form submits" and leave the event name as Lead.
You can set a value override on either, or leave it blank to send no value for a lead. That is fine. Leads are counted, revenue comes later.
![]()
The part that matters and that you do not have to configure is the click ID. When somebody lands on your site from an ad and submits the form, the CRM reads the gclid or fbclid from the page and stores it on the new contact. That is what lets a conversion three weeks from now still get credited to the ad click that started it.
One important note about embedded forms. If you embed a Seedly form on your own website, re-copy the embed code from the form's Share panel after setting this up. The current embed code passes the ad click details from your page through to the form. An older embed does not, and a lead that comes through it will look like it came from nowhere. Forms hosted on the Seedly page already capture everything.
Step 5. Phone calls, and why you need dynamic number insertion
Here is where most setups quietly fall apart.
If the same phone number sits on your website for every visitor, a phone call is an anonymous event. Somebody called. You have no idea whether they came from an ad, a Google Maps listing, or a fridge magnet from 2019.
Dynamic number insertion fixes that by swapping the number on the page depending on who is looking at it. Ad traffic sees one number, organic traffic sees another. Because the number is different, the call itself carries the attribution.
Setting it up takes a few pieces, under Settings, Integrations, Phone and Voice, Tracking.
Turn on call tracking, then create a tracking pool and assign several phone numbers to it. Four or more numbers gives the most accurate visitor-level attribution.
Set the match rules so the pool applies to the right visitors. You can match on the Google click ID being present to catch all Google Ads traffic, on the Facebook click ID for Meta, or on any UTM combination for a specific campaign. Pools are checked in priority order, and you can flag one as the default so visitors who match nothing still see a sensible number.
Turn on DNI, enter the Website URL where the script runs (this now registers your site for number swapping, no developer needed), and give it a CSS selector pointing at the element that holds your phone number. Grab the embed code from the pool's Get embed code button and put it on your site.

Then turn on conversion tracking for the pool. You get both platforms here too.
- Google Ads, "Send conversion when call qualifies", pick your Lead conversion action.
- Meta CAPI, "Send Meta CAPI event when call qualifies", event name Lead.
Both have a Qualify after setting measured in seconds. This part is worth caring about. Without a duration threshold, a two-second misdial reports as a conversion and you have taught the platform that wrong numbers are a good outcome. Pick a length that means a genuine conversation for your business and let short calls fall through.
![]()
Part 2. ROI tracking (closing the loop)
Everything up to now still only reports leads. This part is the one almost nobody does, and it is the one that changes what the ad platform actually buys.
The Customer Paid workflow
Every sub-account already ships with two ready-made workflows, one called Google Ads, Customer Paid (revenue tracking) and one called Meta CAPI, Customer Paid (revenue tracking). Both arrive switched off, sitting in draft, waiting on you.
The shape of each is two steps. An invoice gets paid, and a conversion fires. The value it sends is not a guess or a flat number. It is the amount actually paid, including tip, late fees, and processing fees, pulled straight from the invoice that just got paid, along with its currency.
To turn on the Google one, open it, pick your Customer Paid conversion action in the node, and switch it from draft to published. To turn on the Meta one, open it, confirm the event is Purchase (the default), and publish it. That is the whole job.
They stay in draft until you activate them, which is deliberate, because a workflow firing at nothing is worse than one that never ran.

Now the loop is closed. Google sees the ad click, the lead, and the $9,000 that showed up eleven days later, and it can go find more clicks that look like that one. Meta gets the same Purchase signal against the same visitor.
How the money finds the ad click, weeks later
The click ID captured at lead time is stored on the contact record and never expires. When an invoice for that contact is paid, the workflow reads the click ID off the contact and sends the paid amount to the platform, tied to that original click. You do not have to do anything to connect them. The CRM keeps the thread.
A note on Meta, because it works a little differently
Meta's Conversions API sends events from the server, which is exactly what the CRM does after a form is accepted or an invoice is paid. That is the modern, recommended way, and it is more durable than a browser pixel that iOS and ad blockers keep degrading.
For a lead-generation business, the cleanest setup is to let the CRM own the conversion events (Lead and Purchase) through the Conversions API, and, if you also run a Meta Pixel on your website, use that Pixel only for top-of-funnel signals like page views and for building retargeting audiences. Do not fire Lead or Purchase from both the browser Pixel and the CRM for the same event, or Meta may count it twice. Keeping the conversion events on the CRM side and the page-view signals on the Pixel side means there is no overlap and nothing to deduplicate.
The CRM sends hashed email, phone, name, city, state, and zip with every Meta event, plus the fbclid when it is present, which is what gives Meta enough to match the event to a real person.
A few things that will bite you
Double counting on Google. Forms, workflows, and call pools are tracked separately on purpose, so one lead can trigger more than one signal without inflating your numbers. You do not need to build guards against it.
Reconnecting Google. Google occasionally updates the permissions it requires to receive conversions. If your Google conversions stop appearing and nothing else changed, reconnect Google from Settings and Integrations before you start tearing the setup apart.
Accepted is not matched. When the CRM sends a conversion and the platform accepts it, that means the request landed, not that it was matched and counted. Both Google and Meta show the matched result in their own dashboards a day or two later. Judge the setup there, not on the instant the CRM fires.
The lag is real. Revenue conversions land whenever the invoice gets paid, which might be well after the click. That is the whole point of offline conversion tracking, but it does mean the numbers in your ad account keep filling in behind you. Judge a campaign on a window that has had time to settle rather than on yesterday.
What changes once it is running
You stop optimizing for the cheapest lead and start optimizing for the most profitable one. Those are frequently not the same campaign, and until the revenue signal is flowing you have no way of knowing which is which.
Most accounts discover the cheap-lead campaign they were proud of produces almost nothing, and the expensive one they nearly paused pays for everything else.
You cannot see that with a form-fill conversion. That is the whole reason to do the rest of it.


