On a custom-built site, the FlowConsent snippet is pasted once, at the very top of the <head> in the template shared by all your pages (layout, included header, base template), before any other script. Setup takes two steps: copy the snippet, then place it in that shared template. The two usual pitfalls: a Content-Security-Policy that blocks the banner, and client-side navigation that requires SPA Mode.
Before you start
- An account on app.flowconsent.com (the Free plan costs nothing, needs no credit card and covers up to 25,000 sessions per month).
- A banner created and deployed. On the Free plan, deployment goes through your own Cloudflare account (Cloudflare guide); on Pro and Enterprise, it is one click.
- Access to your site's source code and to its deployment process.
Step 1: Copy the snippet
Open Builder → Deployment → Integration and copy the snippet from the HTML / No-code tab. It has two parts, in this order: the Google Consent Mode v2 stub (denied defaults), then the banner loader.
<head>
<script>
// FlowConsent Loader - place BEFORE any other script in the <head>
window.dataLayer=window.dataLayer||[];
function gtag(){dataLayer.push(arguments);}
gtag('consent','default',{
'ad_storage':'denied',
'analytics_storage':'denied',
'ad_user_data':'denied',
'ad_personalization':'denied',
'wait_for_update':500
});
gtag('set','url_passthrough',true);
gtag('set','ads_data_redaction',true);
</script>
<!-- FlowConsent CMP -->
<script src="https://YOUR-LICENSE-CODE.consent.flowconsent.com/cookie-manager.js?code=YOUR_LICENSE_CODE"></script>
<meta charset="utf-8">
<!-- your other tags and scripts come after -->
</head>Any script placed above this snippet escapes prior blocking, so it must come before Google Analytics, Meta Pixel, Google Tag Manager and any other tracker.
Step 2: Paste it once in the shared template
Find the file that renders the <head> of every page. Depending on your stack:
- Static HTML site: with no template, every
.htmlfile has its own<head>. Paste the snippet into each one (a find and replace on<head>does the job), or use a server-side include if your host supports it. - PHP: the shared header, often
header.php, pulled into each page withincludeorrequire. - Laravel: the Blade layout, for example
resources/views/layouts/app.blade.php. - Django: the base template (often
templates/base.html) that your pages extend with{% extends "base.html" %}. - Ruby on Rails:
app/views/layouts/application.html.erb. - Hugo: the base template
layouts/baseof.html(layouts/_default/baseof.htmlbefore Hugo 0.146), or thehead.htmlpartial it calls. With a theme, copy that file into your project'slayouts/folder instead of editing the theme. - Jekyll: the
_layouts/default.htmllayout, or_includes/head.htmlwith a theme such as Minima. To override a theme file, copy it to the same path in your site. - Eleventy: the base layout in
_includes/(for example_includes/base.njk), selected with thelayoutkey in front matter.
The snippet is plain HTML: no template engine needs it escaped. If your site has several root layouts, repeat the step in each. Then rebuild or redeploy the site.
Do not hard-code your trackers (Google Analytics, Meta Pixel…) in the template: declare them in Builder → Services, and the banner loads them only after consent. For Google Tag Manager, see the dedicated guide.
Content-Security-Policy and client-side navigation
Content-Security-Policy: script-src 'self' 'nonce-RANDOM' https://*.consent.flowconsent.com; connect-src 'self' https://*.consent.flowconsent.comThen add nonce="RANDOM" to both <script> tags in the snippet, with a value generated for every response. Services the banner loads after consent must be allowed too, just as they would be without FlowConsent. When something is blocked, the browser console names the directive and the refused domain.
Verify the installation
- Open the live site in a private window: the banner appears.
- In the Network tab, no third-party request goes out before you click Accept. The Console reports no CSP violation.
- Run the setup wizard (Builder → Integration): it checks the live page (loader present with the right license code, Consent Mode stub present and placed before every Google tag).
- Finish with a refusal scan from the Compliance tab (compliance verification).
Do it from your AI agent (MCP)
FlowConsent has an official MCP server, https://mcp.flowconsent.com, usable from Claude, ChatGPT or any MCP client. You connect through OAuth 2.0 with your FlowConsent account, no API key required. Your agent fetches the snippet and placement instructions (get_banner_snippet, get_setup_instructions), verifies the installation with a real scan (verify_consent_compliance) and can set up recurring monitoring (monitor_compliance). You, or your coding agent, edit the template: the MCP server provides the snippet, the instructions and the verification.
Example request:
Give me my banner snippet for my custom HTML site, tell me where to put it in my template, then check that it is properly installed on https://mysite.com
Learn more: MCP server and FlowConsent for AI agents.
Frequently asked questions
Do I need to paste the snippet on every page?
It must be present on every page, but you paste it only once if your pages share a template. Only a plain HTML site with no template needs it added file by file.
Can I put it at the bottom of the <body>?
No. The Consent Mode stub must run before any tracker: at the bottom of the page, scripts higher up would already have fired. Put it at the very top of the <head>.
The banner does not show up: where do I start?
Open the browser console. A CSP error points to a domain to allow. Otherwise, check that the snippet is in the HTML actually served (view the page source), with your license code.
My site is statically generated: does the banner work without a server?
Yes. The snippet runs in the browser, so it works on any static file hosting.