Compliance
POPIA Cookie Consent Banner for South African Sites.
A POPIA cookie consent banner is a legal requirement for any South African website that uses cookies or pixels to process identifiable personal information — which is almost every ecommerce store. The Protection of Personal Information Act (POPIA), specifically section 69 and the direct marketing provisions, treats identifying cookies, pixels, and fingerprinting as processing that requires informed consent. This guide gives you the legal context, a compliant banner in plain language, a Google Consent Mode v2 default-deny implementation for GTM, a clean custom HTML and JS example, and the GTM triggers that stop Meta Pixel, GA4 and TikTok from firing until the visitor actually consents. Note that this is practical guidance, not legal advice — confirm with your Information Officer.
Prerequisites
- Registered Information Officer with the South African Information Regulator
- Privacy policy and cookie policy pages published on your site
- Google Tag Manager installed (or direct tag control via a tag manager you own)
- List of all cookies and pixels you currently fire, grouped into categories: necessary, analytics, marketing, preferences
- Process for customers to withdraw consent (an accessible 'Cookie settings' link in the footer)
Step 1. Understand what POPIA actually requires for cookies
POPIA does not name cookies specifically, but if a cookie or pixel processes information that can identify a person (hashed email, IP address, device ID, behavioural profile), it falls under the Act. Consent must be voluntary, specific, and informed. Pre-ticked boxes and implied consent from continued browsing are not compliant. The Regulator has signaled alignment with GDPR norms.
Step 2. Audit every cookie and pixel
Open DevTools > Application > Cookies on a fresh session and list every cookie. Do the same for every pixel in Tag Assistant. Classify each into necessary (cart, checkout, CSRF), analytics (GA4, Clarity, PostHog), marketing (Meta, TikTok, Google Ads), or preferences (language, currency).
Step 3. Set Google Consent Mode v2 defaults in GTM
Install a Consent Initialization tag that fires BEFORE every other tag. It sets all consent signals to denied by default. When the user accepts, a second update call flips the granted signals.
<!-- Paste this in your site <head> BEFORE the GTM snippet -->
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
analytics_storage: 'denied',
functionality_storage: 'denied',
personalization_storage: 'denied',
security_storage: 'granted',
wait_for_update: 500,
});
// Region-specific override if you want a stricter default for ZA
gtag('consent', 'default', { region: ['ZA'], wait_for_update: 500 });
</script> Step 4. Ship a custom compliant banner
You can use Klaro, Cookiebot or Termly if you want a polished product, but a clean custom banner is 120 lines of HTML and JS. The snippet below stores the consent state, fires the gtag update, and pushes a dataLayer event GTM can listen for.
<div id="cc-banner" hidden role="dialog" aria-label="Cookie consent">
<p>
We use cookies and pixels to run this site, measure how it performs, and
serve relevant ads. You can accept all, reject non-essential, or manage
your preferences. See our <a href="/privacy">privacy policy</a>.
</p>
<button data-cc="accept">Accept all</button>
<button data-cc="reject">Reject non-essential</button>
<button data-cc="manage">Manage preferences</button>
</div>
<script>
(function(){
var KEY = 'cc_consent_v1';
function save(state){ localStorage.setItem(KEY, JSON.stringify(state)); apply(state); }
function apply(state){
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'update', {
ad_storage: state.marketing ? 'granted' : 'denied',
ad_user_data: state.marketing ? 'granted' : 'denied',
ad_personalization: state.marketing ? 'granted' : 'denied',
analytics_storage: state.analytics ? 'granted' : 'denied',
});
dataLayer.push({ event: 'cc_consent_update', consent: state });
document.getElementById('cc-banner').hidden = true;
}
var saved = localStorage.getItem(KEY);
if (!saved) document.getElementById('cc-banner').hidden = false;
else apply(JSON.parse(saved));
document.querySelector('[data-cc="accept"]').onclick = function(){ save({ analytics: true, marketing: true }); };
document.querySelector('[data-cc="reject"]').onclick = function(){ save({ analytics: false, marketing: false }); };
document.querySelector('[data-cc="manage"]').onclick = function(){ /* open your prefs UI */ };
})();
</script> Step 5. Gate pixels in GTM behind the consent event
For every marketing tag (Meta Pixel, TikTok Pixel, Google Ads Conversion), set the trigger to fire only on the cc_consent_update event AND where consent.marketing equals true. For analytics tags, use consent.analytics equals true. This is the actual gate — Consent Mode v2 adjusts behaviour but GTM triggers keep tags from firing at all.
Step 6. Add a 'Cookie settings' link in the footer
POPIA requires that consent be as easy to withdraw as it is to give. Link a 'Cookie settings' button in your footer that reopens the banner, lets the user flip categories, and saves the new state. Do not bury it inside the privacy policy.
Step 7. Review quarterly and log consent
Store the consent decision with a timestamp (in localStorage for the user, and optionally in your own DB for audit) and review the banner every quarter as new tools are added. The Information Regulator expects evidence of consent if challenged.
SA gotchas
- Your Information Officer must be registered with the SA Information Regulator. No banner fixes that — register first via the Regulator portal.
- Consent withdrawal must be visible and accessible. A buried link in a privacy policy is not acceptable under POPIA guidance.
- Pre-ticked boxes are non-compliant. Every category except 'necessary' must default to unchecked and denied.
- Google Consent Mode v2 alone does not stop Meta Pixel, TikTok, or other non-Google tags from firing. You still need GTM triggers gated on your own consent event.
- Auto-blocking products (OneTrust, Cookiebot) rewrite script tags — double-check your Shopify checkout and custom pixels still work after install. Test a full checkout before calling it done.
Frequently asked questions
Does POPIA require a cookie banner?
POPIA requires informed consent for processing personal information, which includes identifying cookies and pixels. A banner is the standard way to capture that consent. Without one, you are likely non-compliant.
What is the fine for breaching POPIA?
Fines can reach R10 million or 10 years imprisonment in the most serious cases. Most enforcement to date has been warnings and remediation orders, but the Regulator has begun issuing infringement notices — treat it seriously. Consult a South African privacy attorney on material questions.
Can I rely on legitimate interest for marketing cookies?
For direct marketing to existing customers, section 69(3)(a) allows a narrow soft opt-in. For cold marketing cookies and third-party pixels, you need explicit consent. Default to consent for all marketing pixels.
What about GA4 and Meta Pixel specifically?
Both fire when consent.analytics or consent.marketing are true. Gate GA4 on analytics consent and Meta Pixel on marketing consent. See the GA4 and Meta Pixel guides for consent-gated load patterns.