Meridian Blue

Cloudflare installation

How to allow the Meridian Blue loader through a Cloudflare-managed Content Security Policy.

Cloudflare installation

If your site sits behind Cloudflare and your browser console shows:

Refused to load the script 'https://cdn.meridianblue.ai/v1/loader.js' because it
violates the following Content Security Policy directive: "script-src 'self' ..."

…then your site is enforcing a Content Security Policy (CSP) that does not yet allowlist our one script URL. This is the browser doing its job — CSP cannot be bypassed by us, only by you, and it takes about 90 seconds in the Cloudflare dashboard.

You only ever need to allowlist two hostnames:

HostnameUsed forGoes in
https://cdn.meridianblue.aiThe loader + runtime bundlescript-src
https://plugin.meridianblue.aiConfig fetch + event ingestionconnect-src

That is the entire installation. No inline scripts, no multiple URLs, no vendor spaghetti.


Step 1 — Find your current CSP header

Open your site in Chrome or Firefox, open DevTools → Network, reload the page, and click the top document request. Under Response Headers look for:

  • content-security-policy, or
  • content-security-policy-report-only

Copy the full value. You will edit this string in step 3. If there is no header at all, you are not enforcing CSP and the loader should already work — if it still fails, check that you are not serving a <meta http-equiv="Content-Security-Policy"> tag from your HTML (grep the page source).


Step 2 — Open Cloudflare Transform Rules

  1. Sign in to dash.cloudflare.com.
  2. Pick the zone (the domain) you want to install on.
  3. In the left sidebar, go to Rules → Transform Rules.
  4. Click the Modify Response Header tab at the top.
  5. Click Create rule.

If your plan does not show "Modify Response Header", skip to the Cloudflare Workers fallback at the bottom of this page.


Step 3 — Create the rule

Fill in the form exactly as below.

Rule name

Meridian Blue — allow CDN in CSP

If — Custom filter expression → Edit expression

Match every HTML response on your site:

(http.response.content_type.media_type eq "text/html")

If you want to scope it to a single hostname, append:

and (http.host eq "www.example.com")

Then — Modify response header

  • Action: Set dynamic
  • Header name: Content-Security-Policy
  • Value (expression):
concat(
  regex_replace(
    regex_replace(http.response.headers["content-security-policy"][0],
      "script-src([^;]*)",
      "script-src$1 https://cdn.meridianblue.ai"),
    "connect-src([^;]*)",
    "connect-src$1 https://cdn.meridianblue.ai https://plugin.meridianblue.ai")
)

This takes whatever CSP your origin is already sending and splices our two hostnames into the existing script-src and connect-src directives, without touching anything else. If one of those directives does not exist yet, use the manual version instead — see step 3b.

