HubSpot vs Chargebee UTM Tracking: Complete Setup Guide (2025)

Senior WebCoder
HubSpot vs Chargebee UTM Tracking: Complete Setup Guide
HubSpot handles UTM tracking perfectly through marketing funnels. Chargebee checkout forms need explicit UTM data.
This guide shows you how to capture UTMs from HubSpot-tracked pages and pass them to Chargebee checkout using sessionStorage + custom fields.
HubSpot vs Chargebee: UTM Tracking Comparison
| Feature | HubSpot | Chargebee |
|---|---|---|
| Native UTM capture | โ Server-side tracking | โ Requires custom fields |
| Browser cookie access | โ Server-side only | โ No native support |
| Multi-page persistence | โ Automatic | โ Needs JavaScript |
| Checkout attribution | โ Internal forms | โ External checkout |
Key difference: HubSpot tracks server-side across your domain. Chargebee hosted pages live outside that tracking boundary.
HubSpot captures Original/Latest Source automatically. Chargebee needs you to explicitly send UTM data in form fields.
Why Native Integrations Don't Solve UTM Tracking
Official Chargebee โ HubSpot syncs:
- Customers โ Companies
- Subscriptions โ Deals
- Invoices โ Line items
Missing: UTM parameters, traffic sources, attribution data.
Third-party tools (Zapier) fail because:
- No UTM data available at subscription trigger time
- Adds monthly cost for incomplete solutions
Step-by-Step Implementation
Step 1: Create Chargebee Custom Fields (10 minutes)
Chargebee Dashboard โ Settings โ Custom Fields โ Add:
utm_source (text)
utm_medium (text)
utm_campaign (text)
utm_term (text)
utm_content (text)
These fields will capture attribution data on every subscription.
Step 2: JavaScript UTM Capture (30 minutes)
Add this script globally (footer, _document.js, functions.php):
// Capture UTMs from URL and persist across pages
function captureUTMs() {
const urlParams = new URLSearchParams(window.location.search);
const utms = {
utm_source: urlParams.get('utm_source') || sessionStorage.getItem('utm_source'),
utm_medium: urlParams.get('utm_medium') || sessionStorage.getItem('utm_medium'),
utm_campaign: urlParams.get('utm_campaign') || sessionStorage.getItem('utm_campaign'),
utm_term: urlParams.get('utm_term') || sessionStorage.getItem('utm_term'),
utm_content: urlParams.get('utm_content') || sessionStorage.getItem('utm_content')
};
// Store in sessionStorage (survives navigation, cleared on tab close)
Object.keys(utms).forEach(key => {
if (utms[key]) sessionStorage.setItem(key, utms[key]);
});
return utms;
}
// Populate Chargebee form fields when checkout loads
function populateChargebeeUTMs() {
const utms = captureUTMs();
// Target Chargebee custom fields (cf_ prefix)
['source', 'medium', 'campaign', 'term', 'content'].forEach(param => {
const field = document.querySelector(`[name="cf_utm_${param}"]`);
if (field && utms[`utm_${param}`]) {
field.value = utms[`utm_${param}`];
}
});
}
// Run on every page
document.addEventListener('DOMContentLoaded', captureUTMs);
// Detect Chargebee checkout load
const observer = new MutationObserver((mutations) => {
if (document.querySelector('[name^="cf_utm_"]')) {
populateChargebeeUTMs();
observer.disconnect(); // Stop observing once populated
}
});
observer.observe(document.body, { childList: true, subtree: true });
Step 3: Framework-Specific Deployment
WordPress:
// functions.php
wp_enqueue_script('utm-tracker', get_template_directory_uri() . '/js/utm-tracker.js', [], '1.0', true);
Next.js:
// pages/_document.js
<Script id="utm-tracker" strategy="afterInteractive">
{`(${utmTrackerScript.toString()})();`}
</Script>
Any SPA (React/Vue): Add to main.js or App.vue.
Step 4: Test Implementation (15 minutes)
- Visit:
/campaign?utm_source=google&utm_medium=cpc&utm_campaign=blackfriday - Navigate 3+ pages (UTMs persist)
- Open Chargebee checkout
- Submit test subscription
- Verify: Chargebee dashboard shows populated UTM fields โ
Implementation Benefits
| Metric | Before | After |
|---|---|---|
| Chargebee attribution | 0% | 98%+ |
| Engineering time | N/A | 2 hours |
| Cross-domain tracking | โ Broken | โ Fixed |
| Mobile/SPA support | โ | โ Full |
Key advantages:
- Works across page refreshes and navigation
- No cookie consent issues (sessionStorage)
- Handles direct traffic gracefully
- Zero impact on page speed
sessionStorage survives SPA navigation, mobile back/forward, and multi-tab sessions. Clears on tab close (correct attribution behavior).
Common Wrong Approaches (And Why They Fail)
| Approach | Problem | Time Wasted |
|---|---|---|
| Zapier sync | No UTMs at subscription trigger | $50+/month |
| HubSpot forms | PCI compliance requires Chargebee | 12+ hours |
| URL forcing | Breaks Chargebee hosted pages | UX issues |
| Cookie reading | HubSpot doesn't expose UTMs | 8 hours debug |
The sessionStorage approach works because it's independent of both platforms.
FAQ: UTM Tracking Answers
Q: Does HubSpot-Chargebee integration include UTMs?
No. It syncs customers/deals/subscriptions only. Attribution needs custom implementation.
Q: Can I access HubSpot's traffic source from JavaScript?
No. HubSpot stores this server-side. Use URL parameters + sessionStorage instead.
Q: Does this work with Chargebee embedded checkout?
Yes. The MutationObserver detects any Chargebee form fields automatically.
Q: What about users with no UTMs (direct traffic)?
Fields stay blank. Direct traffic = direct traffic (correct behavior).
Q: Is sessionStorage GDPR compliant?
Yes. UTMs aren't personal data. No consent required.
Q: Works on mobile browsers?
Yes. sessionStorage is universally supported.
Q: What if Chargebee changes field names?
Update the cf_utm_ selectors in the JavaScript. Fields are fully customizable.
