Turn off the HubSpot cookie banner, then grant HubSpot consent from a Cookie Consent callback, or tag the HubSpot tracking code so it waits for the answer. Either way, the visitor sees one consent banner.

The HubSpot tracking code stores analytics cookies (__hstc, hubspotutk, __hssc, __hssrc) that identify a returning visitor and tie page views to a contact. HubSpot classifies them as analytics cookies, so they belong to the Cookie Consent tracking category. HubSpot shows its own consent banner on pages that load the tracking code when your account has a consent banner set up for the domain. 2 consent banners on one page confuse visitors and record 2 different answers.

The Cookie Consent code from the TermsFeed generator goes on your pages first, and you need permission to edit website settings in HubSpot. Copy your HubSpot tracking code from the settings icon, then Tracking & Analytics, then Tracking code. Accounts with Marketing Hub Starter or the free tools list Tracking Code under the settings icon without the Tracking & Analytics step.

Set window.disableHubSpotCookieBanner = true near the top of <head>, before the HubSpot tracking code loads. HubSpot then does not show a consent banner on that page. The HubSpot API reference for the cookie consent banner says the flag turns off any HubSpot consent management too.

Place this script above the HubSpot tracking code.

<script>
  window.disableHubSpotCookieBanner = true;
</script>

Check your HubSpot settings too, because a page without the flag still shows a HubSpot consent banner set up for your domain. Click the settings icon, select Privacy & Consent, then the Cookies tab, and confirm that no consent banner listed there covers a domain that loads Cookie Consent. Turn off any such consent banner. HubSpot is moving every account to its v2 consent banner editor, so the options on that tab depend on the editor of your account. Follow the v2 editor in Set up cookie tracking settings and consent banners.

Approach 1: Forward the answer to HubSpot from scripts_specific_loaded

Load the HubSpot tracking code untagged and grant each HubSpot category with setHubSpotConsent from the scripts_specific_loaded callback. HubSpot takes 3 Boolean categories: analytics from tracking, advertisement from targeting, and functionality from functionality.

Replace HUB_ID in this untagged tracking code with your HubSpot account ID, and keep the code HubSpot gives you if it differs.

<!-- Start of HubSpot Embed Code -->
<script type="text/javascript" id="hs-script-loader" async defer src="https://js.hs-scripts.com/HUB_ID.js"></script>
<!-- End of HubSpot Embed Code -->

The HubSpot API reference lists all 3 values in each setHubSpotConsent call. The callback keeps them in one object, starting at false, and sends the whole object each time. Put the callbacks and callbacks_force options in the run() call the TermsFeed generator wrote, next to the options already there.

"callbacks": {
  "scripts_specific_loaded": function (level) {
    window._hsp = window._hsp || [];
    window.hubspotConsent = window.hubspotConsent || {
      analytics: false,
      advertisement: false,
      functionality: false
    };
    switch (level) {
      case 'functionality':
        window.hubspotConsent.functionality = true;
        window._hsp.push(['setHubSpotConsent', window.hubspotConsent]);
        break;
      case 'tracking':
        window.hubspotConsent.analytics = true;
        window._hsp.push(['setHubSpotConsent', window.hubspotConsent]);
        break;
      case 'targeting':
        window.hubspotConsent.advertisement = true;
        window._hsp.push(['setHubSpotConsent', window.hubspotConsent]);
        break;
    }
  }
},
"callbacks_force": true

Keep callbacks_force: true, which makes scripts_specific_loaded run for each accepted category on every page load and right after the visitor accepts. A run() call without the option calls the callback only for categories that have tagged scripts, so HubSpot does not get a grant for a category with no tagged script. Read when scripts_specific_loaded runs, and why it needs the option, in When scripts_specific_loaded Needs callbacks_force.

HubSpot does not save the setHubSpotConsent value in its own consent cookies, according to the HubSpot API reference for the cookie consent banner. The callback therefore sends the value again on every page. The _hsp queue holds each call until the tracking code loads, so the callback and the tracking code work in either order.

HubSpot does not document whether the tracking code waits for the first setHubSpotConsent call before it stores its analytics cookies once its own consent banner is off. Run the verification on your site before you rely on Approach 1.

Approach 2: Tag the HubSpot tracking code

Tag the HubSpot tracking code with tracking, and by default no HubSpot request or cookie exists before the visitor accepts tracking. This approach needs no HubSpot API call and holds HubSpot whatever its tracking code does before consent.

