Hi Michael,
You found a real bug, not a gap in the documentation. Thanks for the clear description — the OSM case made it easy to reproduce.
The plugin has three startup paths, and only two of them announced anything. On a first visit it fires fazcookie_consent_update with action “init”, and when a Global Privacy Control signal is auto-applied it fires one too. The third path — a visitor whose choice is already stored, which is every page after the first — fired nothing at all. So anything keyed on consent worked on the page where the visitor clicked Accept and went quiet from the next page on. Your workaround exists because there was no event to listen for.
Two of my own integrations were affected by the same gap, which is how I found out how far it went. The WP Consent API bridge only ran on that event, so Consent-API aware plugins kept applying their own default (deny) to a visitor who had accepted. The Microsoft UET bridge pushes “consent default: denied” at load and then waits for the event, so a returning visitor who had granted marketing was still reported to Microsoft as denied.
The fix is in the next release. There is a new event, fazcookie_consent_ready, which fires once on every page load and carries the consent in force at that moment:
document.addEventListener(‘fazcookie_consent_ready’, function (e) {
if (e.detail.accepted.indexOf(‘functional’) !== -1) {
showMap();
}
});
e.detail is { accepted: [slug, …], rejected: [slug, …], action: ‘init’ | ‘restore’ | ‘gpc’ } — “init” on a first visit before any choice, “restore” for a visitor whose choice was already stored, “gpc” when a Global Privacy Control signal was auto-applied. Register the listener before the plugin’s script runs, for example from an inline script in the head. That also removes a race your current code has: your check runs inside your own DOMContentLoaded handler, and if the plugin’s script has not defined getFazConsent yet, the guard fails silently and the map never appears.
I did not simply make the existing event fire on every page load, and it is worth saying why, because it affects how you choose between the two. fazcookie_consent_update means “the consent just changed”. Its listeners act on that meaning — the consent logger writes an audit row, the pageview tracker records a banner interaction, and Google Consent Mode pushes an update. Firing it on every page load would have written one consent-log row per page view for every returning visitor, which is both unbounded table growth and a false record of an action the visitor never took. So the two events stay separate: use fazcookie_consent_ready to read the state on load, and fazcookie_consent_update to react to a change. A snippet that sends an analytics event belongs on the second one, or it will fire on every page view.
On your second question: no, cookie names are not exposed. getFazConsent() reports categories only, and the new event carries the same granularity. Per-service decisions do exist inside the consent cookie as svc.* keys, but there is no public API for reading them, so category level is the supported granularity today. If a per-service accessor would be useful for your case, tell me what you would do with it and I will look at adding one.
Until the release lands, your current approach is fine. Adding a small wait for getFazConsent to be defined, instead of checking it once, will make it reliable on slower page loads.