Sign in
By Variafy team / Updated 10 November 2026

How to track Meta Ads revenue in HubSpot: from test lead to payment

To track Meta ads revenue in HubSpot, each lead needs three things from the start: a campaign key, a payment record with its own date (not only a closed-won date), and one customer key. With those in place, you can export from HubSpot and compare receipts by lead cohort at day 7 and day 30. This guide follows one test lead from the ad click to its first payment, then shows how to check your export against the free Meta Ads CRM revenue report template, whose sample data gives you an answer key.

A test lead with the key meta-10001 leads to a 240 payment on day 2, which the report shows as 240 paid by day 7 and 560 by day 30.
On this page11 sections

What HubSpot shows by default, and what it does not

HubSpot records where a contact came from in its original traffic source properties. According to HubSpot’s documentation, for paid social the first drill-down shows the social site, for example Facebook, and the second shows the campaign name taken from utm_campaign. You can also edit the source on a contact by hand, and doing so clears the drill-downs. That makes it a useful clue but a weak key: it describes the first known source, and it can change.

For deals, HubSpot’s default deal properties say that moving a deal into a closed-won stage sets the close date to today, unless you turn that automation off. The deal amount is the total value of the deal. Neither tells you when each payment arrived.

HubSpot’s attribution reports for revenue and deal creation are limited to Marketing Hub Enterprise. Without that plan, a cohort report built from your own export fills the gap.

The report template needs these inputs. This is where each one comes from in HubSpot:

Template columnWhere it comes from in HubSpot
Lead dateThe date the lead was created or submitted the form. Pick one and keep it for every row
Campaign keyA custom contact property filled from utm_campaign at form submission, prefixed meta-
Customer keyThe contact record ID, or one ID per person after you merge duplicates
Payment keyThe payment record ID
Payment dateThe payment’s date property. Decide which one you use
AmountThe payment’s gross amount, in one currency

Closed won is not the same as paid

A deal in a closed-won stage says the sale was agreed. A payment record says money moved. HubSpot keeps the two apart, and a revenue report built on one answers a different question from a report built on the other.

  • Closed won is a deal stage. According to HubSpot’s default deal properties, moving a deal into a closed-won stage sets the close date to today, unless you turn that automation off. The deal amount is the total value of the deal. Neither carries the date of each payment.
  • A payment record has its own amount and its own date. HubSpot’s payments API also lets you associate it with a contact and a deal, and gives it a status such as refunded or partially_refunded.
Closed-won dealPayment record
The date it carriesThe day the deal moved stage, by defaultThe date of that payment
The amount it carriesThe total value of the dealThe amount of that payment
A customer who pays in installmentsOne amount and one dateEach payment has its own amount and date
RefundsNot visible in the stageVisible in the payment’s status
The question it answersDid the sale close?How much money arrived, and when?

Here is the difference on the test lead from step 2. The deal is moved to closed won on day 2 with an amount of 360. The customer pays 240 on day 2 and 120 on day 12.

Received byClosed-won deal saysPayments say
Day 2360240
Day 7360240
Day 30360360

The two views agree by day 30 but not before, and a cohort report compares campaigns at exactly day 7 and day 30. A report built on close dates would credit this lead with 120 more than had arrived by day 7. It would do the same for every customer who pays in installments, and it would not reflect refunds, which show up in a payment’s status.

Closed won is a fair stand-in only when customers pay the full amount on the day the deal closes and nothing is refunded. Check that against your payment records for a few months before you rely on it, and use payment records for the day-7 and day-30 numbers in the template.

Step 1: put the campaign key on the lead

Add the campaign to the ad’s link as a URL parameter, for example utm_campaign=meta-10001, where 10001 is the Meta campaign ID. The Facebook UTM parameters guide shows how to build links for every ad. Keep one format: a typo today becomes an unmatched payment later.

Then store it on the contact:

  • HubSpot forms. HubSpot documents that a hidden form field can capture a URL parameter such as utm_campaign and write it to a contact property when the form is submitted. It is available on all products and plans. A required field cannot be hidden, and for returning visitors a pre-populated hidden value may be overwritten, so test with a returning contact too. HubSpot’s page does not say whether the property must exist first, so create a custom single-line text contact property for the key before you add the field.
  • Meta lead ads synced into HubSpot. HubSpot’s lead sync is available on all plans and can take up to two hours to deliver new leads. The page does not say which properties it sets or whether campaign data is stored, so do not assume the key arrives. Check a synced test lead in step 2. If the campaign is missing, see how to match CRM payments to ads and the built-in CRM options for lead ads.
  • Forms outside HubSpot. HubSpot’s hidden-field page does not describe embedded or non-HubSpot forms. Test the exact form your landing page uses.

Step 2: follow one test lead

Use a clearly fake test contact, for example test+meta-10001@yourdomain.com, and delete it afterwards. The report template’s sample shows what to expect, so use its first customer, c-01.

  1. Create the lead. Open your ad link with utm_campaign=meta-10001 and submit the form. For a lead-ad test, submit the lead form and allow up to two hours for the sync.
  2. Check the contact. The campaign key property should say meta-10001. The create date is the lead date you will use. Original traffic source should show paid social with meta-10001 as the second drill-down; if it shows something else, note what it shows, because sources can differ.
  3. Create a deal and associate it with the contact.
  4. Record the payments. A first payment of 240 two days after the lead and a second of 120 twelve days after the lead. Step 3 explains how to record payments.

This customer is the first row of the template’s sample. In the report, the September 7 lead week for meta-10001 shows 240 paid by day 7 and, together with the other customers in that cohort, 560 by day 30.

If you also move this deal to closed won on day 2, compare what the deal says with what the payments say: closed won is not the same as paid.

