Google Fonts needs two directives: style-src https://fonts.googleapis.com for the stylesheet and font-src https://fonts.gstatic.com for the font files. The <link> in Google’s CSS API docs points at https://fonts.googleapis.com/css2?family=…, and the CSS that comes back names each file on the other host, for example src: url(https://fonts.gstatic.com/s/inter/v20/….woff2). Each directive allows one half, so one without the other still breaks the font.
The policy
Content-Security-Policy: default-src 'self'; style-src 'self' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'
The builder finds one low point: a <meta> tag ignores frame-ancestors, so send this as a header. Google’s own tag platform CSP guide writes the pair the same way for Tag Manager’s preview mode: https://fonts.googleapis.com in style-src, https://fonts.gstatic.com in font-src.
The usual mix-ups
- Hosts swapped.
fonts.gstatic.cominstyle-srcorfonts.googleapis.cominfont-srcallows nothing the fonts need: the stylesheet or the files are refused, the text falls back to another font, and the console names the directive that refused them. - No
font-srcat all. It falls back todefault-src, so withdefault-src 'self'the stylesheet arrives and every font file is refused. 'unsafe-inline'isn’t needed. The fonts come in an external stylesheet, so nothing here asks for inline styles. The builder rates'unsafe-inline'instyle-srcmedium; drop it unless your own markup needs it.@importcounts as a stylesheet.@import url("https://fonts.googleapis.com/css2?family=Inter")in your CSS is checked againststyle-srctoo.'strict-dynamic'does nothing for styles. It only changes how scripts are trusted, so a nonce-based policy keepshttps://fonts.googleapis.cominstyle-src.- Stripe Elements fonts. When you pass a Google Fonts URL to Elements as
cssSrc, Stripe’s guide saysconnect-srcmust allow it as well.
Self-hosting removes both
Serve the files from your own origin and 'self' covers the stylesheet and the fonts. next/font/google in Next.js does this at build time, so the browser never asks Google.
@font-face {
font-family: "Inter";
src: url("/fonts/inter-latin.woff2") format("woff2");
font-display: swap;
}
In HTML and nginx
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter&display=swap">
add_header Content-Security-Policy "default-src 'self'; style-src 'self' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;