Table of contents

HubSpot Server-side Tracking: Complete Setup Guide

If you run marketing or sales through HubSpot, your lead data is only as good as the tracking that feeds it. And that tracking has a problem: the browser is turning against it.

It starts with a single cookie. HubSpot's standard tracking code sets a cookie called hubspotutk to recognize returning visitors and stitch together a contact's journey before they ever fill out a form. Safari's Intelligent Tracking Prevention caps that cookie at seven days when it's set by JavaScript, which is exactly how HubSpot sets it by default. Ad blockers and the strict privacy settings in Firefox, Edge, and Safari go further. They block the HubSpot script and its embedded forms outright, sometimes leaving nothing but a blank space where your lead form used to be.

None of this is a future risk. It's already happening on your site, and it's a big part of why HubSpot's Original Source and multi-touch attribution reports drift further from reality than most teams realize.

Hubspot Server-side Tracking fixes the root cause. Instead of the browser calling HubSpot's js.hs-scripts.com and hsforms.net endpoints directly, your own server does the talking on the contact's behalf. This guide walks you through how to set up Server-side Tracking for HubSpot using Google Tag Manager and TAGGRS.

Benefits of HubSpot Server-side Tracking

With client-side tracking, the HubSpot script runs inside the visitor's browser. It reads what it needs from the page, drops the hubspotutk and __hstc cookies, and calls HubSpot's servers directly to log page views, identify visitors, and submit forms.

Server-side Tracking moves that connection to your own server. The browser sends one request to your domain (through a Google Tag Manager server container), and your server forwards the relevant data to HubSpot's API using a private, authenticated connection. The visitor's browser never talks to HubSpot's domains at all.

The server-side equivalents of HubSpot's client-side script are its CRM Objects API for contacts and its Custom Behavioral Events API for everything else: page interactions, product views, custom form submissions, whatever you want tied to a contact record.

In plain terms, anything the HubSpot script does in the browser today has a server-side counterpart, so you're not giving up functionality by moving it, you're just changing where the work happens. For a marketing team, the practical result is that the data feeding your lists, workflows, and reports arrives more completely and stops depending on whether each visitor's browser cooperated.

Server-side Tracking is particularly worth the setup if HubSpot is where you make decisions: scoring leads, triggering workflows, reporting attribution to leadership, or optimizing ad spend against contact and deal data. The more weight you put on that data, the more the gaps cost you.

Not used to working with Google Tag Manager yet? TAGGRS has guides that cover the basics before you touch HubSpot specifically:

Why client-side tracking is unreliable for HubSpot users right now

This isn't a general "browsers are strict these days" observation. A few specific, current changes are hitting HubSpot's tracking directly, and each one maps to a report or a workflow you already rely on. Here's what's breaking client-side HubSpot tracking, and what each break costs you.

The tracking cookie is capped, and it's the one HubSpot depends on most. hubspotutk is written through document.cookie, and WebKit's own tracking-prevention rules delete any cookie set that way after seven days without a visit.

The cap drops to 24 hours specifically when a visitor lands on your site from a domain Safari has classified as a cross-site tracker, through a link carrying query parameters, exactly the pattern behind most paid ad clicks. A prospect who does their research two weeks before filling out a form shows up as a fresh, first-time visitor when they finally convert, because the cookie that tied their earlier sessions together expired days earlier.

For a considered purchase with a multi-week research cycle, this is the norm. The channel that first brought that prospect in (often an expensive one like paid search or a webinar) gets no credit, while whatever they typed into the address bar on conversion day (usually "direct") takes it all. Multiply that across a quarter and your Original Source report overweights direct and organic while starving the campaigns that did the work.

Ad blockers and browser tracking prevention block the script, not just the cookie. HubSpot's own community forum has multiple open threads about this: Firefox's Enhanced Tracking Protection and Edge's strict Tracking Prevention block requests to hsforms.net, which means hbspt.forms.create() never runs and visitors see an empty box where the form should be. No error message, no fallback. The visitor usually just leaves, and you never know the lead existed.

Apple's browser-level blocking is expanding. Safari 27 adds IP-range blocking at the network layer and puts CDPs like Segment and Tealium on its fingerprinting-script list. If you route any HubSpot-bound tracking through a CDP, or through a script tag that Safari classifies as a fingerprinting tool, it can lose access to referrer data and query parameters before it ever reaches HubSpot.

In other words, the data on "where did this lead come from" gets stripped at the browser before HubSpot ever sees it. Since roughly one in four visitors browses on Safari, that's a large, growing, and specifically high-intent portion of your audience going dark, precisely the Apple-device buyers many B2B and premium brands most want to attribute.

