HubSpot has built-in source tracking. It's not enough.
HubSpot's "Original Source" field uses its own logic, it categorizes contacts as "Paid Search," "Social Media," or "Direct Traffic" based on referrer data and page metadata. It doesn't read your UTM parameters. If you're running campaigns with custom UTMs, HubSpot's native field won't tell you which specific campaign, ad set, or creative drove a contact.
To get that data, you need to capture UTM parameters yourself using hidden form fields and custom contact properties. Here's exactly how to do it.
What you're building
By the end of this guide, every contact created through your HubSpot forms will have custom properties populated with UTM data from the URL they arrived on. So when a lead comes through from a LinkedIn Sponsored Content campaign, the contact record shows:
- utm_source: linkedin
- utm_medium: paid-social
- utm_campaign: q2-enterprise-retarget
- utm_content: cta-variant-b
That data flows into your deals, your reports, and your CRM views, so you can filter by campaign, build attribution reports, and actually answer "which campaign drove this deal."
Step 1: Create custom contact properties in HubSpot
You need a custom property for each UTM parameter you want to capture. HubSpot's native properties won't receive hidden field data, so you have to create these yourself.
Go to: Settings → Properties → Contact properties → Create property
Create one property for each of the following:
| Property label | Internal name | Field type |
|---|---|---|
| UTM Source | utm_source | Single-line text |
| UTM Medium | utm_medium | Single-line text |
| UTM Campaign | utm_campaign | Single-line text |
| UTM Content | utm_content | Single-line text |
| UTM Term | utm_term | Single-line text |
Use single-line text for all of them, not dropdowns, not multi-select. UTM values are free-form strings, and a dropdown field won't accept values it doesn't already know.
Step 2: Add hidden fields to your HubSpot forms
For each form you want to track, you'll add hidden fields that map to the custom properties you just created.
In HubSpot's form editor:
- Click "Add field" and choose the custom property you created (e.g., "UTM Source")
- Once it's added to the form, click on the field to open its settings
- Check "Make this field hidden"
- Under "Set a default value," select "Prefill from query parameter"
- Enter the query parameter name:
utm_source
Repeat for utm_medium, utm_campaign, utm_content, and utm_term.
When a visitor arrives at your page with ?utm_source=linkedin in the URL, HubSpot reads that parameter and pre-fills the hidden field before the form is submitted. The contact is created with the UTM value in the custom property.
Step 3: Test it
Before you trust this setup with real leads, verify it's working.
Build a test URL with all five parameters using the Trakt UTM Builder →:
https://yoursite.com/demo?utm_source=linkedin&utm_medium=paid-social&utm_campaign=test&utm_content=test-cta&utm_term=test
Open that URL, fill out the form with your own email, then find the contact in HubSpot. Check the custom properties, all five should be populated.
If they're blank: double-check that each hidden field is mapped to the correct property and that "Prefill from query parameter" is enabled with the exact parameter name (case-sensitive: utm_source not UTM_Source).
What HubSpot's "Original Source" still does (and why you might keep both)
HubSpot's native source tracking has one thing going for it: it's always on and doesn't require form configuration. It captures the referring domain, session type, and approximate channel even without UTMs.
The problem is granularity. "Paid Search" tells you the channel. utm_campaign=q2-enterprise-retarget-linkedin tells you the specific campaign. For anything beyond basic channel attribution, you need the UTM properties.
Keep both. Use HubSpot's native source for broad channel reporting, and your custom UTM properties for campaign-level attribution and deal reporting.
Connecting UTMs to your deals
Here's where this gets valuable: UTM properties on a contact are useful, but UTM properties visible on a deal are what you need to prove ROI.
HubSpot deals don't automatically inherit contact properties. You have a few options:
Option 1: Report at the contact level. Build a custom contact report filtered by your UTM properties. This works for pipeline attribution even without moving data to the deal.
Option 2: Create mirrored deal properties. Create the same five UTM properties on deals (UTM Source, UTM Medium, etc.) and use a workflow to copy the contact's UTM properties to the associated deal when the deal is created.
To build the workflow: Workflows → Create workflow → Contact-based → Trigger: Deal is associated with contact → Action: Copy contact property value to deal property (for each UTM field)
Option 3: Use Trakt's dashboard. Trakt connects form submissions, UTM data, and deal outcomes in one view without needing to build manual workflows. See how it works →
What about forms built outside HubSpot?
If you're using third-party forms (Contact Form 7, Typeform, Gravity Forms, Webflow forms) that submit data to HubSpot via integration, the setup is different.
The hidden fields need to exist in the third-party form and the form's HubSpot integration needs to map those fields to the correct custom properties.
In Zapier: add the UTM fields from your form tool as data in the "Create Contact" action, mapping each to the corresponding HubSpot property.
In native integrations (Typeform → HubSpot, Webflow → HubSpot): look for field mapping in the integration settings. The UTM hidden fields in your form need explicit mappings, they won't auto-match.
Detailed form-specific instructions: UTM tracking for Contact Form 7, Gravity Forms, and Typeform →
The maintenance problem and how to solve it
This setup works, but it requires you to add hidden fields to every new form you create. Add a new landing page, forget to add the hidden fields, and those leads come in without UTM data.
If you have more than a handful of forms, or if your marketing team moves fast and forms get created regularly, manual setup doesn't scale.
Trakt handles this automatically: it scans your site, detects forms, and injects UTM hidden fields across all of them, including new ones. When a form is updated or replaced, Trakt's injection updates too.
See how Trakt works with HubSpot →
Common gotchas
- Test in incognito. HubSpot remembers known contacts and may not re-create properties if you test with your own email repeatedly. Use a fresh email for each test.
- Don't use "remember me" pre-fill. HubSpot's "save user data" feature can override hidden field values. Disable it on forms where UTM capture matters.
- Check your ad platform UTM conventions. Google Ads auto-tagging (
gclid) competes with UTMs. Make sure you have "Allow auto-tagging to override UTM" disabled if you want your custom UTMs to take precedence in HubSpot.