
TL;DR: A Content-Security-Policy header restricts which origins can load scripts, styles, and other resources on your page. It's a security hardening measure, not a ranking factor — but a hacked site tanks rankings fast, so treat CSP as cheap insurance. Test in report-only mode, then enforce.
What a missing Content-Security-Policy header means
A Content-Security-Policy (CSP) response header tells the browser which origins are allowed to load scripts, styles, images, and frames on your page, so if it's missing the browser trusts everything and a single injected <script> can run unchecked. This is a defense-in-depth measure against cross-site scripting and content injection — it is not a direct Google ranking factor, and no page has ever ranked lower for lacking one.
So why does an SEO crawler flag it? Because a compromised page is an SEO problem by proxy. Injected spam, a hacked-site warning in Search Console, or a browser interstitial will bury your rankings faster than any header ever could. CSP is the seatbelt: invisible until the day it saves you.
A real example and the fix
Run a header check against a page with no policy and you get nothing back — here's a live response from a site that shipped without one:
$ curl -sI -A 'Mozilla/5.0' https://example.com/ | grep -i content-security
# (no output — header absent)The fix is to send a policy that names your legitimate sources. A pragmatic starting policy for a typical WordPress site with a couple of third-party scripts looks like this — note it mirrors the shape of what large sites actually ship (GitHub and Cloudflare both send default-src plus explicit allow-lists):
Content-Security-Policy: default-src 'self';
script-src 'self' 'unsafe-inline' https://www.googletagmanager.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' data:;
connect-src 'self' https://www.google-analytics.com;
frame-ancestors 'self';
base-uri 'self';
form-action 'self';
upgrade-insecure-requestsAfter deploying, re-check and confirm the header now returns:
$ curl -sI -A 'Mozilla/5.0' https://example.com/ | grep -i content-security
content-security-policy: default-src 'self'; script-src 'self' ...CSP directives that matter most
| Directive | Controls | Sane starting value |
|---|---|---|
default-src | Fallback for anything not named | 'self' |
script-src | Where JS can load from | 'self' + your tag manager |
style-src | Where CSS can load from | 'self' 'unsafe-inline' |
img-src | Image origins | 'self' data: https: |
frame-ancestors | Who can iframe your page (clickjacking) | 'self' |
upgrade-insecure-requests | Rewrites http:// sub-resources to https:// | enabled |
How to detect it
- curl the header directly:
curl -sI -A 'Mozilla/5.0' https://yourdomain.com/ | grep -i content-security-policy. No line back means no policy. - securityheaders.com: paste your URL and read the grade. A missing CSP knocks the score down and is called out explicitly in the report.
- Browser DevTools: open the Network tab, click the document request, and read the Response Headers pane. CSP violations also log to the Console in red.
- Screaming Frog: enable Security in the crawl config; the Security tab flags every URL missing a CSP across the whole site at once.
How to fix it
Pick the layer you control and send the header there. Test in report-only mode first so you don't break your own page.
Apache (.htaccess)
<IfModule mod_headers.c>
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com; img-src 'self' data: https:; frame-ancestors 'self'; upgrade-insecure-requests"
</IfModule>Nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com; img-src 'self' data: https:; frame-ancestors 'self'; upgrade-insecure-requests" always;WordPress (no server access)
If you can't touch Apache or Nginx config, send the header from PHP in your theme's functions.php or a small must-use plugin:
add_action('send_headers', function () {
header("Content-Security-Policy: default-src 'self'; "
. "script-src 'self' 'unsafe-inline' https://www.googletagmanager.com; "
. "img-src 'self' data: https:; frame-ancestors 'self'; "
. "upgrade-insecure-requests");
});A security plugin such as one that manages HTTP headers can do the same through a UI if you'd rather not edit code. Either way the header ends up on the response — the browser doesn't care how it got there.
Report-only first (do this before enforcing)
Swap the header name for Content-Security-Policy-Report-Only. The browser logs every violation to the console but blocks nothing, so you can watch your real traffic surface the origins you forgot — a font CDN, an embedded map, a chat widget — then add them and only then switch to the enforcing header. Enforce a policy you haven't watched in report-only mode and you will white-screen your own site. Ask me how I know.
Common mistakes
A handful of errors account for most broken CSP rollouts:
- Forgetting your own subdomains. If your CDN or asset host is
cdn.yourdomain.com,'self'won't cover it — name it explicitly. - Blocking inline styles the theme needs. Many themes inject inline CSS; omit
'unsafe-inline'fromstyle-srcand your layout collapses. - Setting the header twice. A plugin and the server both sending CSP produces two headers, and browsers enforce the intersection — the strictest combination, which usually breaks something.
- Copying a huge policy off another site. GitHub's or Cloudflare's policy fits their assets, not yours. Start minimal and widen from report-only data.
FAQ
Will adding a CSP improve my Google rankings?
No, not directly. Google has never listed CSP as a ranking signal. The SEO payoff is indirect: it hardens the site against the kind of hack that does tank rankings via manual actions and malware warnings.
What's the difference between CSP and HSTS?
CSP controls what content is allowed to load; HSTS forces the connection itself to stay on HTTPS. They solve different problems and you want both.
Will a CSP break my existing scripts?
It can, which is exactly why you run Content-Security-Policy-Report-Only first. Anything not on your allow-list gets logged, you add it, and you flip to enforcing once the console is quiet.
Is 'unsafe-inline' bad?
It weakens the policy because it re-allows inline scripts, which is what most XSS abuses. It's a common concession for WordPress themes that inline JS. Tightening to nonces or hashes is the mature next step, but a policy with 'unsafe-inline' still beats no policy.
Do I need a CSP if I already run HTTPS everywhere?
Yes. HTTPS encrypts the transport; it does nothing to stop a malicious script that's legitimately served over that encrypted connection. See our mixed content guide and the security issues glossary for how these layers stack.
Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.
About SEO ProCheck
Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.
Work With Me
Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.







