Free scan Install guides Developers Compare CMPs About Support Contact
Get Velo

Already have an account? Log in

Can I move a script into Google Tag Manager to make it consent gated?

Consent Mode 29 August 2026· 6 min read
The Velo mascot moves a loose script into a tidy container while a ghost looks on

All posts

Yes for most vendor scripts, and Google Tag Manager gives you a real gate: the tag runs only when its trigger fires and its consent settings allow it. The exception is any script that has to act before the page renders or see the very first request, because a container cannot fire it early enough.

What the move actually changes

A script hardcoded in the head runs the moment the parser reaches it. There is no gate in front of it, which is why a vendor snippet sitting in the head is the most common reason a site sets cookies before the visitor has agreed to anything.

Move it into a container and it stops being markup and becomes a tag. It now runs when a trigger fires it and when its consent settings allow it to proceed. That is exactly what you wanted. It is also the part people underestimate: you have not only added a gate, you have changed when the script runs. For most vendors that is harmless. For a few it is the whole problem.

The scripts that cannot move

Three shapes fail the move, and they fail for the same underlying reason. A container loads and evaluates after the page has already started, and these scripts need to act before that.

  • Anything that has to run before render. Personalisation and A/B testing scripts rewrite the page before the visitor sees it. Behind a trigger they arrive after first paint, so the visitor watches the original content appear and then change. That flicker is the exact thing the script existed to prevent, so moving it does not gate it, it breaks it.
  • Anything that has to see the first request. Some bot and fraud tools are built to observe the earliest moment of a visit. Fired from a container they see a page that has already been open for a while, and their answer changes accordingly.
  • The consent layer itself. You cannot gate the thing that collects consent behind consent. The banner has to be able to run before any decision exists, which is why it belongs in the head, and why it is one of the few scripts that genuinely is strictly necessary.

When a script cannot move, the honest answer is to leave it where it sits and gate it there: your consent tool blocks it in the page, by category, instead of a container withholding it. Same outcome, different mechanism, and the category question is covered in what consent category a script should go in.

STAYS IN THE HEAD Must run before render A/B testing, personalisation Must see the first request some bot and fraud tools The consent layer itself MOVES INTO THE CONTAINER Analytics Advertising and retargeting pixels Session recording Chat and support widgets Embedded players and social widgets The test is timing, not category. A container cannot fire anything early enough to beat first paint.
The question is not what the script does, it is when it has to act. Anything that must run before the page renders stays in the head and gets gated there instead.

Moving it, without leaving a copy behind

  1. Remove it from the head first

    Not last. A script that exists in both places runs twice, and the copy in the head runs ungated, so the container tag you just built proves nothing. This is the most common way a migration ends up looking finished while changing nothing.

  2. Rebuild it as a tag

    A custom HTML tag holding the vendor's snippet, or the vendor's own template if the gallery has one. Prefer the template: it exposes the vendor's parameters as proper fields and usually arrives with its consent settings already declared.

  3. Set the consent settings on the tag, not only the trigger

    In a web tag these live under Advanced Settings, then Consent Settings, where you require additional consent for the tag to fire and name the consent types it depends on. The trigger is the other control. You want both, for the reason in the next section.

  4. Publish, then test on the live page

    Preview mode runs with the container's debug wiring and, very often, a consent state you clicked through yourself a minute earlier. It is good for confirming a tag exists. It is not evidence about what a real visitor gets.

  5. Check both paths in the page, not in the container

    On the deny path the vendor should be absent from the DOM and absent from resource timing, so nothing was injected and nothing was fetched. On the accept path it should appear in both. Resource timing is the one that matters: if the vendor host was fetched, it was fetched, whatever the container reported.

If the vendor still shows up on the deny path after all that, the script you moved is probably not the one firing. Something else on the page is loading it, which is a different fault with its own diagnosis in why the Facebook pixel still loads when your tags are blocked.

A consent check on the tag is not the same as a trigger that waits

This is the distinction that decides whether the gate actually holds. A trigger controls when a tag is considered. Consent settings control whether it is allowed to run once it has been considered.

Gate with a trigger alone and you have covered the first page load and nothing else. A tag whose trigger is a later event, a click, a form submission, a route change in a single page app, is considered again the moment that event happens. With no consent requirement on the tag, it runs then, whatever the visitor chose.

Put the requirement on the tag as well and it holds wherever the tag is reached. The trigger says when to think about firing; the consent settings say whether firing is permitted. Together the gate becomes a property of the tag rather than of one route into it.

Strictly necessary is a claim you then have to keep

The last constraint is not technical. A vendor is sometimes argued as strictly necessary so that it can run before consent, and occasionally that argument is sound. What matters is that the site's own consent notice and cookie table say the same thing, word for word.

If your notice lists a vendor under a category the visitor is invited to refuse, the tag has to honour that refusal. A script running ungated while the page tells the visitor they may decline it is a contradiction a regulator can read straight off your own site, and it is considerably easier to find than a misconfigured container.

Velo blocks by category in the page and passes the same decision into the container, so a script gets the same answer whether it ended up in the head or in a tag.

Common questions

What people ask about this topic.

Can I move a script into Google Tag Manager to make it consent gated?

Usually yes, and for most vendor scripts it is the right move. Once the script is a tag rather than markup in the head, it runs only when a trigger fires it and its consent settings allow it. The exceptions are scripts that have to act before the container can reach them: anything that must run before the page renders, such as A/B testing and personalisation, anything built to observe the very first request, and the consent layer itself, which cannot be gated behind the decision it exists to collect. Those stay in the head and get blocked there by category instead.

Which scripts should stay in the site head?

The ones whose job depends on running early. Personalisation and A/B testing scripts rewrite the page before first paint, so firing them from a container produces exactly the flicker they were installed to prevent. Some bot and fraud tools are built around seeing the earliest moment of a visit. And the consent banner itself has to run before any decision exists. Everything else, including analytics, advertising and retargeting pixels, session recording, chat widgets and embedded players, moves into a container without losing anything.

Is a consent check on the tag the same as gating it with a trigger?

No, and the difference decides whether the gate holds. A trigger controls when a tag is considered; consent settings control whether it may run once it has been considered. If you gate only with a trigger, you have covered the first page load, but a tag fired by a later click, form submission or route change is considered again at that moment and will run regardless of what the visitor chose. Setting the consent requirement on the tag as well makes the gate a property of the tag rather than of one route into it.

How do I check that a script is really blocked before consent?

Test on the published page rather than in preview mode, because preview runs with debug wiring and often with a consent state you set yourself moments earlier. On the deny path the vendor should be absent from the page's DOM and absent from resource timing, which together show that nothing was injected and nothing was fetched. On the accept path both should show it. Resource timing is the decisive one: if the vendor host was requested, it was requested, whatever the container reported.

Your banner, your consent,
your data — all in one place.

Scan your site →
Pages Free scan Product Agencies Pricing Developers Install guides Compare CMPs
Company About Velo Blog Help Contact
Account Sign up Log in Get early access
GDPR CCPA
All rights reserved
© 2026 by Amplio Data