Clarity gives you a solid design system. CSP gives you a solid boundary. The annoying part is getting both to cooperate without punching holes in your policy.
If you’re using VMware Clarity and trying to keep a sane Content Security Policy, the trade-offs are pretty familiar: developer ergonomics vs actual security, static hosting vs runtime nonces, and “just make it work” vs “I’d like to block XSS this year.”
This guide compares the main ways teams approach CSP with Clarity-heavy apps, where the pain usually shows up, and what I’d recommend in practice.
The short version
If you want my opinion up front:
- Best security: nonce-based CSP with
strict-dynamic, nounsafe-inline, no broad host allowlists unless you truly need them. - Best compatibility with messy frontend stacks: a host allowlist CSP, but keep it tight and expect ongoing maintenance.
- Worst common shortcut: enabling
unsafe-inlineand calling it done. - For most Clarity apps: start with a self-hosted app bundle, no inline scripts, no inline event handlers, and add nonces only if your rendering path needs them.
Clarity itself is not usually the core CSP problem. Your analytics tags, consent tooling, and runtime-injected scripts usually are.
What “CSP for Clarity” usually means
For a Clarity-based app, CSP work tends to fall into a few buckets:
-
Your app code
- bundled JS/CSS
- icons/fonts/images
- API calls
-
Clarity component behavior
- overlays, templates, dynamic rendering
- styles applied by framework/runtime choices
-
Third-party integrations
- Google Tag Manager
- Google Analytics
- Cookie consent tools
- monitoring, chat, A/B testing, and random marketing pixels
That third bucket is where policies go from clean to ugly fast.
Here’s a real-world CSP header from headertest.com:
content-security-policy:
default-src 'self' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com;
script-src 'self' 'nonce-NDA2NzdlODUtNzMwMS00NjJlLTlhYjctY2JmNmU3MmUxYjZh' 'strict-dynamic' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com;
style-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://*.cookiebot.com https://consent.cookiebot.com;
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.headertest.com https://tallycdn.com https://or.headertest.com wss://or.headertest.com https://*.google-analytics.com https://*.googletagmanager.com https://*.cookiebot.com;
frame-src 'self' https://consentcdn.cookiebot.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
object-src 'none'
This is a decent example of the compromises teams make in production:
- good:
nonce-...,strict-dynamic,object-src 'none',frame-ancestors 'none' - less good:
style-src 'unsafe-inline' - realistic: multiple third-party hosts in
script-src,connect-src, andframe-src
That’s not “bad CSP.” That’s “CSP after product and marketing happened.”
Comparison: common CSP approaches for Clarity apps
1) Strict nonce-based CSP
This is the version I trust most.
Example
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{RANDOM}' 'strict-dynamic';
style-src 'self' 'nonce-{RANDOM}';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
object-src 'none';
And in your HTML:
<script nonce="{{ .CSPNonce }}" src="/assets/app.js"></script>
<style nonce="{{ .CSPNonce }}">
.app-loading { display: none; }
</style>
Pros
- Strong XSS mitigation.
strict-dynamicreduces dependence on brittle host allowlists.- Works well when your app bootstraps from a trusted root script.
- Easier to reason about than giant lists of analytics domains.
Cons
- You need server-side nonce generation on every response.
- Static hosting gets awkward unless you avoid inline code entirely.
- Some tooling and legacy snippets assume inline scripts/styles.
- Third-party copy-paste tags often fight this model.
Best fit
- Server-rendered apps
- apps with mature deployment pipelines
- teams that care about real CSP, not checkbox CSP
If your Clarity app is rendered through something like Express, Spring, or another backend that can inject a nonce, this is the cleanest route.
2) Host allowlist CSP
This is the most common production setup because it’s easier to bolt on.
Example
Content-Security-Policy:
default-src 'self';
script-src 'self' https://www.googletagmanager.com https://*.google-analytics.com;
style-src 'self';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com https://*.google-analytics.com;
frame-ancestors 'none';
base-uri 'self';
object-src 'none';
Pros
- Easy to understand at first glance.
- Works with static hosting.
- No nonce plumbing needed.
- Good enough for many internal apps.
Cons
- Host allowlists age badly.
- Third parties add new domains and break production.
- If an allowed host serves attacker-controlled JS, CSP still allows it.
- Tends to grow into a junk drawer.
This is the policy style I see most often in enterprise Clarity deployments. It starts small, then somebody adds GTM, then consent tooling, then a support widget, and now connect-src looks like airport departures.
Best fit
- static SPAs
- internal tools with limited third-party scripts
- teams that can tolerate maintenance churn
3) CSP with unsafe-inline
I get why teams do this. I still hate it.
Example
Content-Security-Policy:
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
Or worse:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline';
Pros
- Fastest way to stop CSP breakage.
- Compatible with inline style-heavy codebases.
- Minimal refactoring required.
Cons
script-src 'unsafe-inline'seriously weakens CSP.style-src 'unsafe-inline'is less catastrophic, but still not great.- Teams rarely come back later to clean it up.
- You lose most of the point of having CSP in the first place.
I’ll be blunt: if you have script-src 'unsafe-inline', your CSP is mostly decorative.
style-src 'unsafe-inline' is more common and sometimes tolerated, especially when framework behavior or third-party consent tools make nonce-based styling painful. That headertest example does exactly that. I don’t love it, but I understand it.
For directive behavior details, the official spec docs are the thing to read, and csp-guide.com is useful when you want plain-English explanations.
Where Clarity specifically can affect CSP
Clarity itself usually behaves fine under CSP if your app bundle is external and your templates don’t inject inline script. The real friction points are usually adjacent:
1) Inline bootstrapping code
A lot of teams add tiny inline setup scripts to pass config into the app.
<script>
window.APP_CONFIG = { apiBase: "/api" };
</script>
That forces you toward a nonce, hash, or unsafe-inline.
Safer option:
<script nonce="{{ .CSPNonce }}">
window.APP_CONFIG = { apiBase: "/api" };
</script>
<script nonce="{{ .CSPNonce }}" src="/assets/app.js"></script>
Or skip inline config entirely:
<script src="/assets/app.js"></script>
Then fetch config from the DOM or an endpoint.
2) Inline styles
Some frontend stacks sneak in inline styles, especially around hydration, overlays, or third-party widgets.
If Clarity is just part of your app and your own CSS is bundled normally, you can often avoid this. Third-party consent banners are a bigger source of style-src pain than Clarity itself.
3) Icons, fonts, and assets
Clarity apps commonly need predictable asset rules:
img-src 'self' data: https:;
font-src 'self';
If you self-host assets, this stays simple. If you pull fonts or icon assets from a CDN, expect more CSP sprawl.
A practical comparison table
Strict nonce CSP
Pros
- strongest XSS posture
- future-proof compared to allowlists
- pairs well with
strict-dynamic
Cons
- setup complexity
- requires response-time nonce handling
- annoying for static-only deployments
Host allowlist CSP
Pros
- easy rollout
- static-site friendly
- decent baseline control
Cons
- brittle over time
- weaker trust model
- lots of ongoing maintenance
unsafe-inline-friendly CSP
Pros
- easiest path to compatibility
- low engineering effort up front
Cons
- weak security value
- encourages sloppy patterns
- hard to unwind later
My recommended baseline for Clarity apps
If I were setting this up for a typical Clarity app today, I’d start here:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{RANDOM}' 'strict-dynamic';
style-src 'self';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
frame-src 'self';
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
object-src 'none';
Then I’d add only what’s required by actual runtime behavior.
If you must support GTM, analytics, and consent tooling, you’ll end up closer to this shape:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{RANDOM}' 'strict-dynamic' https://www.googletagmanager.com https://*.cookiebot.com https://*.google-analytics.com;
style-src 'self' 'unsafe-inline' https://*.cookiebot.com https://consent.cookiebot.com;
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com https://*.google-analytics.com https://*.googletagmanager.com https://*.cookiebot.com;
frame-src 'self' https://consentcdn.cookiebot.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
object-src 'none';
That’s not perfect, but it’s honest. Security work gets better when the policy reflects reality instead of pretending the app has no dependencies.
What I’d avoid
script-src 'unsafe-inline'- wildcarding everything with
https: - copying a CSP from another app without observing actual violations
- dumping every vendor into
default-src
default-src is not a junk drawer. Be explicit with script-src, style-src, connect-src, img-src, and frame-src.
Final take
For Clarity apps, CSP success mostly comes down to discipline outside Clarity:
- keep scripts external
- avoid inline bootstrapping where possible
- self-host assets when you can
- use nonces if you need inline code
- treat third-party tags as the main source of policy complexity
If you want strong security, build around nonce-based script-src and keep the exceptions narrow. If you want easy deployment, a host allowlist CSP works, but you’re signing up for maintenance.
That’s the real comparison: cleaner security model vs easier operations. I usually pick the cleaner model first and make exceptions only when the app forces my hand.