Ad blocker adoption isn't a niche problem anymore. Roughly a third of internet users run some form of ad blocker, and that number keeps climbing. In short, a meaningful slice of your traffic never lets the HubSpot script load at all.

How client-side tracking breaks HubSpot attribution and lead data

The consequences show up in the fields you actually use to run campaigns.

Original and Latest Traffic Source are set from the tracking cookie's session history. HubSpot tries to match a new contact record to any anonymous activity tracked under that visitor's cookie. When the cookie resets early, that earlier activity is gone, so HubSpot has nothing to match against and sets Original Source from whatever session happens to be active when the contact record gets created, not the visitor's actual first visit.

Attribution reports that credit a channel with a contact creation or a deal creation rely on the same interaction history. Fewer tracked page views and touchpoints mean flatter, less useful attribution. Your marketing didn't stop working. HubSpot just stopped seeing it.

Custom Behavioural Events and e-commerce events fired through client-side JavaScript inherit every one of these problems. If the script is blocked, the event never fires. Any workflow or lead score built on that event just sits there, doing nothing, with no error to tell you why.

One thing does still work even with the cookie blocked: HubSpot's forms can pull UTM parameters straight from the current page URL at the moment of submission, so campaign-level attribution on that specific submission usually survives. What doesn't survive is everything that depends on connecting that submission to the visitor's earlier, cookie-tracked sessions.

What HubSpot users gain from Server-side Tracking

Server-side Tracking changes what you can trust in HubSpot. Here's what improves once the connection moves to your own server:

- Forms that actually load, which is the most direct revenue impact on this list. A blocked form is a lead you never see and never paid to acquire twice. A form request served from your own domain, through your server container, isn't on the same blocklists as hsforms.net, so visitors with strict privacy settings or ad blockers still see and submit it.

- A tracking cookie that survives more than a week. Cookies set through an HTTP response header aren't subject to the seven-day JavaScript cap Safari applies to hubspotutk, but only if your server clears WebKit's separate CNAME and IP-address cloaking defense, which caps HTTP-set cookies at seven days too when it triggers.

Getting the full benefit here depends on your server sitting on a genuine first-party subdomain with an IP range that matches your main site's, which is covered in the setup section below. The most reliable way to guarantee that match is routing your server container through a Cloudflare Worker on the same origin as your main site, a path like yourdomain.com/metrics rather than a separate subdomain, since Safari's IP-matching check doesn't apply at all once everything is genuinely same-origin.

- Attribution that reflects what's actually happening. Fewer sessions get dropped along the way, so Original Source, Latest Source, and multi-touch reports get closer to the truth. That matters most when you're deciding on your budget: attribution that undercounts paid or organic leads you to cut the channels that are working.

- Reliable Custom Behavioral Events. Sending events server-side through HubSpot's API means an ad blocker on the visitor's end has no bearing on whether the event reaches HubSpot.

- More control over what you send. You decide exactly which fields get forwarded to HubSpot and when, which makes data minimization and consent enforcement a matter of configuration rather than hope.

- A lighter page. Fewer client-side scripts competing for the main thread means less impact on load time, which matters for both conversion rate and Core Web Vitals.

Taken together, these add up to more of the leads you're already earning that are making it into HubSpot, attributed correctly, ready for your workflows and reports to act on. 

What you need before you start

Setting up Server-side Tracking for Hubspot doesn’t require a rebuild. Most of it you do once, and several items you may already have if you're running GA4 server-side. 

Here's the full checklist before you build any HubSpot tags:

  • A Google Tag Manager account with a web container and a server container. If you're new to GTM, start with the beginner's guide.
  • A working data layer on your site, or at minimum a GA4 configuration tag forwarding basic page and event data to your server container. TAGGRS's server-side setup guide walks through getting that connection working, since most HubSpot tags in the server container rely on data that already reaches it through this route.
  • A TAGGRS server container, deployed with a first-party subdomain on your own domain. Create a free account to get started; the free tier covers up to 10,000 requests a month, which is enough for most initial setups.
  • A HubSpot Private App access token. HubSpot retired its legacy API keys on November 30, 2022. Create a private app under Settings > Integrations > Private Apps, and grant it only the scopes you actually need: crm.objects.contacts.write and crm.objects.contacts.read for contact records, plus analytics.behavioral_events.send if you're sending Custom Behavioral Event occurrences. If you also want to create or edit event definitions through the API rather than the UI, that's a separate scope, behavioral_events.event_definitions.read_write. HubSpot's private apps guide covers the exact steps. Copy the token when it's generated. HubSpot won't show you the full value again.
  • Event definitions created in HubSpot first, if you're sending Custom Behavioral Events. HubSpot needs the event and its properties defined before it will accept an occurrence sent through the API. You can do this through Data Management > Event Management in the UI, or through the event definitions API if you'd rather script it.
  • A consent setup that covers your server container, not just HubSpot's own banner. HubSpot's built-in consent banner only blocks HubSpot cookies and HubSpot-native integrations. It has no visibility into a custom GTM server container, so you'll need your consent management platform to pass its signal into GTM directly. TAGGRS's Consent Mode setup and the CookieConfirm integration guide both show how that connection works in practice.

