The CRM and the Warehouse
Analytics stops at the visit. How your values reach the lead, the deal and the revenue: hidden form fields, first, last or every touch, and the join that puts spend and revenue on one row.
On this page
Here is a lead record from Stride’s CRM, as it would have arrived had the sign-up form stayed as it was:
| Field | Value |
|---|---|
| First name | Maya |
maya@example.com | |
| Form | 10% off your first order |
| Signed up | the sale’s second week |
| Source | empty |
| Medium | empty |
| Campaign | empty |
Where did Maya come from?
You can’t say. Neither can anyone at Stride who opens this record, today or in a year.
Chapter 6 left the spring sale in good shape, and ended on a question. The names match the links. What happens when a visitor becomes a lead?
This record is what happens, unless something is built to stop it.
It’s easy to treat the campaign report in analytics as the whole answer. It shows which campaigns brought visits and conversions, so the job ends when the link is tagged.
But the lead, the deal and the revenue are recorded in other systems, and those systems see only what reaches them. So the bill arrives in three places:
- A perfectly tagged visit turns into a lead with no source.
- Sales can’t tell where anyone came from.
- Chapter 6’s join, spend against the revenue analytics saw, stops at analytics. The leads, and any revenue recorded beside them, have nothing to join on.
Analytics stops at the visit
Here’s what analytics recorded for Maya over the same two weeks:
| Visit | Source | Medium |
|---|---|---|
| Facebook ad, launch week | facebook | paid_social |
| Instagram ad, a week later | instagram | paid_social |
Both carry the campaign spring_sale-runners-2025_03. Both rows are perfect. The record above is blank. They describe the same person in the same fortnight.
Analytics did its job. Its job ends at the visit.
The lead, and later the deal and the revenue, are written somewhere else. A CRM (customer relationship management system) keeps one record per person and per deal: who they are, what they bought or might buy, and where they came from, if anyone told it. Marketing automation is the system beside it that runs the forms and the emails: a sign-up form like Stride’s, and the emails that follow it. On the tool map, forms, CRMs and marketing automation sit together at stage 4.
The lead record is the fourth envelope from the introduction, the one sales opens. Like every envelope, it carries only what was written into it. Nobody wrote anything into Maya’s.
The CRM won’t complain. An empty field is a perfectly valid field.
A form sends only its own fields
So where did Maya’s values go? Follow her first visit:
- She taps the Facebook ad and lands on
stride.com/. The values are in the address, and analytics reads them from there.spring- sale ?utm_source= facebook& utm_medium= paid_social& utm_campaign= spring_sale- runners- 2025_03 - She clicks through to a product page. Its address carries none of the values.
- She leaves.
- A week later the Instagram ad brings her back, and she signs up for 10% off her first order.
The form sends what she typed into it: her first name, her email.
A form sends its own fields and nothing else. The address she landed on a week earlier isn’t one of them, and by the time anyone fills in a form they’ve usually moved to another page, or left and come back days later.
Analytics never had this problem: it read the values from the address the moment she landed.
The form reads nothing but itself. Nothing carries the values across that gap unless the site does two things:
- Keep them in the browser. On landing, a small script reads the values from the address and saves them, in a cookie or in browser storage. Either one belongs to one browser on one device, and either can be cleared.
- Copy them into hidden fields. A hidden field is a form field the visitor never sees. It’s sent with the form like any other field. The script fills it from what it saved, before the form goes:
<input type="hidden" name="first_touch_utm_campaign">
<input type="hidden" name="last_touch_utm_campaign">
The full recipe, including how long to keep the values, is in the Cheat Sheet.
There’s a second way across, with different rules. A CRM can bring its own tracking script for your site, which records each visit and fills a source on the lead by itself:
Hidden fields you add
Your exact values, in fields you named. You build it: the script, the fields, and a home for each value in the CRM.
Lean this way when the record has to carry your letter as written: the campaign value a join will need, the values your reports group by.
The CRM’s own tracking
Its script records the visit by its own rules, into its own categories. No setup, and no say in what it keeps.
Lean this way when its categories answer your questions, and nothing downstream needs your exact values.
The second is Chapter 2’s lesson again, one stage later: the tool picks the category. You get someone else’s grouping of your values, not your letter. Which CRMs do this, and what their categories hold, is in The Tool Landscape, with a checked date.
The same lead, with hidden fields
Now put the hidden fields on Stride’s form, two sets of them, and run Maya’s two visits again:
| On the lead | Source | Medium |
|---|---|---|
| Before | empty | empty |
| First touch | facebook | paid_social |
| Last touch | instagram | paid_social |
The campaign fields, empty before, now read spring_sale-runners-2025_03 for both touches.
First touch
Launch week
Facebook ad
facebook / paid_social
Last touch
A week later
Instagram retargeting ad
instagram / paid_social
Outcome
Signs up for 10% off her first order
First touch
Launch week
Facebook ad
facebook / paid_social
Last touch
A week later
Instagram retargeting ad
instagram / paid_social
Outcome
Signs up for 10% off her first order
spring_sale-runners-2025_03. The first touch is what brought her in; the last is what brought her back the time she signed up.Facebook found her. Instagram brought her back. The campaign value is the same on both, so both touches belong to the spring sale.
One aside for the expert: retargeting is the audience, not the medium. The Instagram ad is still paid_social.
Now take the hidden fields away again and look at what changes. Analytics still has both visits, every value intact.
The visit didn’t change. Only the lead lost its letter.
Decide what each record keeps
Why two sets of fields? Because a field keeps a value in one of two ways:
- First-touch fields are written once and never overwritten. They answer: what brought this person in?
- Last-touch fields are rewritten on every tagged visit. They answer: what brought them back the time they converted?
Whatever a record doesn’t keep can’t be added later.
It’s Chapter 1’s rule (you can remap what was recorded, never record what wasn’t), now applied to the lead. A CRM that keeps only last touch has overwritten every first visit as it went, and no report can bring one back.
There’s a third option, for the middle of the journey. A touch history keeps one row per tagged visit, either in the browser or sent to the warehouse as events (a row per visit, as it happens), and ties the rows to the lead when the form is sent. It’s the only way the middle survives.
| First | Last | Every | |
|---|---|---|---|
| Keeps | the first tagged visit, once | the latest tagged visit | every tagged visit |
| Answers | what brought them in? | what brought them back? | what happened between? |
| Costs | hidden fields; CRM fields written once | hidden fields, refilled | engineering and storage |
| Loses | other devices; visits before storage was cleared | every earlier visit | what the browser never saw |
First, last or every touch is a choice of what each record keeps and what each costs to build. The first two take a few hidden fields.
The third is a project.
Which touch gets the credit for a sale is a different question, answered by an attribution model, and that’s Chapter 11’s. Here the question is only which values the record keeps.
The deal and the revenue need the values too
A lead isn’t the end of the trail. If your CRM keeps the deal as a separate record from the lead, the deal carries the lead’s values only if they’re copied onto it, or if it stays linked to the lead. Otherwise the deal starts blank, and the trail ends one step later than before. Stride sells through checkout, so picture Maya’s values in a business that sells through deals, with a CRM that keeps the deal apart from the lead:
| On the deal | Copied | Not copied |
|---|---|---|
| Amount | recorded | recorded |
| Source, first | facebook | empty |
| Source, last | instagram | empty |
| Medium | paid_social | empty |
One person, one lead, the values sitting in the CRM. The deal in the Not copied column never got them, and the deal is where the money gets recorded.
Revenue is recorded wherever the sale happens: a deal marked won in the CRM, or an online order. Wherever that is, it needs the values too.
With the values on every record, Chapter 6’s join reaches the CRM. It matches two things:
- The campaign: Meta’s
campaign_nameagainst the lead’s campaign, the same exact string. - The platform: Meta’s rows (the platform is added as a column when the export loads) against leads whose source is one of Meta’s,
facebookorinstagram, bothpaid_social.
The campaign alone isn’t enough. The newsletter and the QR code carry spring_sale-runners-2025_03 too, and their leads didn’t come from Meta’s money.
Meta's spend export
Meta Ads, one row per campaign per day
- date
- platform
- campaign_name (join key)
- spend
- clicks
campaign_name and first_touch_campaign both hold
spring_sale-
Stride's leads
the CRM, one row per lead
- first_name
- signed_up
- first_touch_source
- first_touch_campaign (join key)
- last_touch_campaign
facebook or instagram. A lead whose campaign is spelled differently doesn't join.Add analytics, which has the visits by utm_campaign, and three systems meet on the same campaign value: the money that went out, the visits it bought, and the leads that came back, with every deal and order that carries their values. Experts call this closed-loop reporting, and it’s the term to search for when you want to see how others build it.
The join itself can run in three places. Each costs more to set up and less to repeat:
| Where it runs | Setup | Each repeat |
|---|---|---|
| A sheet of two exports | none | all of it, by hand |
| A BI tool (stage 6 dashboards, such as Looker) | a connection per source | a refresh |
| A warehouse that pipelines fill daily (stage 5) | a pipeline per system, and upkeep | none: it’s there each morning |
If the question comes once a quarter, the sheet is fine. If it comes every Monday, the sheet is a part-time job.
Your situation
Four things decide what your version of this looks like:
- If you sell through leads (a form, then a conversation or a deal), the lead is where the values land first, and the deal has to inherit them. If you sell straight to checkout, the order is the record, and it needs the values the way a lead would.
- If revenue is recorded in the CRM, in your store, or in both, every place that records a sale needs the values, or a link back to a record that has them.
- If first visit and sign-up are weeks apart, first touch matters more, and the browser storage is likelier to be cleared or left behind on another device. If people sign up on their first visit, first and last touch are the same visit.
- If nothing joins your systems yet, the join starts in a sheet. If a BI tool or a warehouse already holds spend and visits, the CRM is one more source on the same key.
What changes
| Decision | Before | After |
|---|---|---|
| Where the job ends | the analytics report | the trail ends at the visit; the lead, deal and revenue need the values after it |
| Lead forms | typed fields only | your values in hidden fields, or the CRM’s tracking and its categories, knowing what each keeps |
| Source on a lead | whatever the tool stored | first, last or every touch, by the question and the cost |
| Spend vs revenue | by hand, when asked | spend, leads and revenue joined in one place on the same campaign value, where it fits how often it’s asked |
Where the rule lives
Every system after the link keeps whatever it’s given. The hidden fields copy the link’s values unchanged, the CRM stores them, and the warehouse joins on them, typo and all; none of them knows that a stray Spring_Sale was a mistake. So the one place to get a value right is where the link is made. Cleaning it in the CRM later is a rule beside the path: someone has to remember it, every time, in every system the value reached.
Check yourself
Your CRM keeps only last-touch values. The CEO asks which campaigns find new customers. Can you answer for the leads you already have?
Show answerHide answer
No. Last touch is rewritten on every tagged visit, so what first brought each lead in is gone, and it can’t be added back. First-touch fields, written once, answer it from now on.
Your analytics report shows the spring sale's visits with every value, and the CRM shows its new leads with empty source fields. Where did the values stop, and what carries them across?
Show answerHide answer
At the visit: the form sent only the fields people typed. Keep the values in the browser when someone lands and copy them into hidden fields when the form is sent, or rely on the CRM’s own tracking and its categories.
Meta's export lists spend under spring_sale-runners-2025_03; some leads' first-touch campaign reads Spring_Sale-runners-2025_03. What happens to the join, and where is the fix that stops it coming back?
Show answerHide answer
Those leads don’t join: the join key matches exact strings. Remap the history once. The lasting fix is where the link was made, because the hidden fields copied it faithfully.
In one line
Analytics stops at the visit. The values reach the lead, the deal and the revenue only if a form carries them there, so decide which touches each record keeps, and join it all on the same campaign value.
Before the next chapter
Open one of your lead forms from a tagged link, fill it in, and open the record it creates. If the source fields are empty, that's where your trail ends.