Step 3: record payments, not only won deals

Pick the option that matches how you get paid:

  1. HubSpot payment records. HubSpot’s payments API describes payment objects as a way to track revenue collected outside HubSpot’s own processing. A payment needs an amount (hs_initial_amount) and a date (hs_initiated_date), and it can be associated with a contact, a deal and an invoice. Statuses include partially_refunded and refunded. You can export payments from Revenue > Payments and choose the properties and associated records (HubSpot’s documentation). The documentation does not say whether several payments can be linked to one deal, how installments should be recorded, or which plans and countries can use payments, so test this in your own portal.
  2. Your billing or accounting system as the source. Export one row per payment from the system that holds the money, and join it to HubSpot contacts by a customer key such as an email or an ID you store on the contact. This is the safest option when installments are involved.
  3. One deal per payment. This can work for a few large sales. It makes cost per customer harder to read.

Decide which date you will call the payment date. HubSpot’s hs_initiated_date is the date the payment was initiated, and a separate payout date records bank deposits. Use the date you treat as the day the money arrived, and use it consistently.

Step 4: export from HubSpot and fill the template

Export the contacts (record ID, create date, campaign key) and the payments (payment ID, amount, date, associated contact), then paste values into the CRM Payments tab of the template:

CRM Payments columnFill with
Payment keyThe payment record ID, with a text prefix such as p-
Customer keyThe contact record ID, with a text prefix such as c-
Campaign keyThe contact’s meta- key. Leave it blank when the source is unknown
Lead dateThe contact’s lead date, the same for every installment of that customer
Payment dateThe date you chose in step 3, in the report time zone
AmountGross amount in the report currency. Keep refunds on a separate list

Then fill the Report tab: one row per campaign and Monday-starting lead week, with the ad spend and leads for that same week from Ads Manager. Use one currency and one time zone throughout. The template holds up to 50 campaign-week rows and 300 payment rows.

If you also saved the original ad ID in HubSpot, include it in your joined payments export. The free attribution checker compares it with an ad-level Meta export.

Step 5: reconcile your result

Check 1: the answer key

Before you use real data, paste the template’s 12 sample payment rows and confirm that you get the same report. This proves that your copy and your date handling work.

Lead week and campaignPaid by day 7Paid by day 30Customers by day 30Cost per day-30 customer
Sep 7 · meta-10001 (spend 360)2405602180
Sep 7 · meta-10002 (spend 300)2004002150
Sep 14 · meta-10001 (spend 450)06002225
Oct 12 · meta-10001 (spend 120)Still collectingStill collectingStill collectingStill collecting

Matched receipts through the as-of date, October 20, 2026, come to 1,740. Unmatched receipts come to 150: one payment with no campaign key and one with a key that does not appear for that lead week. Payment p-06 arrives on day 7 and counts, because the window counts the lead date as day zero.

Check 2: your own data

  • Matched plus unmatched receipts should equal total valid payments through the as-of date in your billing or accounting records for the same period.
  • “Payment rows to fix” in the Report tab should be zero.
  • Customers by day 30 should equal the number of distinct customers who paid within 30 days of their lead date.
  • A cohort that has not had 7 or 30 days to pay should be blank, not zero.

Check 3: when the numbers do not match

What you seeLikely causeWhat to do
Large unmatched receiptsThe key was never captured, was captured on a different property, or changed formatCheck the form and link for those leads. Fix the key, not the totals
A customer counted twiceDuplicate contact records for one personMerge them, or give the payments one customer key
Day 7 is zero and day 30 is filledNormal for slow payers, as in the September 14 row of the sampleWait for the window. Do not judge the campaign early
HubSpot revenue by close date differs from the templateClose date is not the payment date, the deal amount is not the money received, or refunds are involvedReconcile against payment records, not deal amounts
Totals differ from accountingRefunds, a currency mix or time zone differencesUse one currency and time zone, and list refunds separately

Step 6: read the result

Compare cost per paying customer, not only cost per lead. In the template’s sample, campaign meta-10001 costs $15 per lead and campaign meta-10002 $20, but meta-10002 costs less per paying customer ($150 against $180).

Do not compare cohorts of different ages. The lead-to-payment lag case study shows how much of the money can arrive after day 7. For targets, see cost per qualified lead.

When to automate this

If you do not want to export every week, Variafy’s HubSpot connector reads your deals, their stages, pipelines and deal properties with a read-only key. It works from deal stages, not from HubSpot payment records, so check how your sales are recorded before you compare its numbers with this report. Use the same cohort definitions as this guide when you compare the two.

How we checked

We checked HubSpot’s behavior against its own documentation on November 10, 2026: traffic source properties, hidden form fields, Facebook lead sync, default deal properties, the payments API and payments management, and attribution reports. Where a page does not say how a feature works, this guide says so and asks you to check it in your own portal. All figures are fictional data from the report template. The guide covers HubSpot and Meta Ads; other CRMs work differently.

Questions

Does HubSpot show Meta ads revenue on its own?

Only through its attribution reports, which HubSpot lists for Marketing Hub Enterprise. Without that plan, you can build the same view from an export, as in this guide.

Can I use the closed-won deal amount instead of payments?

You can for a rough count, but it hides timing and installments. Close date is when the deal moved stage, not when the money arrived, so use payment records for day-7 and day-30 numbers.

What about leads created before I added the campaign key?

Leave the campaign key blank for them. They appear as unmatched receipts when they pay, which is the correct picture: it shows how much revenue you cannot trace to a campaign.

Where do refunds go?

Keep them on a separate list. The template counts gross receipts and does not subtract refunds. HubSpot marks refunded payments with a status, which you can use to filter the export.

Related guides