Keep the disableHubSpotCookieBanner script above this tagged tracking code.

<script type="text/plain" data-cookie-consent="tracking" id="hs-script-loader" async defer src="https://js.hs-scripts.com/HUB_ID.js"></script>

Cookie Consent keeps id, async, and defer when it runs the script. The moment the visitor accepts, HubSpot loads on the same page and records the page view. Tag the tracking code with targeting instead when HubSpot loads ad pixels for you through it, because those pixels store advertising cookies. Learn how tagged scripts run in Block Scripts Until Consent.

The HubSpot live chat widget depends on the tracking code and does not load without it, according to the HubSpot knowledge base article Install the HubSpot tracking code. A tagged tracking code holds the chat widget with it, so visitors who decline do not see the chat. HubSpot embedded forms load from their own embed code and keep receiving submissions. A submission from a visitor without the hubspotutk cookie is not tied to the earlier page views of that visitor.

The checks assume express consent with page_load_consent_levels left out or at the generator value ["strictly-necessary"], and the "I decline" button shown. Publish the change and clear any page cache before the check. Check the Application tab for the HubSpot analytics cookies and the Network tab for the tracking code, before and after a click on the "I agree" button. Close every private window and use a new one for the check, so no saved answer hides the consent banner.

  1. Open your site in that window of Chrome. Only the consent banner of Cookie Consent shows, with no HubSpot consent banner.
  2. Open DevTools, select the Network tab, type hs-scripts in the filter box, and reload. With Approach 2, no request appears before the answer. With Approach 1, the tracking code loads.
  3. Select the Application tab and open Cookies. With Approach 2, your site does not list a __hstc or hubspotutk cookie before the answer. With Approach 1, a __hstc cookie before the answer means the tracking code stores its cookies before your grant, so switch to Approach 2. On HubSpot CMS, which does not allow a tagged tracking code, use the HubSpot consent banner in place of Cookie Consent when that cookie appears.
  4. Click the "I agree" button. The __hstc, hubspotutk, and __hssc cookies appear under your site.
  5. Close every private window, open a new one, open DevTools on the Application tab, load your site, and click the "I decline" button. Under Cookies, no __hstc or hubspotutk cookie appears.

Cookies the HubSpot tracking code sets

The HubSpot tracking code stores these analytics cookies on your domain, according to the HubSpot knowledge base. List them in your Cookies Policy under tracking cookies.

Cookie Lifetime Purpose
__hstc 6 months Tracks the visitor across sessions
hubspotutk 6 months Identifies the visitor, and passes the identity to HubSpot when a form is submitted
__hssc 30 minutes Counts the page views of a session
__hssrc Session Detects a new session

HubSpot classifies messagesUtk, the chat cookie, as a functionality cookie, which fits the Cookie Consent functionality category. Ad pixels that HubSpot installs for you, such as the Meta, LinkedIn, and Google pixels, store advertising cookies that belong to targeting.

Common mistakes with HubSpot

A second consent banner, a second tracking code, a missing grant, or a cookie kept after a withdrawal points to the page source, the run() options, or your cleanup code. Check every page for each mistake.

  • 2 consent banners appear. The disableHubSpotCookieBanner script runs after the tracking code, or a page lacks it. Search the page source of each page for disableHubSpotCookieBanner, and check that it comes before hs-scripts.com. Move the script near the top of <head>, below any Consent Mode default and above the HubSpot tracking code, on every page.
  • 2 tracking codes load. A WordPress plugin for HubSpot, or a second embed code, adds an untagged copy that runs outside Cookie Consent. With Approach 2, the hs-scripts filter then shows a request before the answer. Search the page source for hs-scripts.com to find each copy. Keep one copy, tagged or untagged as your approach needs.
  • Approach 1 runs without callbacks_force. On a page with no tagged script in the accepted category, the callback never runs, so HubSpot does not receive a setHubSpotConsent call after you accept. Search your run() call for the option, and add "callbacks_force": true where it is missing.
  • You expect a withdrawal to remove HubSpot cookies. Cookie Consent does not delete cookies set by HubSpot, and a cookie stays until it expires. The Application tab still lists __hstc after the withdrawal. Delete cookies from your own code with the pattern in Rejecting Does Not Delete Cookies Already Set.