Step 3b — Manual CSP value (if you don't have one yet)

If your origin sends no CSP header, paste a complete, strict-but-working baseline instead. Set Action → Set static (not dynamic) and use:

default-src 'self';
script-src 'self' https://cdn.meridianblue.ai;
connect-src 'self' https://cdn.meridianblue.ai https://plugin.meridianblue.ai;
img-src 'self' data: https:;
style-src 'self' 'unsafe-inline';
font-src 'self' data:;
frame-ancestors 'self';
base-uri 'self';
object-src 'none';

Only use this baseline if you know your site does not depend on other inline scripts, fonts, or third-party widgets. When in doubt, use the dynamic version in step 3 — it preserves your current policy.


Step 4 — Deploy and verify

  1. Click Deploy in Cloudflare. The rule is live globally within seconds.
  2. Hard-reload your site (⌘⇧R / Ctrl+F5) so the browser discards any cached CSP header.
  3. Open DevTools → Network and look for loader.js:
    • Status should be 200, not (blocked:csp).
    • The Console tab should have no red CSP errors.
  4. Open DevTools → Application → Storage → Local storage and confirm a mb_ prefixed key was written — that's the SDK booting successfully.

If loader.js is 200 but you still see a CSP error for an mb_ URL (e.g. plugin.meridianblue.ai/v1/config/…), you forgot connect-src. Repeat step 3.


Step 5 — (Optional) lock it down

Our loader never evaluates inline scripts, never calls eval, and never reaches outside the two hostnames above. That means you can safely drop 'unsafe-inline' and 'unsafe-eval' from your script-src — as long as nothing else on your site needs them. Doing so upgrades your CSP from "advisory" to "real protection".

You do not need to add us to:

  • img-src (we render no images from our own origin)
  • font-src (we use only system fonts)
  • frame-src / child-src (we do not iframe anything)
  • style-src (all styles live inside a closed Shadow DOM root)

That is the whole point of the shadow-DOM isolation: your site's CSS and ours can never fight, and your CSP stays as tight as you want it.


Fallback: Cloudflare Workers

If your Cloudflare plan does not include Modify Response Header (very old Free plans), you can do the same thing with a tiny Worker.

  1. Go to Workers & Pages → Create application → Create Worker.
  2. Name it meridianblue-csp and replace the default code with:
export default {
  async fetch(request, env, ctx) {
    const response = await fetch(request);
 
    // Only touch HTML responses — don't rewrite headers on images, etc.
    const ct = response.headers.get("content-type") || "";
    if (!ct.includes("text/html")) return response;
 
    const headers = new Headers(response.headers);
    const existing = headers.get("content-security-policy") || "";
 
    const patched = existing
      ? existing
          .replace(/script-src([^;]*)/, "script-src$1 https://cdn.meridianblue.ai")
          .replace(/connect-src([^;]*)/, "connect-src$1 https://cdn.meridianblue.ai https://plugin.meridianblue.ai")
      : "default-src 'self'; script-src 'self' https://cdn.meridianblue.ai; connect-src 'self' https://cdn.meridianblue.ai https://plugin.meridianblue.ai; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;";
 
    headers.set("content-security-policy", patched);
 
    return new Response(response.body, {
      status: response.status,
      statusText: response.statusText,
      headers,
    });
  },
};
  1. Click Save and Deploy.
  2. Go to your zone → Workers Routes → Add route and bind the Worker to *your-domain.com/*.

Troubleshooting

"I deployed the rule but still see the CSP error." Hard-reload. Browsers cache CSP headers aggressively. If that doesn't work, check Cloudflare → Caching → Configuration → Development Mode is off and purge the HTML page from the cache.

"My origin sends CSP via a <meta> tag, not a header." Cloudflare Transform Rules cannot edit HTML body content — only headers. You will need to either (a) remove the <meta> and switch to the header approach above, or (b) patch the tag at the application layer (WordPress theme, Next.js middleware, etc.). Open an issue if you're stuck.

"I have CSP in report-only mode and want to test first." Change the header name in step 3 from Content-Security-Policy to Content-Security-Policy-Report-Only. The browser will log violations to your report endpoint instead of blocking the script.

"I have a nonce-based CSP (script-src 'nonce-…')." The regex rewrite in step 3 still works — it appends our hostname alongside the nonce. You do not need to give us a nonce; we are loaded as an external script, not inline.


Why this is the only configuration step

Every other option is worse:

  • Inlining the SDK into every page bloats your HTML by ~25KB on every request, defeats browser caching, breaks CSP script-src tightening (you'd need 'unsafe-inline' or per-page nonces), and makes upgrades a nightmare — every customer would be frozen on whatever version they pasted.
  • Same-origin proxy (you serve our JS from yourdomain.com/mb/loader.js) works but gives up caching, shifts our CDN cost to your origin, and still requires an edit to your infrastructure — we picked Cloudflare because it's the fastest place to make the fix.
  • A browser extension only works for you, not your visitors.

Allowlisting two hostnames in one header is the smallest possible change that keeps CSP actually enforced. That's why it is the supported install path.