How to capture UTM parameters in Pipedrive
Pipedrive has no field for “where did this lead come from”. It stores what your form posts to it, and a form posts what it can see. UTM parameters live in the URL, not in the form, so unless you put them there yourself the person record arrives with a name, an email, and no idea which campaign paid for it.
This is fixable in an afternoon. Three parts: somewhere in Pipedrive to put the data, hidden fields on the form to carry it, and a mapping in between.
Why Pipedrive does not do this natively
Pipedrive is a sales CRM. Its job starts once a lead exists. The marketing context that produced the lead sits upstream, in the browser session, and by the time Pipedrive sees the record that session is over.
There is a second complication if you use Pipedrive’s own LeadBooster Web Forms: they do not support hidden fields. There is nowhere to put a value that the visitor should not see. If you are running Pipedrive’s built-in forms today, you will need a different form builder to make any of this work.
Step 1: create the custom person fields
Go to Settings > Company settings > Data fields and switch to the Person tab. These are contact-level fields rather than deal fields, because a form submission creates or updates a person.
Add one Text field for each thing you want to capture. A reasonable starting set:
| Label | Holds |
|---|---|
| Lead Source | utm_source, for example google |
| Lead Medium | utm_medium, for example cpc |
| Campaign | utm_campaign |
| Keyword | utm_term |
| Ad Content | utm_content |
| Google Click ID | gclid |
| Landing Page | The first page they arrived on |
Two things to watch. Pipedrive generates an internal API name from the label and can change it, so check what it became after you save. And resist the urge to make these dropdown fields. A dropdown with a fixed option list will silently drop any campaign name you have not added yet.
The Google Click ID field is the one people skip and later regret. It is what lets you push closed deals back into Google Ads as offline conversions, so the bidding optimises toward revenue rather than form fills.
Step 2: get the values into the form
Your form needs a hidden input for each field. In plain HTML that looks like this:
<form action="/submit" method="POST">
<input type="text" name="name" required>
<input type="email" name="email" required>
<input type="hidden" name="utm_source">
<input type="hidden" name="utm_medium">
<input type="hidden" name="utm_campaign">
<input type="hidden" name="utm_term">
<input type="hidden" name="utm_content">
<input type="hidden" name="gclid">
<button type="submit">Send</button>
</form> Every mainstream form builder has an equivalent. Gravity Forms and WPForms have a hidden field type. Contact Form 7 uses a [hidden fieldname] shortcode. Jotform has a Hidden Field element, though it only works if you embed the form with the JavaScript code rather than an iframe.
The inputs are empty. Something has to fill them.
The manual way
The short version is a script that reads the query string and writes it into the inputs:
<script>
var params = new URLSearchParams(location.search);
['utm_source','utm_medium','utm_campaign','utm_term','utm_content','gclid']
.forEach(function (key) {
var input = document.querySelector('input[name="' + key + '"]');
if (input && params.get(key)) input.value = params.get(key);
});
</script> Paste that below your form, and a visitor who lands on the form page from a tagged ad link will submit with the values attached. It costs nothing and it works.
It also has four holes, and they are the reason most people eventually stop maintaining a version of this script.
It only works on the landing page. Someone clicks your ad, lands on a service page, reads it, then clicks through to Contact. The query string is gone by the second page, so the form submits blank. To fix it you have to write the values into sessionStorage or a cookie on arrival and read them back at the form.
It misses everyone without UTMs. Organic search, a link from a directory, a LinkedIn post someone shared. That is often the majority of your traffic, and all of it arrives with an empty query string and a populated document.referrer that this script never reads.
It only knows the last visit. A serious buyer visits five times over three weeks. This script records the fifth visit and nothing else. The blog post that introduced them, which is the reason they came back at all, gets no credit.
Safari drops it. Cookies set by JavaScript expire after seven days in Safari, and outside the EU every browser on iOS uses the same engine. If your sales cycle is longer than a week, a meaningful chunk of first-touch data disappears before the deal closes.
If you only run paid search, only send traffic to one landing page, and close deals within a week, the manual script is honestly fine. Beyond that, you are rebuilding an attribution tool one edge case at a time.
Step 3: map the fields into Pipedrive
The form now carries the values. They still have to reach the right Pipedrive field, and this is where most setups quietly fail: the field exists in Pipedrive, the hidden input exists on the form, and nothing in the middle connects them.
Whichever route your submissions take, open the mapping and check every field individually. If you’re using a native form builder integration, Gravity Forms, WPForms and others have Pipedrive add-ons with a field mapping screen where you map each hidden field to its custom person field. In Zapier, each Pipedrive custom field appears in the dropdown list on the Create Person step, so drag the matching form field into it. And if you post to Pipedrive’s API yourself through a webhook, use the field’s API key rather than its label, because labels change and keys do not.
Step 4: test it properly
Open an incognito window and visit a page with the form using a fully tagged URL:
https://yoursite.com/contact?utm_source=google&utm_medium=cpc&utm_campaign=brand-search&utm_term=crm+software&gclid=TEST123 Before submitting, open dev tools, find the form element, and check the hidden inputs already hold values. If they are empty here, the problem is on your site and nothing downstream will help.
Then submit with an email address Pipedrive has never seen. Test on a fresh person every time. Some integrations skip custom fields when they update an existing record instead of creating one, and the result looks exactly like a tracking failure.
Open the new person and confirm each custom field. If the form had the values and Pipedrive does not, the mapping in step 3 is the problem.
Do this again from a phone. Mobile is usually where a form breaks, and it is usually where most of your paid traffic is.
What to do with it once it works
Filter your people list by Lead Source and Campaign, then look at what actually became a deal rather than what became a contact. The campaign with the cheapest cost per lead is frequently not the campaign with the cheapest cost per closed deal, and you cannot see that gap without the source on the record.
Group by first touch rather than last touch if you sell anything with a consideration period. Last touch over-credits branded search, which is the channel that would have happened anyway, and under-credits whatever made them search your name.
Then take the gclid values from closed deals and upload them to Google Ads as offline conversions. That single step is worth more than the reporting, because it changes what the bidding algorithm optimises toward.
The automated version
If the four holes in the manual script matter for your business, SourceTag handles them: it stores first click and last click in a first-party cookie, categorises visits without UTMs by referrer, and fills the hidden fields on any form on your site. Setup is one script tag, the same hidden fields, and the same Pipedrive custom fields you just created. The Pipedrive setup guide has the field list.
