Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/skyphusion-labs/zaraz-consent/archive/refs/heads/main.zipA WordPress must-use file for Cloudflare Zaraz cookie consent.
Cloudflare injects Zaraz on the proxied zone. This plugin ships no banner, no stylesheet and no script request. It adds one footer button. The button stays hidden until zarazConsentAPIReady. The button then sets zaraz.consent.modal = true. PHP reads the consent cookie when something asks for it.
Read this before you install it
This plugin does not gate anything. It does not give your site consent.
The plugin does two jobs. It reopens a modal that Zaraz draws. It also reads the visitor choice back in PHP. Cloudflare does all the gating, in the Zaraz configuration. The plugin does none of it.
Zaraz can gate only Zaraz tools. WordPress, your theme and other plugins also load scripts. Those are not Zaraz tools. No purpose reaches them. Correct Cloudflare configuration does not stop them. Read What Zaraz cannot gate first. That section decides whether this repo solves your problem.
Do the configuration below before you copy the file. The order matters. Out of order, you get a button that does nothing, and no way to tell why.
Prerequisite order
Each step depends on the step above it.
- Zaraz is enabled on the zone.
- Purposes are defined.
- Tools are assigned to purposes.
- Consent is enabled.
- The plugin is installed.
Start at step 5 and you see a hidden button and no modal. WordPress does not explain why. Stop after step 4 and you get a modal that records a choice. That modal enforces nothing.
1. Zaraz must be enabled on the zone
Check this from the edge. You need no credential:
curl -o /dev/null -w "%{http_code}\n" https://<your-zone>/cdn-cgi/zaraz/i.js
curl -o /dev/null -w "%{http_code}\n" https://<your-zone>/cdn-cgi/trace
i.js returns 200 when Zaraz is on. It returns 404 when Zaraz is off. The second request is the control. /cdn-cgi/trace returns 200 on any Cloudflare proxied zone. So 200 on trace with 404 on i.js means Zaraz itself is off. It does not mean the cdn-cgi path is unreachable or the host is wrong.
Measured 2026-10-23 on ggc.sh, skyphusion.org and vivijure.com. All three returned 404 for i.js and 200 for trace. Zaraz serves on none of them.
A zone can hold a Zaraz configuration and still not serve the script. Those three zones hold a configuration. It reports autoInjectScript: true and contains zero tools. So reading the configuration does not replace the check above.
2. Purposes
A purpose is what the visitor agrees to. A purpose is not a tool. A purpose is not a vendor. It is a category, such as analytics or marketing. Each purpose has an id, a display name and a description. The modal lists one row for each purpose.
Purposes live in iac/consent.json under purposes. The key is the purpose id. Use that id everywhere else, including in zaraz_consent_choice():
"purposes": {
"analytics": {
"name": "Analytics",
"description": "Measure how the site is used."
}
}
sync_consent.py refuses a purpose that has no name or no description.
Zaraz does not list a purpose that has no tool assigned. Defining purposes alone changes nothing a visitor can see.
3. Assign tools to purposes, which is the whole mechanism
The defaultPurpose field gates a tool. That one field decides whether consent applies to the tool.
A tool with no defaultPurpose skips consent. In Cloudflare's words: "When you add a new tool to your website, Zaraz does not assign any purpose to it. This means that this tool will skip consent by default."
That default makes the dangerous state quiet. Enable consent over unassigned tools and the system gates nothing. The modal appears. A choice is recorded. A cookie is written. Every tool keeps firing as before.
iac/tool-purposes.json maps a tool id to a purpose id. It ships empty:
{}
The empty default is deliberate. It stops a sync from attaching Google, Meta or anything else. A sync refuses to enable consent over an empty map. That combination would show a modal and gate nothing. Add the tool to gate it:
{
"<tool-id-from-the-live-zaraz-config>": "analytics"
}
The tool must already exist in the zone. sync_consent.py does not create tools. It refuses a tool id that the live configuration does not hold. It also refuses a purpose id that consent.json does not hold.
4. Enable consent
consent.enabled in iac/consent.json switches the system on. On its own it does three things only. Zaraz draws the modal. Zaraz writes the consent cookie. The plugin button becomes usable. It gates no tool at all. Step 3 is the only source of gating.
consent.cookieName must match what the plugin reads. The default on both sides is cf_consent. If the zone uses another name, define ZARAZ_CONSENT_COOKIE in wp-config.php to the same string as consent.cookieName.
5. Install the plugin
cp zaraz-consent.php wp-content/mu-plugins/zaraz-consent.php
There is no activation step and no settings row. WordPress loads mu-plugins on its own.
Check your Content Security Policy. The plugin emits an inline `