Step-by-step: setting up HubSpot Server-side Tracking with Google Tag Manager

Here is the full setup, start to finish: 

1. Deploy your TAGGRS server container and connect it to a subdomain on your own domain (for example measure.yourdomain.com). This is what lets cookies set by your server count as first-party rather than third-party.

2. Confirm your data layer is forwarding to the server container. Most setups do this by sending a GA4 configuration event from the web container; the server container then has access to the same event data for every tag you build on top of it, HubSpot included.

3. Create your HubSpot Private App and copy the access token. Store it as a server-side GTM variable, not a hardcoded value inside a tag, so you can rotate it later without editing every tag that uses it.

4. Add a tag to your server container that calls HubSpot's API. Search Google Tag Manager's Community Template Gallery for an existing HubSpot server tag first.

5. Set up the Create or Update Contact tag. This is the one that turns a form submission into a contact record. At minimum, map a contact email variable from your data layer into the request, since email is what HubSpot uses to decide whether to create a new contact or update an existing one.

Then, add any custom properties you want tracked (lead source detail, page path, form name) as additional fields in the same request body. Whatever you map here is what your sales team and your reports will see, so it's worth mapping more than the bare minimum while you're in there.

6. Set up Custom Behavioral Event tracking, if you need it. Map the event name and its properties to match exactly what you defined in HubSpot in the setup step above. Names have to match the internal name HubSpot generated, not the display label, or the event will be rejected.

7. Add triggers for each tag. A contact-create tag typically fires on form submission events already present in your data layer. A behavioral event tag fires on whatever custom event you're tracking (a pricing page view, a video watched to completion, an add-to-cart on a HubSpot-connected commerce integration).

8. Test everything in GTM Preview mode, with preview active on both the web and server containers at once. TAGGRS's testing guide covers how to read the request flow between the two. Submit a real test form and confirm the contact appears (or updates) in HubSpot, then trigger a test behavioral event and check it shows up on the contact's timeline.

9. Run the new setup alongside your existing HubSpot tracking code for a short period, rather than removing it immediately. This gives you a way to compare contact creation and event volume before you fully cut over, and it protects you if something in the new setup is misconfigured.

10. Publish your server and web containers once testing looks clean.

Once published, the change is live for every visitor immediately, and the data starts flowing through your own domain from the next form submission on. From here, the ongoing work involves just maintaining tags and consent rules. You no longer need to troubleshoot a client-side script every time a browser changes its privacy rules.

Common mistakes to avoid

When a server-side HubSpot setup goes wrong, it usually doesn't throw an error. The tags look like they're working, but the data either doesn't reach HubSpot or arrives wrong, so the problem often goes unnoticed until a report looks off. These are the mistakes that cause it most often:

  • Sending Custom Behavioral Events before defining them in HubSpot. HubSpot rejects any event it doesn't already recognize, so the tag fires, nothing lands, and there's no obvious error to point you at the cause. Define the event and its properties in HubSpot first, every time.
  • Missing or wrong scopes on the Private App token. A token without the right scope doesn't fail loudly. The tag shows as "fired" while HubSpot silently rejects the request, so contacts or events never appear. Check the actual response code in server container preview mode rather than trusting the "fired" status.
  • No visitor email available when the tag fires. Email is how HubSpot decides whether to update an existing contact or create a new one. Without it, the call either fails outright or spawns a duplicate contact with nothing to match it against, which quietly pollutes your database over time. Make sure the email variable is populated before the tag runs.
  • Running old and new tracking in parallel with no cleanup plan. Running both for a few weeks is smart for comparison, but if both keep creating contacts and events indefinitely, you'll double-count and inflate every report built on that data. Decide upfront which setup is your source of truth, and switch the other off once you trust the numbers.
  • Assuming the server-side cookie automatically beats the seven-day cap. It only does if your subdomain doesn't point (via DNS CNAME) to a third-party domain and your server's IP range matches your main site's. Miss either and Safari re-applies the same seven-day cap you moved server-side to escape, so you get all the setup work and none of the attribution benefit. Routing through a same-origin Cloudflare Workers setup is the most reliable way to guarantee the match.
  • Forwarding personal data before checking consent. Server-side gives you more control over what you send, but only if you actually build the consent check into each tag's trigger conditions. The architecture doesn't enforce consent for you, and assuming it does is how a privacy-safe setup quietly becomes a non-compliant one.
  • No data layer, or an inconsistent one. Every tag here depends on data reaching the server container in a predictable shape. When event names or parameter keys drift between pages, tags stop firing with no obvious cause, and you're left debugging the tag when the real problem is upstream. Lock down consistent naming before you build on top of it.

