Each Cookie Consent category maps to a fixed list of vendor consent signals: tracking maps to the analytics signals, targeting to the advertising signals, and functionality to the functionality signals. Cookie Consent sends none of these signals by itself, so your callbacks send them.

The 4 categories are strictly-necessary, functionality, tracking, and targeting, written exactly so. Cookie Consent has no analytics category and no custom category. Check what each category covers in The 4 Cookie Categories.

Each Cookie Consent category controls the vendor signals in its row, spelled with the exact name and capitalization each vendor uses. The callbacks send granted for an accepted category (Meta: grant, HubSpot: true). For Google, user_consent_saved sends denied for each refused category. For the other vendors, a rejected category does not get a call of its own. Meta and TikTok keep the default set in the page (revoke, holdConsent()). The Clarity and HubSpot recipes list every key in each call, so the call for an accepted category sends every key not granted yet as denied (Clarity) or false (HubSpot).

Cookie Consent category Google Consent Mode v2 Microsoft Clarity consentv2 Meta Pixel TikTok Pixel HubSpot setHubSpotConsent
strictly-necessary No signal No signal No signal No signal No signal
functionality functionality_storage, personalization_storage No signal No signal No signal functionality
tracking analytics_storage analytics_Storage No signal No signal analytics
targeting ad_storage, ad_user_data, ad_personalization ad_Storage fbq('consent', 'grant') ttq.grantConsent() advertisement

The strictly-necessary category is always accepted. Clarity spells its 2 keys with a capital S (ad_Storage, analytics_Storage), as the Microsoft Clarity consent API reference writes them, and the Google keys stay lowercase.

The TikTok command in the table, ttq.grantConsent(), comes from the pixel consent mode TikTok documents. Set up the pixel with Block the TikTok Pixel Until Consent.

LinkedIn does not document a consent command for the LinkedIn Insight Tag on an official page, so the Insight Tag waits as a tagged targeting script. Tag it with Block LinkedIn Insight Tag Until Consent.

A category grants its Microsoft Clarity, Meta, TikTok, and HubSpot signals only when Cookie Consent releases it. On each page, a vendor starts from its default state for every category Cookie Consent does not release there. The scripts_specific_loaded callback receives one category ID as level, once for each released category. The Google signals follow the same answer through user_consent_saved, which receives every category in details.

Which categories reach the callback depends on the answer, page_load_consent_levels, and notice_banner_purposes_levels.

  • An accepted category reaches the callback. The "I agree" button accepts every category in use, and the "Save my preferences" button accepts the categories whose switch is on.
  • A rejected category never reaches the callback. No scripts_specific_loaded call runs right after a click on the "I decline" button, and on later page loads with callbacks_force, the callback runs for strictly-necessary alone.
  • A visitor who has not answered gets only the categories that run on page load. In express consent, the default, no optional category reaches the callback unless page_load_consent_levels lists it.
  • A category left out of notice_banner_purposes_levels never reaches the callback. Cookie Consent never accepts a category the visitor has no switch for, so the callback never grants its signals.

Cookie Consent reads the categories in use from notice_banner_purposes_levels, and every category is in use when the option is not set. Choose the categories in use with Hide Cookie Categories and Buttons.

A user_consent_saved callback sends the Google Consent Mode v2 signals, with "user_consent_saved_on_page_load": true beside it. Cookie Consent calls the callback before it releases any tagged script, on every answer and on every page load. A tagged Google tag therefore starts with the saved choice. The generator code starts Cookie Consent on DOMContentLoaded, so an untagged Google tag often loads first and usually takes the update within its wait_for_update time. Without user_consent_saved_on_page_load, the callback skips every later page load of a visitor who answered.

A scripts_specific_loaded callback with a switch on level grants the signals of Microsoft Clarity, the Meta Pixel, HubSpot, and the TikTok Pixel, with "callbacks_force": true beside it. Without callbacks_force, the callback runs only for categories that have tagged scripts, so the untagged vendor code of a category with none does not get a grant. With callbacks_force, the callback runs on every page load and after each answer that accepts a category.

Each vendor call except the HubSpot push checks that the vendor code is on the page. The same callbacks then work on a site that uses only some of the vendors. Add user_consent_saved_on_page_load, callbacks, and callbacks_force to your run() call, next to the options the TermsFeed generator writes.

"user_consent_saved_on_page_load": true,
"callbacks": {
  "user_consent_saved": function (details) {
    // Google Consent Mode v2
    if (typeof window.gtag === 'function') {
      window.gtag('consent', 'update', {
        'analytics_storage': details.tracking ? 'granted' : 'denied',
        'ad_storage': details.targeting ? 'granted' : 'denied',
        'ad_user_data': details.targeting ? 'granted' : 'denied',
        'ad_personalization': details.targeting ? 'granted' : 'denied',
        'functionality_storage': details.functionality ? 'granted' : 'denied',
        'personalization_storage': details.functionality ? 'granted' : 'denied'
      });
    }
  },
  "scripts_specific_loaded": function (level) {
    window.clarityConsent = window.clarityConsent || {
      ad_Storage: 'denied',
      analytics_Storage: 'denied'
    };
    window.hubspotConsent = window.hubspotConsent || {
      analytics: false,
      advertisement: false,
      functionality: false
    };
    window._hsp = window._hsp || [];

    switch (level) {
      case 'functionality':
        // HubSpot
        window.hubspotConsent.functionality = true;
        window._hsp.push(['setHubSpotConsent', window.hubspotConsent]);
        break;

      case 'tracking':
        // Microsoft Clarity
        if (typeof window.clarity === 'function') {
          window.clarityConsent.analytics_Storage = 'granted';
          window.clarity('consentv2', window.clarityConsent);
        }
        // HubSpot
        window.hubspotConsent.analytics = true;
        window._hsp.push(['setHubSpotConsent', window.hubspotConsent]);
        break;

      case 'targeting':
        // Microsoft Clarity
        if (typeof window.clarity === 'function') {
          window.clarityConsent.ad_Storage = 'granted';
          window.clarity('consentv2', window.clarityConsent);
        }
        // Meta Pixel, loaded with fbq('consent', 'revoke') before fbq('init')
        if (typeof window.fbq === 'function') {
          window.fbq('consent', 'grant');
        }
        // TikTok Pixel, loaded with ttq.holdConsent() before ttq.load()
        if (window.ttq && typeof window.ttq.grantConsent === 'function') {
          window.ttq.grantConsent();
        }
        // HubSpot
        window.hubspotConsent.advertisement = true;
        window._hsp.push(['setHubSpotConsent', window.hubspotConsent]);
        break;
    }
  }
},
"callbacks_force": true

The HubSpot call pushes onto the _hsp queue, so it works even before the HubSpot script loads. Remove the calls of any vendor your site does not use. The switch has no case for strictly-necessary, so that category sends nothing.

A withdrawal sends denied to Google as soon as the visitor saves it. The other vendors keep the granted signals on the current page. On the next page load, each vendor starts again from its default state, and HubSpot gets a consent call only for the categories still accepted. Read every moment the callback runs, and the order it runs in after each button, in Free Cookie Consent Callbacks and DOM Events.

Where each vendor takes its default before the callback runs

Google, Meta, and TikTok take a default command in the page before their tag runs, because the callback runs only after Cookie Consent starts. The callback sends the grant, and the default covers the time before the grant and every category the visitor refuses.

Place each default command before the tag of its vendor sends anything, and leave Clarity and HubSpot without one.

Vendor Default before the callback Where it goes
Google Consent Mode v2 gtag('consent', 'default', {...}) with every signal denied First script in <head>, after only the charset meta, above the Google tag, the Google Tag Manager container, and the Cookie Consent block
Microsoft Clarity No default command; turn off the Clarity "Cookies" setting, so Clarity records every visitor without cookies until it receives consent In the Clarity project settings, not in the page
Meta Pixel fbq('consent', 'revoke') Inside the pixel code, before fbq('init', ...)
TikTok Pixel ttq.holdConsent() Inside the pixel base code, before ttq.load(...)
HubSpot No default command; window.disableHubSpotCookieBanner = true turns off the HubSpot consent banner Near the top of <head>, below any Consent Mode default and before the HubSpot code loads

HubSpot does not document whether its tracking code stores analytics cookies before the first setHubSpotConsent call once its consent banner is off. Check for the __hstc cookie before the answer. A cookie there means switching to the tagged tracking code, or on HubSpot CMS to the HubSpot consent banner. Run the full check with How to verify the HubSpot consent setup.

Each vendor setup ends with a check of what the vendor sends and stores before the answer. Follow the Google setup and its check in Set Up Google Consent Mode v2, and the Clarity one in Block Microsoft Clarity Until Consent. Follow the pixel and HubSpot setups in Block the Meta Pixel Until Consent, Block the TikTok Pixel Until Consent, and Block HubSpot Tracking Until Consent.

A denied Google or Clarity signal stops new cookies, and Cookie Consent does not delete cookies a vendor stored before the visitor withdrew. Cookies stored before a withdrawal stay until they expire or your own code removes them. Clarity documents that it deletes its cookies when a visitor rejects them, and that window.clarity('consent', false) erases them, but not that a denied consentv2 value does. These callbacks send denied for a Clarity key only in a call that grants the other key. Clarity then does not receive a denied signal after a withdrawal unless the visitor still accepts the other Clarity category.

The signals reach only the vendor code on the page. A vendor that runs on its own server, a platform that injects its own tracking, and an untagged script that ignores the signals keep running whatever the visitor chose. Tag each untagged script with Block Scripts Until Consent.