Modern B2B marketing attribution is only as good as the data captured during a user’s journey.
While working at Billtrust, I developed a custom attribution tracking solution that captured and persisted UTM parameters, referral sources, and campaign metadata across a user’s session lifecycle — ultimately syncing that data into Marketo forms and Salesforce lead records.
The goal was simple:
Ensure that marketing campaign attribution persisted across multiple page views and sessions, even when a user converted days or weeks after their initial visit.
This system was built using:
- JavaScript
- Browser cookies
- WordPress
- Marketo Forms
- Hidden form fields
- Campaign attribution logic
The result was a lightweight client-side attribution framework that enabled both first-touch and last-touch campaign tracking without requiring third-party attribution software.
The Problem with Standard UTM Tracking
Most websites only capture UTM parameters on the landing page.
That creates a major problem:
- A user clicks a paid ad with UTMs
- They browse multiple pages
- They return days later directly
- They complete a form
At conversion time, the original UTM parameters are gone.
Without persistence, attribution is lost.
For marketing teams, this creates inaccurate reporting in:
- Marketo
- Salesforce
- Google Analytics
- Revenue attribution dashboards
- Multi-touch campaign reporting
We needed a solution that:
- Persisted attribution data across sessions
- Captured both first and latest interactions
- Worked across WordPress pages
- Integrated directly into Marketo forms
- Required minimal maintenance
Attribution Architecture Overview
The implementation used a two-part system:
Part 1: Cookie-Based Attribution Engine
A JavaScript layer automatically:
- Captured URL UTM parameters
- Parsed referral traffic
- Identified organic search traffic
- Stored campaign metadata in browser cookies
- Persisted both first-touch and returning-touch interactions
Part 2: Marketo Form Injection
Another JavaScript layer:
- Read stored cookie values
- Mapped them to hidden Marketo fields
- Injected values before form submission
- Passed attribution data into CRM systems
This created a seamless attribution pipeline from anonymous visitor → known lead.
Capturing First-Touch and Last-Touch Attribution
The system stored two categories of cookies:
First-Touch Cookies
These represented the original acquisition source.
fs_referrer
fs_campaign
fs_content
fs_medium
fs_source
fs_term
FirstSession
Last-Touch / Returning Cookies
These represented the latest interaction before conversion.
rs_referrer
rs_campaign
rs_content
rs_medium
rs_source
rs_term
ReturningSession
This distinction enabled marketing teams to answer questions like:
- Which campaign originally acquired the lead?
- Which campaign influenced conversion?
- Did paid search drive awareness while email closed the conversion?
- What channels assisted pipeline generation?
Parsing UTM Parameters
The attribution engine first inspected the current URL for standard marketing parameters.
if (urlSearch.indexOf('utm_source') > -1) {
source = getParam(urlSearch, 'utm_source');
medium = getParam(urlSearch, 'utm_medium');
campaign = getParam(urlSearch, 'utm_campaign');
term = getParam(urlSearch, 'utm_term');
content = getParam(urlSearch, 'utm_content');
}
Supported parameters included:
utm_sourceutm_mediumutm_campaignutm_termutm_contentgclidli_fat_id
This ensured compatibility with:
- Google Ads
- LinkedIn Ads
- Email campaigns
- Paid social
- Affiliate campaigns
- Organic tracking initiatives
Organic Search Detection
When UTMs were unavailable, the system intelligently evaluated referral traffic.
Search engines were mapped manually:
var searchEngines = [
['bing', 'q'],
['google', 'q'],
['yahoo', 'q'],
['baidu', 'q'],
['yandex', 'q'],
['ask', 'q'],
];
If the referrer matched a known engine:
medium = organicsource = search engine name
This enabled organic attribution even without campaign tagging.
Cookie Persistence Strategy
One of the most important implementation details was preserving both:
- Original acquisition source
- Most recent interaction source
The logic worked like this:
var existing = crumbleCookie()[pair.first];
var targetCookie = typeof existing === 'undefined' ? pair.first : pair.repeat;
If no first-touch cookie existed:
Store data as:
fs_source
fs_medium
fs_campaign
If a first-touch cookie already existed:
Store subsequent visits as:
rs_source
rs_medium
rs_campaign
This preserved attribution integrity while still tracking ongoing engagement.
Normalizing Direct Traffic
Direct traffic can pollute attribution data if not handled carefully.
The implementation normalized missing values:
var source = trafficSources.source.length === 0 ? 'direct' : trafficSources.source;
Similarly:
medium = 'none';
campaign = 'none';
This created cleaner downstream CRM reporting and reduced null-value issues inside Marketo and Salesforce.
Marketo Form Integration
Once attribution cookies existed, the next step was syncing them into Marketo forms.
Hidden form fields were dynamically populated:
<input type="hidden" name="btURLSource" />
<input type="hidden" name="btURLMedium" />
<input type="hidden" name="btURLCampaign" />
The script then mapped browser cookies into Marketo-compatible fields.
var marketoMap = {
btURLCampaign: 'UTM_Campaign__c',
btURLContent: 'UTM_Content__c',
btURLMedium: 'UTM_Medium__c',
btURLSource: 'UTM_Source__c',
};
This allowed attribution data to flow directly into:
- Marketo lead records
- Salesforce contacts
- Campaign influence reporting
- Revenue attribution dashboards
Referrer Attribution Logic
One of the more nuanced parts of the implementation was determining the “true” referrer.
The system accounted for cases where:
- Users navigated internally
- Users returned directly
- Users revisited through new campaigns
- Self-referrals occurred
Logic was added to avoid misattributing traffic to internal domains.
if (
(fs === 'direct' && rs === 'direct') ||
(fs === 'billtrust.com' && rs === 'billtrust.com')
)
This prevented internal navigation from overwriting meaningful attribution data.
Why This Approach Worked Well
This implementation succeeded because it balanced:
Marketing Needs
- Reliable attribution
- Campaign visibility
- CRM enrichment
- Revenue reporting
Engineering Needs
- Lightweight footprint
- No backend dependency
- Browser-native persistence
- Minimal third-party tooling
It also reduced reliance on expensive attribution platforms while still delivering highly actionable campaign intelligence.
Key Lessons from Building Attribution Systems
1. Attribution Is Fragile
Campaign data disappears quickly if not persisted immediately.
Capturing UTMs on first page load is critical.
2. Internal Referrals Must Be Ignored
Without safeguards, your own domain can overwrite valuable attribution signals.
Self-referral filtering is essential.
3. First-Touch and Last-Touch Both Matter
Marketing teams often debate attribution models.
The best approach is usually:
- Store both
- Let reporting decide later
4. CRM Hygiene Matters
Normalizing values like:
direct
none
(not set)
helps downstream analytics remain consistent.
Final Thoughts
This project was a great example of where marketing operations and frontend engineering intersect.
By combining:
- JavaScript
- Cookie persistence
- Attribution logic
- WordPress integration
- Marketo automation
we created a reliable attribution framework that improved lead intelligence and campaign reporting across the marketing funnel.
It reinforced an important principle:
Good attribution is not just analytics — it’s infrastructure.
And when implemented thoughtfully, it becomes a foundational layer for growth, optimization, and revenue visibility.