Additional tools worth pairing with your HubSpot setup

If your leads come through Google Ads, this one directly protects your ad reporting. The GCLID is the tag Google uses to connect a click to a conversion, and when Safari strips it from the URL, Google Ads can't tell which clicks became customers, so your ROAS looks worse than it is and the algorithm optimizes on bad data. Click ID Recovery restores GCLID values that Safari strips from URLs before they ever reach your form.

HubSpot doesn't capture GCLID out of the box. You need a custom contact property named to match the URL parameter, added to your form as a hidden field, and HubSpot's own hidden-field matching will populate it when a visitor arrives with that parameter in the URL. Once that piece is in place, our guide to fixing GA4 ROAS inaccuracies covers how the stored GCLID becomes an offline conversion upload once a deal closes, and our Enhanced Conversions guide covers the upload side in more depth.

The Enhanced Tracking Script masks and encrypts the request between browser and server, which helps more events survive ad blocker pattern matching before they even reach your server container.

If you serve EU traffic, pair this setup with Consent Mode V2 so consent signals travel with the data all the way to HubSpot, not just to Google's tags. Our GDPR overview for server-side tracking has more on what that requires in practice.

Conclusion

HubSpot's client-side tracking was built for a browser world that doesn't really exist anymore. Between Safari's seven-day cookie cap, ad blockers stripping out the script entirely, and browsers classifying more of the marketing stack as a fingerprinting risk, relying on the browser alone means losing contacts, misattributing the ones you keep, and missing events that should be feeding your lead scores.

Moving that connection server-side, through Google Tag Manager and TAGGRS, puts the request on your own domain instead of HubSpot's, where ad blockers and tracking prevention settings have nothing to match against. It also puts you in control of what gets sent to HubSpot and when, which makes the privacy side of this easier, not harder.

Ready to set it up? Create a free TAGGRS account or book a demo to talk through your specific HubSpot setup.

FAQ

What is Server-side Tracking for HubSpot?

Server-side tracking for HubSpot means routing the data that would normally go straight from a visitor's browser to HubSpot's servers through your own server first. Instead of the HubSpot script calling js.hs-scripts.com or hsforms.net directly, your server receives the event and forwards it to HubSpot's CRM and Events APIs using an authenticated connection. The result is data that reaches HubSpot even when ad blockers or browser privacy settings would have blocked the standard client-side script.

Does HubSpot support Server-side Tracking natively?

Not in the way most people mean it. HubSpot's own tracking code, forms, and consent banner are all client-side by design, and its native integrations sync through the CRM API rather than through a server-side tag manager. To get true server-side tracking, most teams pair a Google Tag Manager server container with HubSpot's Private App access tokens and its CRM Objects and Custom Behavioral Events APIs, using a hosting provider like TAGGRS to run the server container.

How does this affect lead and contact attribution in HubSpot?

It generally improves it. HubSpot's Original Source, Latest Source, and attribution reports depend on a tracking cookie surviving across a visitor's sessions. When that cookie is capped at seven days by Safari's ITP, or blocked entirely by an ad blocker, HubSpot loses the thread between a visitor's early research and their eventual form submission. Server-side tracking, combined with a correctly configured first-party subdomain, extends how long that identity persists, which means more contacts get attributed to the channel that actually brought them in.

Is Server-side Tracking for HubSpot GDPR-compliant?

Yes, when it's set up with consent in mind. Because the data passes through your own server before reaching HubSpot, you control exactly what gets forwarded, which makes it easier to apply data minimization and to check a visitor's consent status before any personal data leaves your server. HubSpot's own consent banner doesn't extend to a custom server container, so you still need your consent management platform to pass its signal into your Google Tag Manager setup directly, as covered in the setup section above.

Do you need to remove HubSpot's standard tracking code?

Not right away. Running both in parallel for a few weeks is the safer path. It gives you a way to compare contact creation, event volume, and attribution between the two setups before you commit. Once you trust the server-side numbers, you can decide whether to remove the client-side code entirely or keep a trimmed version of it for things like the HubSpot chat widget, which still depends on the visitor identification token running in the browser.

About the author

Recently published

magnifiercrossmenu linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram