NOTE: This is not legal advice. We are not lawyers. It’s also not the only thing you’ll need to do to reach GDPR compliance for your business. Cookie consent is only one portion of GDPR compliance. Please consult legal counsel before implementing this solution.
Another note: This solution works for cookies fired from inside the GTM container. It won’t prevent cookie placement for those placed outside the container.
We’ve already provided some GDPR basics for marketers. This post gets a lot more tactical.
Under the General Data Protection Regulation (GDPR), the ideal cookie consent form will:
- Detect your location and see whether you’re in the EU
- Based on your location, display the cookie consent (or not)
- Request cookie consent
- If you consent, place analytics cookies as usual
- By default, let you browse the site, but turn off analytics cookies, providing a seamless user experience
- Oh, and since you have about 48 hours (GDPR goes into effect May 25th), require as little developer time as possible.
Ask, and ye shall receive: This step-by-step uses Google Tag Manager (GTM) to create a cookie consent banner that pops up at the bottom of your site only for EU visitors. The banner asks visitors to opt-in. If they don’t, they can still browse the site, but GTM will not fire cookies that require consent.
To set this up, you need to understand GTM and GTM configuration. When you’re done, you’ll get something like this:
Step 1: Sign up for an ipinfo.io account
First, you need a way to identify visitors from the European Union. IP Info provides an API to do just that.
It’s free for up to 1,000 requests/day. We get more traffic than that, so we’re paying $100/month for up to 40K requests/day. Not bad.
After signup you get an API token:
Copy that and hang on to it for later.
Step 2: Generate a cookie consent banner at Cookie Consent by Insites
At Cookie Consent by Insites, you can generate a Cookie Consent banner that matches the look and feel of your site.
Once you have configured and styled your banner, copy the code in the box on the right-hand side and hang on to it for later.
Step 3: Configure Google Tag Manager
For this step, we’re assuming you know a bit about GTM variables, triggers, and tags work. This is where the rubber meets the road. If you aren’t sure what this all means, stop. Get your analytics nerd to help out.
Set up country lookup
Use this code:
Replace the YOUR-TOKEN-GOES-HERE portion with your IP Info API Token you set aside from Step 1.
Then create a data layer variable to pull the value of that Country Code.
Once the Country Code is available in the data layer, use a Lookup Table variable to look for each of the EU Alpha-2 Country Codes and return a “Yes” if they are in the EU and a “No” for all other Country Codes.
That will inform a trigger called “IP Event – EU” which will show/hide the Cookie Consent banner based on location.
Add the cookie consent banner
Next, take your script from Step 2 and create a Custom HTML tag to fire that when the “IP Event – EU” trigger meets its criteria.
If the visitor accepts, the banner sets a first-party cookie. Otherwise, no cookies for them.
We’ll also need a trigger that verifies the corresponding cookie values if the visitor accepts.
Once that trigger executes, we send a data layer event and trigger.
Here’s example code for that data layer event.
The “cookieConsent” Custom Event then becomes the trigger that you use to fire all tags for EU visitors.
Make sure this doesn’t impact any tracking you’re doing for non-EU visitors: Delay your tags to fire on Window Loaded (not Pageview), and ensure your “In The EU” variable equals “No.” That way, the Country Code process has a chance to run.
Test! Test! Test! Test on staging or in Google Tag Manager’s preview mode:
Next, you’ll want to find a proxy service that allows you to view the preview mode URL from a server in the EU. We used Hide Me, a service that has options to proxy from Holland or Germany.
Be sure you test this on a mobile device and in every possible form factor. We didn’t, and our social share ribbon overlapped with the consent button. Luckily @_sebastiansimon was on the case and let us know. We’re fixing it as I write this.
Done! And A Question
That’s it! You now have a low-code cookie consent form in place.
We did grapple with one question, and we’d love your opinion: Should we display the cookie consent for everyone, regardless of location? That way if someone from the EU is, say, traveling in Canada, the would still see the form? We don’t want to litter our site with forms. We don’t want to get fined a few million Euros, either. GTM exceptions are a solution to respect cookie exceptions when needed.
Questions or comments? Leave them below.
Great article and very useful information. My question is: If the EU can not load cookies before consent, why does nobody (or almost nobody) do it? On your page I see that the cookies have been loaded before my consent. I am doing it in the places I do but I feel a little “silly”, or is there something that escapes me?
Thanks in any case for your method, it is an alternative but I would prefer to continue using a lightweight plugin since calls to Google affect performance.
Hi, Santiago. Thanks for reading!
It’s important to note that all this solution does is block the cookies that are generated via GTM tags. It is not the only step in becoming GDPR compliant. But it is a very important one, as most folks send data off to the third-party platforms via tag management solutions.
Do you have a lightweight plugin you prefer for this task? The trouble with plugins, in my experience, is there’s always a risk of them getting outdated and/or not playing nice with new versions of WordPress, etc. Still would love to hear about it, if you have one you like.
Thanks for your reply! so I’m confused is because the most usual thing in websites around the net (even in the EU) is to load the cookies BEFORE the consent. That’s why I asked you why you have not implemented it. Is it or is it not mandatory to wait to load the cookies until you receive the express consent of the user of the website?
Regarding the plugins, I am very careful with their choice and their maintenance. Cookie Notice by Dfactory is for me the best option, do not affects performance, GDPR compliant and includes a very useful feature to not load the scripts you want until you receive the consent.
Thanks a lot for your time and insights!
GDPR requires opt-in for all cookies, whereas most cookie notices prior to the EU were opt-out.
In our situation, some cookies load by virtue of scripts hosted outside of Google Tag Manager. The plugin solution would definitely help there, so thanks for the tip!
But this article addresses delaying the firing of any/all tags within GTM that would generate cookies until opt-in occurs.
I run an IP Geolocation API – ipdata.co – that explicitly returns an is_eu field, telling you if the user is in the EU.
This would make your lookup logic much easier.
Thanks for the tip, Jonathan. There are a lot of IP lookup solutions out there that do slightly different things beyond just the country code and I’m sure our readers appreciate having options to choose one that’s right for them.
Hey Michael, Brilliant steps.
Easy to set up and configure. Did it completely.
Thanks for reading.
I believe there might be several issues with this solution, so I thought I would drop my 5 cents. Some of the potential problems I see are:
1. GDPR applies to EU citizens, not users browsing from EU. IP address will only identify the device and its current location. You might still reach EU citizen while he’s visiting any other region.
2. This cookie consent would only be proper for anonymous web tracking. If you want to track PIIs or connect later on visitor data to some identifier, you will likely need more granular permission model.
3. Storing consent on user’s device might not be the best solution. After all it is mostly supposed to help you in legal processing of data. I believe because of that it would be best recorded in your own database. Cookies can be erased instantly, leaving no trace of user consent.
Wish all fun with compliance 😉 I don’t believe that 100% compliance is possible anyway.
Good points on all fronts. We’re definitely not billing this as a comprehensive solution for 100% compliance, but as a step toward compliance in good faith. I’d encourage folks to iterate on this method to fit the needs of their business.
One way to get around the scenario you mentioned in point 3 is to also send in the consent cookie value when given into GA as a user-scoped Custom Dimension.
GDPR is for all european visitors worldwide! European visitors who are not in EU can not consent with your solution. IP checking is not the soluce! I don’t know how to do with eu visitors who lives in America or Africa or Asia….
You can show the consent banner to all visitors as an alternative for the cases you mention.
The IP lookup is a way to mitigate some potential data loss from other non-EU locations.
Why do you inject the datalayer variable and base your other tags on this trigger?
Can’t you just you use the “Cookie consent | Allow or dismiss” trigger you created one step before?
It seems to me that you’re doing a few steps more that are non required.
The Data Layer Variable is a redundancy to differentiate the consent event from other gtm.click events in the Preview Mode.
You can forgo this step if you like.
Thanks for reading!
This is really informative & knowledge full article but i have a question. If the EU can not load cookies before consent, why does nobody do it?
Honestly, I think there’s been inconsistent application and enforcement of the law in the EU and larger companies would rather contest it in court than lose precious customer data.
I am struggling like hell as I cannot go beyond the trigger “cookie consent – allow or dismiss”. Somehow the conditions are not working for me. The click field is “Allow cookies” and I also tried click classes contains “cc-allow”.
click classes= Data Layer Variable string ‘cc-btn cc-allow’
click text = Auto-Event Variable string ‘Allow cookies’
cookie consent = 1st Party Cookie undefined undefined
I’ll email you around troubleshooting this, as it’s hard to know what’s wrong unless we have Edit access to your container.