> ## Documentation Index
> Fetch the complete documentation index at: https://docs.replo.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Cookie Consent

> Ask visitors for consent before your tracking scripts load, so your pixels stay GDPR and CCPA compliant.

export const Screenshot = ({src, altText, width, shadow = true}) => {
  const generateAltText = imageSrc => {
    if (!imageSrc) return "Screenshot";
    const filename = imageSrc.split("/").pop() ?? "";
    const nameWithoutExt = filename.replace(/\.[^/.]+$/, "");
    const readable = nameWithoutExt.replace(/[-_]/g, " ").replace(/\b\w/g, char => char.toUpperCase());
    return readable === "" ? "Screenshot" : readable;
  };
  const finalAltText = altText ?? generateAltText(src);
  const imageWidth = width ? `${width}px` : "100%";
  return <div style={{
    position: "relative",
    width: "100%",
    borderRadius: "12px",
    overflow: "hidden",
    boxSizing: "border-box",
    display: "flex",
    justifyContent: "center"
  }}>
      {}
      <svg style={{
    position: "absolute",
    top: 0,
    left: 0,
    width: "100%",
    height: "100%",
    zIndex: 0,
    pointerEvents: "none"
  }} viewBox="0 0 1920 1080" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice">
        <g clipPath="url(#clip0_5067_2569)">
          <rect width="1920" height="1080" fill="black" />
          <g opacity="0.9" filter="url(#filter0_fn_5067_2569)">
            <mask id="mask0_5067_2569" style={{
    maskType: "alpha"
  }} maskUnits="userSpaceOnUse" x="539" y="-367" width="2018" height="1261">
              <rect x="539" y="-367" width="2017.6" height="1261" fill="#C4C4C4" />
            </mask>
            <g mask="url(#mask0_5067_2569)">
              <g filter="url(#filter1_f_5067_2569)">
                <path d="M880.949 82.6474L1798.19 -385.441L2215.11 -385.441L2725.35 -260.618L936.539 437.057L880.949 82.6474Z" fill="url(#paint0_linear_5067_2569)" />
              </g>
              <g filter="url(#filter2_f_5067_2569)">
                <ellipse cx="462.152" cy="150.719" rx="462.152" ry="150.719" transform="matrix(0.914846 -0.403803 0.330497 0.943807 1250.96 112.228)" fill="#FEBC2E" />
              </g>
              <g filter="url(#filter3_f_5067_2569)">
                <path d="M1687.1 56.3942C2102.4 -149.497 2274.54 -159.301 2672.61 -80.8668L2803.87 183.851L884.491 784.367C849.346 777.831 951.195 612.791 1228.77 362.78C1281.1 315.653 1271.81 262.285 1687.1 56.3942Z" fill="url(#paint1_linear_5067_2569)" />
              </g>
              <g opacity="0.7" filter="url(#filter4_f_5067_2569)">
                <path d="M1975.09 -76.9728C2367.51 -238.299 2270.38 -191.657 2637.67 -120.329L2758.78 120.402L1001.73 662.047C969.304 656.104 932.244 530.091 1043.42 349.988C1182.4 124.86 1518.29 110.824 1975.09 -76.9728Z" fill="#B7FEAE" fillOpacity="0.5" />
              </g>
              <g filter="url(#filter5_f_5067_2569)">
                <path d="M2052.63 99.5535C2383.11 16.7587 2366.44 -59.7112 2665.61 -7.17013L2707.81 170.156L1276.64 569.14C1250.23 564.762 1220.04 471.939 1310.6 339.273C1423.8 173.44 1803.59 161.946 2052.63 99.5535Z" fill="#EF196E" />
              </g>
              <g opacity="0.4" filter="url(#filter6_f_5067_2569)">
                <ellipse cx="462.152" cy="218.806" rx="462.152" ry="218.806" transform="matrix(0.914846 -0.403803 0.330497 0.943807 1152.46 417.938)" fill="#FFEB80" />
              </g>
              <g filter="url(#filter7_f_5067_2569)">
                <ellipse cx="462.152" cy="150.719" rx="462.152" ry="150.719" transform="matrix(0.914846 -0.403803 0.330497 0.943807 1913.18 237.904)" fill="#B7FEAE" />
              </g>
              <g filter="url(#filter8_f_5067_2569)">
                <g opacity="0.4" filter="url(#filter9_f_5067_2569)">
                  <path d="M1551.1 493.269L2619.23 -0.477507L3125.23 -71.2418L3756.49 -67.6927L1652.68 739.798L1551.1 493.269Z" fill="url(#paint2_linear_5067_2569)" />
                </g>
              </g>
              <g filter="url(#filter10_f_5067_2569)">
                <g opacity="0.4" filter="url(#filter11_f_5067_2569)">
                  <path d="M1696.12 652.03L2820.04 310.947L3330.91 310.947L3956.12 401.903L1764.24 910.278L1696.12 652.03Z" fill="url(#paint3_linear_5067_2569)" />
                </g>
                <g opacity="0.4" filter="url(#filter12_f_5067_2569)">
                  <path d="M1628.55 727.676L2843.38 257.743L3271.53 195.271L3903.03 210.271L1788.72 978.91L1628.55 727.676Z" fill="url(#paint4_linear_5067_2569)" />
                </g>
              </g>
            </g>
          </g>
        </g>
        <defs>
          <filter id="filter0_fn_5067_2569" x="637.809" y="-607" width="2158.79" height="1741" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="120" result="effect1_foregroundBlur_5067_2569" />
            <feTurbulence type="fractalNoise" baseFrequency="1 1" stitchTiles="stitch" numOctaves="3" result="noise" seed="7978" />
            <feColorMatrix in="noise" type="luminanceToAlpha" result="alphaNoise" />
            <feComponentTransfer in="alphaNoise" result="coloredNoise1">
              <feFuncA type="discrete" tableValues="1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 " />
            </feComponentTransfer>
            <feComposite operator="in" in2="effect1_foregroundBlur_5067_2569" in="coloredNoise1" result="noise1Clipped" />
            <feFlood floodColor="rgba(0, 0, 0, 0.25)" result="color1Flood" />
            <feComposite operator="in" in2="noise1Clipped" in="color1Flood" result="color1" />
            <feMerge result="effect2_noise_5067_2569">
              <feMergeNode in="effect1_foregroundBlur_5067_2569" />
              <feMergeNode in="color1" />
            </feMerge>
          </filter>
          <filter id="filter1_f_5067_2569" x="878.4" y="-387.991" width="1849.5" height="827.597" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="1.27461" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter2_f_5067_2569" x="1129.77" y="-334.846" width="1187.61" height="805.41" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="84.0203" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter3_f_5067_2569" x="855.856" y="-148.194" width="1969.97" height="954.514" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="10.9761" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter4_f_5067_2569" x="958.113" y="-196.498" width="1811.26" height="869.143" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="5.29875" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter5_f_5067_2569" x="1149.75" y="-124.443" width="1658.06" height="793.583" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="50" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter6_f_5067_2569" x="1098.27" y="39.191" width="1098.61" height="797.277" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="60.1484" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter7_f_5067_2569" x="1886.85" y="-114.306" width="997.881" height="615.684" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="36.5888" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter8_f_5067_2569" x="1540.3" y="-82.0399" width="2226.99" height="832.636" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="5.39908" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter9_f_5067_2569" x="1547.97" y="-74.3651" width="2211.64" height="817.287" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="1.56172" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter10_f_5067_2569" x="1598.84" y="165.553" width="2387" height="843.074" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="14.8586" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter11_f_5067_2569" x="1693" y="307.824" width="2266.24" height="605.577" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="1.56172" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <filter id="filter12_f_5067_2569" x="1617.84" y="184.562" width="2295.9" height="805.057" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
            <feFlood floodOpacity="0" result="BackgroundImageFix" />
            <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
            <feGaussianBlur stdDeviation="5.35445" result="effect1_foregroundBlur_5067_2569" />
          </filter>
          <linearGradient id="paint0_linear_5067_2569" x1="1803.15" y1="-385.441" x2="1040.5" y2="259.543" gradientUnits="userSpaceOnUse">
            <stop stopColor="#FF7D54" />
            <stop offset="1" stopColor="white" stopOpacity="0" />
          </linearGradient>
          <linearGradient id="paint1_linear_5067_2569" x1="2283.14" y1="-17.1385" x2="1351.98" y2="310.625" gradientUnits="userSpaceOnUse">
            <stop stopColor="#B7FEAE" />
            <stop offset="0.65537" stopColor="#EF196E" />
            <stop offset="1" stopColor="#274AE2" />
          </linearGradient>
          <linearGradient id="paint2_linear_5067_2569" x1="2625.25" y1="-1.32004" x2="2201.56" y2="820.649" gradientUnits="userSpaceOnUse">
            <stop stopColor="#3A4CF0" />
            <stop offset="1" stopColor="#F5FAD9" stopOpacity="0" />
          </linearGradient>
          <linearGradient id="paint3_linear_5067_2569" x1="2826.12" y1="310.947" x2="2295.81" y2="1065.13" gradientUnits="userSpaceOnUse">
            <stop stopColor="#EF196E" />
            <stop offset="1" stopColor="white" stopOpacity="0" />
          </linearGradient>
          <linearGradient id="paint4_linear_5067_2569" x1="2452.05" y1="509.031" x2="2135.78" y2="1074.58" gradientUnits="userSpaceOnUse">
            <stop offset="0.166667" stopColor="#EF196E" />
            <stop offset="0.541667" stopColor="#FFEB80" stopOpacity="0.25" />
            <stop offset="1" stopColor="#274AE2" stopOpacity="0" />
          </linearGradient>
          <clipPath id="clip0_5067_2569">
            <rect width="1920" height="1080" fill="white" />
          </clipPath>
        </defs>
      </svg>

      {}
      <div style={{
    position: "relative",
    zIndex: 1,
    padding: "clamp(24px, 4vw, 48px)",
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: "100%"
  }}>
        <img src={src} alt={finalAltText} style={{
    width: imageWidth,
    maxWidth: "100%",
    height: "auto",
    display: "block",
    borderRadius: "8px",
    boxShadow: shadow ? "0 20px 60px rgba(0, 0, 0, 0.3)" : "none"
  }} />
      </div>
    </div>;
};

Cookie consent asks each visitor whether your tracking scripts are allowed to run, and holds those scripts back until they answer. It lives in **Site settings**, under the **Scripts & Pixels** tab, and covers the pixels and analytics you add there. Turn it on when you sell into regions with privacy laws like GDPR (EU) or CCPA (California), where firing tracking cookies before a visitor agrees can put you out of compliance.

Replo handles this natively, with its own consent banner and category system, so you do not need a separate consent tool for the pixels you manage in Scripts & Pixels. If your store already runs Cookiebot, you can connect it as your consent platform instead, and Replo hands consent over to it (see "Using Cookiebot instead of Replo's banner" below).

## How it works

When cookie consent is on, Replo does not load your tracking scripts on the first page view. Instead a banner asks the visitor to accept or reject tracking. The script tags only enter the page once the visitor grants the matching category, so nothing fires beforehand. This is stricter than tag managers that load a script and then ask it to hold back: with Replo, the script is never added to the page until consent allows it.

Each managed script is tied to one or more consent categories. A script loads only after the visitor grants **all** of the categories it needs. With Replo's own banner, the choice is remembered in a `replo_consent` cookie so returning visitors are not asked again until it expires. (With Cookiebot connected, Cookiebot stores and replays the choice instead.)

## Consent modes

The **Cookie consent** control at the top of the Scripts & Pixels tab has three modes:

* **Off**: no banner, and every managed script loads immediately for every visitor. This is the default and matches how a site with no consent layer behaves.
* **Simple**: shows a banner with **Accept all** and **Reject all**. The visitor makes one choice that covers every category at once.
* **Per category**: shows the same banner plus a **Customize** option, where the visitor can grant some categories and deny others (for example, allow analytics but not marketing).

## What consent gates

With consent on, these load only after the visitor agrees:

* **Pixels**: Google Analytics 4, Google Tag Manager, Meta Pixel, TikTok Pixel, Pinterest Tag, Reddit Pixel, and Snapchat Pixel.
* **Behavior analytics**: Hotjar and Microsoft Clarity.
* **Attribution and data**: Triple Whale, Segment, and Northbeam.
* **Custom scripts** you add in Scripts & Pixels, gated by the categories you pick.
* **Replo's own analytics**, which power [Insights](/apps/insights), gated on the analytics category.

Each built-in pixel maps to a sensible category by default: analytics tools (GA4, Hotjar, Clarity) require the analytics category, and ad pixels (Meta, TikTok, Pinterest, Reddit, Snapchat) require marketing. Google Tag Manager requires both, since it can load either kind of tag.

## Consent categories

Replo groups scripts into these categories, matching the standard ones used across ecommerce privacy tools:

* **Necessary**: always on, and never shown as a choice. These are the scripts your site needs to function.
* **Analytics**: measurement and traffic tools.
* **Marketing**: ad pixels and retargeting.
* **Preferences**: scripts that remember visitor settings.
* **Sale of data**: tracking that shares data with third parties, the category CCPA's "Do Not Sell" rules apply to.

In **Simple** mode, accepting grants every category and rejecting denies all of them. In **Per category** mode, the visitor decides category by category.

## Turn on cookie consent

<Steps>
  <Step title="Open the Scripts & Pixels tab">
    In the [Site Builder](/apps/website-builder), open the **⋯ more-options menu** in the top bar, choose **Site settings**, and select the **Scripts & Pixels** tab.

    <Screenshot src="/images/cropped/site-settings-pixels.png" altText="The Scripts & Pixels tab in Site settings, with the Cookie consent control at the top and built-in entries for common pixels" />
  </Step>

  <Step title="Choose a consent mode">
    Open the **Cookie consent** dropdown at the top of the tab and pick **Simple**
    or **Per category**. Leave it on **Off** if you do not want a banner.
  </Step>

  <Step title="Confirm which scripts are managed">
    Any pixel or custom script added through Scripts & Pixels is consent-managed
    automatically. If you see scripts listed under **Unmanaged scripts**, those
    were pasted directly into your site and load regardless of consent. Use
    **Convert to managed** on each one so consent covers it too.
  </Step>

  <Step title="Publish">
    Publish your site for the consent banner and gating to go live. Changes to scripts and consent settings apply to your published site on your next publish.
  </Step>
</Steps>

## Custom scripts and consent

When you add a custom script in Scripts & Pixels, and consent is on, Replo asks which consent categories it needs. The script loads only after the visitor grants every category you selected, so pick the narrowest set that fits (for example, marketing for an ad pixel, analytics for a measurement tool). You can also ask Replo in chat to add a script and tell it which category to gate on.

## Scripts that bypass consent

Consent only covers scripts Replo manages. A script pasted straight into your site's code, outside of Scripts & Pixels, loads for every visitor no matter what they choose. Replo flags these under **Unmanaged scripts** with a warning so you can spot them, and offers **Convert to managed** to bring them under consent. If you use tracking that you added outside Scripts & Pixels, convert it so your consent banner actually governs it.

## Customizing the banner

The banner Replo installs has default copy ("We value your privacy"), an **Accept all** and **Reject all** button, a **Customize** flow in Per category mode, and a link to your privacy policy. You can ask Replo to restyle it, reword it, or point the privacy policy link at your own page. Keep the banner in place while consent is on, since it is what collects the visitor's choice.

## Using Cookiebot or another consent platform instead of Replo's banner

If your store already standardizes on Cookiebot, connect it under **Consent Management** in the Scripts & Pixels tab with your **Domain Group ID (CBID)**, found in the Cookiebot dashboard under Settings. Once connected, Cookiebot owns consent for the site:

* Cookiebot's banner collects the visitor's choice, and Replo's native banner stays out of the way.
* Every managed script in Scripts & Pixels is tagged for Cookiebot automatically, so it stays inert until the visitor consents to its category. Replo's own analytics follows Cookiebot's answer too.
* If you already pasted Cookiebot's script into your site yourself, remove it once you connect Cookiebot here — two copies of the loader fight over consent, and the tab flags this for you.
* Connecting Cookiebot turns Replo's own **Cookie consent** control **Off** automatically, so visitors see one banner, not two. If you turn it back on later, the tab warns you about the double-banner conflict.
* Raw scripts pasted directly into your site bypass the platform's tagging and load regardless of consent. The tab flags them, and **Convert to managed** brings each one under the platform's control.

Other consent platforms that support per-script manual blocking (Termly, CookieYes, and similar) can be connected by asking Replo in chat — the agent configures the platform's loader and script-tagging attributes from that platform's documentation. Cookiebot is the fully built-in option; for others, verify the platform's banner appears and your scripts stay held until consent.

## FAQ

<AccordionGroup>
  <Accordion title="Do I need to republish for consent changes to take effect?">
    Yes. Turning consent on or off, changing the mode, and adding or converting scripts all apply to your live site on your next publish. You can check the behavior in preview before you publish.
  </Accordion>

  <Accordion title="Will returning visitors keep getting asked?">
    No. With Replo's banner, the visitor's choice is stored in a `replo_consent`
    cookie that lasts about six months, so the banner does not reappear until it
    expires or the visitor clears it. If a visitor changes their mind and revokes
    a category, Replo reloads the page so the now-disallowed scripts stop running.
    With Cookiebot connected, Cookiebot stores the choice and handles revocation
    itself; Replo's cookie is not used.
  </Accordion>

  <Accordion title="I already use a third-party consent tool like Cookiebot or OneTrust. Can I keep it?">
    Cookiebot has first-class support: connect it in Scripts & Pixels with your
    Domain Group ID and it becomes your site's consent platform, gating every
    managed script automatically (see "Using Cookiebot instead of Replo's banner"
    above). Do not add Cookiebot as a custom script, and set Replo's own cookie
    consent to **Off** once it is connected, so visitors see only Cookiebot's
    banner. Other consent tools like OneTrust are not integrated this way; for
    those, Replo's built-in cookie consent is the simpler path since it already
    gates the pixels you add in Scripts & Pixels. Use one consent system or the
    other, never both.
  </Accordion>

  <Accordion title="Does consent detect the visitor's region automatically?">
    No. When consent is on, the banner shows to every visitor. If you only need it
    for certain regions, that is a good reason to keep the banner simple and
    applicable everywhere rather than trying to show it conditionally.
  </Accordion>

  <Accordion title="Does turning consent on hurt my tracking?">
    It changes what you can measure to what visitors allow, which is the point of compliance. Visitors who accept are tracked exactly as before. The tradeoff is that data from visitors who decline is not collected, so expect your pixel and analytics counts to reflect consent rates rather than total traffic.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Adding Scripts" href="/features/scripts">
    Add pixels and custom scripts, site-wide or per page.
  </Card>

  <Card title="Integrations" href="/integrations/introduction">
    Connect GA4, Meta, TikTok, and other tracking tools.
  </Card>

  <Card title="Act on Your Analytics" href="/analytics">
    Read your traffic and sales after you launch.
  </Card>

  <Card title="Publishing" href="/publishing">
    Publish your site so consent settings go live.
  </Card>
</CardGroup>
