Cookie Consent Banner

Drop a compliant consent banner on your site in minutes. Gate Google Tag Manager, Meta Pixel, Hotjar, or any other tracker behind explicit visitor consent. Geo-target the banner so visitors in regions that don't require consent (e.g. most US states) don't see it.

How It Works

  1. Visitor lands on your page; the embed checks dismiss memory.
  2. If the visitor hasn't already accepted or declined, the banner renders at the bottom of the page.
  3. Visitor clicks Accept (the fm-cta button) or Decline (the fm-close button).
  4. The choice is saved to localStorage with the configured dismiss behavior (default: PERMANENT).
  5. On Accept, the embed fires the cta:click JS event - your code listens and loads GTM (or any other tag).

Setting Up the Banner

  1. Dashboard -> Messages -> New, pick the Cookie Banner template.
  2. Edit the headline + body copy in the visual editor (or write your own HTML / CSS in the code editor).
  3. Set the dismiss behavior to PERMANENT so the banner never reappears once a choice is made.
  4. Save. The banner appears on every page where the embed loads.

Gating Google Tag Manager Behind Consent

The right pattern is to load GTM only after the visitor accepts. FloatMessage fires a cta:click event on Accept; you listen for it and inject GTM at that moment.

<!-- Place anywhere AFTER the FloatMessage script tag -->
<script>
window.FloatMessage = window.FloatMessage || { _q: [] };
FloatMessage._q.push(["on", "cta:click", function (detail) {
  // Only fire for the cookie banner, not other CTA clicks.
  if (detail.template !== "cookie-banner") return;

  // Load GTM (replace GTM-XXXXXX with your container ID).
  (function (w, d, s, l, i) {
    w[l] = w[l] || [];
    w[l].push({ "gtm.start": new Date().getTime(), event: "gtm.js" });
    var f = d.getElementsByTagName(s)[0],
        j = d.createElement(s),
        dl = l != "dataLayer" ? "&l=" + l : "";
    j.async = true;
    j.src = "https://www.googletagmanager.com/gtm.js?id=" + i + dl;
    f.parentNode.insertBefore(j, f);
  })(window, document, "script", "dataLayer", "GTM-XXXXXX");
}]);
</script>

On the next page load the embed sees the dismiss flag is set, the banner doesn't render, and your cta:click handler isn't needed - so you load GTM unconditionally guarded by your own check on the same localStorage key. See the cookie consent + GTM guide for the full pattern including the second-page-load case.

Show the Banner Only Where Required

GDPR / ePrivacy applies to EU + UK visitors. CCPA applies to California residents. Visitors elsewhere generally don't need to see the banner, and showing it adds friction for no compliance value.

Pair the cookie banner with geo targeting:

{
  "geoCountries": [
    "AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR",
    "HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK",
    "SI","ES","SE",
    "GB",
    "NO","IS","LI",
    "CH"
  ]
}

For California-only display you currently need a separate banner instance with US targeting and your own state-level filtering on the client (sub-country IP geolocation is on the roadmap).

Audit Trail of Consent Decisions

Set a webhook URL on the cookie banner message (Dashboard -> Message -> Webhook URL). Every Accept and Decline fires a JSON POST to that URL with the visitor token, country, page URL, and timestamp - giving you the "demonstrate consent" record GDPR Art. 7 requires.

{
  "type": "consent_event",
  "messageId": "msg_cookies",
  "decision": "accept",
  "visitorToken": "v_kx9d2",
  "country": "DE",
  "pageUrl": "https://example.com/",
  "userAgent": "Mozilla/5.0 ...",
  "submittedAt": "2026-05-13T10:42:09.501Z"
}

What FloatMessage Itself Stores Before Consent

The embed script stores a single localStorage entry (fm_visitor_token) for first-party visitor identification. This is necessary for the chat widget and dismiss memory to work; it's functional storage, not analytics. No third-party cookies, no fingerprinting, no analytics events fire until you explicitly enable them.

If your privacy policy requires consent for first-party functional storage too, gate the FloatMessage script tag itself behind the same Accept handler (don't inject it until consent lands).

Related