Self-host your fonts
A stylesheet link to Google sends every visitor’s IP address to a third country before they have clicked anything.
Why it matters · the 2-minute check · the fix
Self-host your fonts
A stylesheet link to Google sends every visitor’s IP address to a third country before they have clicked anything.
Why it matters · the 2-minute check · the fixWhy it matters
When a page links to fonts.googleapis.com, the visitor’s browser has to connect to Google to render the page. That request carries their IP address and user agent, and it happens automatically — before they have read a word, consented to anything, or had any opportunity to object.
An IP address is personal data when the operator has means reasonably likely to be used to identify the person behind it. That is settled: the CJEU said so in Breyer (C-582/14), and Recital 30 treats online identifiers the same way.
On 20 January 2022 the Landgericht München I awarded a visitor €100 in damages, plus an injunction, because a website embedded Google Fonts dynamically (Az. 3 O 17493/20). The court specifically rejected legitimate interest under Art. 6(1)(f): the fonts could have been hosted locally, so passing the IP address to Google was not necessary. It is a first-instance judgment and not binding precedent, but the reasoning is hard to argue with, and it triggered a large wave of warning letters in Germany.
The same logic applies to anything else the page loads by itself: icon fonts, CSS frameworks from a CDN, avatar services, embedded maps, YouTube iframes, hosted chat widgets. The font is just the example everyone got sued over.
The 2-minute check
- Open your site in a private window with DevTools on the Network tab, and reload with the cache disabled.
- Sort by Domain. Every row that is not your own domain is a third party your visitor contacted without being asked.
- Or search your built output directly. For a static build: grep -rhoE 'https?://[^"\'()<> ]+' out/ | sort -u | grep -v your-domain.test — every line left is a third party. (Avoid a negative lookahead here: grep -E is POSIX and does not support (?!...).)
The fix
Serve the font from your own origin. In Next.js, next/font downloads the file at build time and emits it under /_next/static/media, so the browser never talks to Google. next/font/local goes one step further: the file lives in your repository, so not even your build machine makes the request.
Then re-run the network check. The fix is only real when the request is gone.
// Every visitor's browser connects to Google to fetch this.
// Their IP address goes with it, automatically, before any consent.
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter&display=swap"
/>import localFont from 'next/font/local'
// The .woff2 file is committed to the repo. Next emits it under
// /_next/static/media and rewrites the @font-face rule to point there.
// No request to Google at runtime — or at build time.
const inter = localFont({
src: './fonts/Inter-Variable.woff2',
variable: '--font-sans',
display: 'swap',
})
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className={inter.variable}>
<body>{children}</body>
</html>
)
}next/font/google works too and also self-hosts the result — the visitor never reaches Google either way. The difference is that your build machine still downloads from Google, and the build needs network access. This site uses the local variant.
Sources
- LG München I, judgment of 20.01.2022, Az. 3 O 17493/20 (opens in a new tab)
- Art. 6 GDPR — lawfulness of processing (opens in a new tab)
- CJEU, Breyer, C-582/14 (IP addresses as personal data)
Is this already true of your app?