How it works
You do not need this page to install Consentio. You need it when something is not behaving and you want to know what should have happened.
⏱️ The sequence, in your HTML
consentio-loader.min.js is small and blocking, and it does its most important work before it downloads
anything at all.
- It finds its own tag by the
data-consentio-loaderattribute. No tag, no run — it printsscript not foundand stops. - It reads the consent cookie and works out the seven Google signals from it. If there is no cookie, it uses the built-in fallback rather than “everything denied” — the difference matters, and the cookie page explains why.
- It pushes
consent defaultonto thedataLayer, synchronously. This is the whole reason the tag blocks. Nothing has been fetched yet; it does not need anything to have been. - It publishes
window.ConsentioDefault— what that push was built from. - Everything after this point is asynchronous and the page carries on: it injects
consentio.min.js, fetches your settings, language and cookie files, builds the banner, and inserts it.
Steps 1 to 4 are why async and defer break it. Both let the browser run the tag after your tag manager
has already read consent, and there is no way to correct that afterwards — a tag manager reads consent once,
at load.
🏷️ The sequence, in Tag Manager
- The Consent Initialization - All Pages trigger fires. Tag Manager guarantees this runs before every other trigger in the container.
- The template reads the same cookie, by the same rules, in sandboxed template code, and sets the consent default through Tag Manager’s own consent API.
- It calls
injectScriptforconsentio.min.jsat a pinned version, thenConsentio.Createfrom its own fields.
injectScript is always asynchronous, which is why step 2 cannot be handed to the file it loads — by the
time that file runs, Tag Manager has already decided what it may do.
The template’s entry point into the bundle:
// Three objects, one per concern - the same three the JSON files hold on the other route.
Consentio.Create(settings, language, cookies);
The template sends the settings and the wording as one object, which Create takes apart itself. That is
deliberate: the template pins an exact version of the bundle, so it has to call the bundle it pins in a way
an older one also understands.
Create puts the instance on window.ConsentioInstance itself, so there is nothing to assign afterwards.
That is what the template’s run-once guard reads, and what your own page calls to
reopen the settings.
The cookie is a contract, not an implementation detail. The template reads it a second time, in a
different language, in Tag Manager’s sandbox. Its name, its version field, its shape and what “no stored
answer” means all have to agree exactly, or the two routes disagree about the same visitor — silently.
Anyone writing a reader implements against
the cookie page, not against a guess, and
the fallback rule is the part
that is easiest to get wrong.
🧩 The two routes, in technical terms
| Directly in the site | Google Tag Manager custom template | |
|---|---|---|
| What you add | consentio-loader.min.js as a plain blocking <script> in <head>, above the tag manager snippet |
the Consentio tag, on the Consent Initialization - All Pages trigger |
| What pushes the consent default | the loader, on its first pass, before it fetches or injects anything | the template’s own sandboxed code, before it calls injectScript |
| Where settings come from | two JSON files, fetched by URL | the template’s own fields |
| Uses the loader | yes | no — never |
| The cost | it blocks. 4.9 KB has to download before the page paints | it only covers tags in that container |
🔒 The banner is inside a closed shadow root
The bar, the settings panel and the overlay are all rendered inside a shadow root attached with
{ mode: 'closed' }. Two consequences worth knowing:
- Your CSS cannot reach it, and its CSS cannot reach your page. There is nothing to override and nothing to accidentally break. Restyling means changing the source, not writing a selector.
document.activeElementreturns the host element, not whatever is focused inside. A closed root retargets it. If you are writing anything that inspects focus around the banner, that is the trap.
⚖️ What it weighs
Measured on the files this site is serving right now.
| File | Minified | Compressed | When it loads |
|---|---|---|---|
consentio-loader.min.js |
4.9 KB | about 2.1 KB | blocking, in <head>, before the page paints |
consentio.min.js |
42.0 KB | about 12.9 KB | in the background, after the default is already pushed |
The compressed column is gzip, which is what almost any server will do for you. Only the first file is on the critical path, and only because the answer has to reach your tag manager before it decides anything. On the Tag Manager route neither file blocks — and neither does the banner cover anything outside the container.
🔍 What ends up on window
Three globals, listed on the install page.
window.ConsentioDefault is the useful one when you are checking behaviour: it is set by the loader and by
nothing else, so its absence tells you a page is running the Tag Manager route.