Self-host Google Fonts for GDPR compliance

• 4 min read • 915 words

Illustration of an EU flag connected via a dotted line to a cloud with a green padlock between them, representing GDPR-compliant self-hosted fonts

If your site does this:

<link href="https://fonts.googleapis.com/css2?family=Inter&display=swap" rel="stylesheet">

Every visitor's IP address is being sent to Google. A German regional court ruled in January 2022 that this violates GDPR Article 6 because it happens without explicit consent. Plaintiffs have since started filing claims against EU-based sites that haven't fixed it.

The fix takes 5 minutes. Download the WOFF2, drop it in your project, change one CSS line.

Why fonts.googleapis.com is the problem

When a browser loads a stylesheet from fonts.googleapis.com, it makes a TCP connection. That connection sends the visitor's IP to Google's servers as part of the standard HTTP request. The IP is personal data under GDPR.

If the visitor hasn't consented to that data transfer (and they almost never have, because cookie banners don't usually mention fonts), the transfer is unlawful.

The German court awarded €100 in damages to the plaintiff. Standalone that's nothing, but the same legal theory has been recycled into thousands of demand letters across the EU since.

The fix in 5 steps

1. Pick the fonts you actually use

Most sites load 4-6 weights of one or two families. Look at your CSS, find every font-family reference, list the weights and styles you actually use. Drop the rest.

Common offender: a CSS template that loads Roboto in 12 weights and the site uses Bold and Regular only. That's 10 wasted downloads on every visit.

2. Download pre-compressed WOFF2 files

Don't generate them yourself. Pre-compressed versions of every popular Google Font are available, pick the families and weights you need:

Each one downloads as a single WOFF2 file under 30KB after subsetting.

3. Drop them in your project

Create a fonts/ folder at your web root. Move the WOFF2 files in.

your-site/
├── public/
│   ├── fonts/
│   │   ├── inter-regular.woff2
│   │   └── inter-bold.woff2
│   └── ...

4. Replace the Google Fonts link with a local @font-face

Delete this:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">

Replace with this (in your CSS):

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

For variable fonts (one file covers all weights), it's even simpler:

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-variable.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

5. Set long cache headers

Fonts are content-addressable: once you ship inter-regular.woff2, the bytes never change. Set a 1-year cache header so repeat visitors don't re-download.

For Vercel:

{
  "headers": [
    {
      "source": "/fonts/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
      ]
    }
  ]
}

For nginx:

location /fonts/ {
  add_header Cache-Control "public, max-age=31536000, immutable";
}

Verifying the fix

Open your site in a clean browser, check the Network tab. You should see ZERO requests to fonts.googleapis.com or fonts.gstatic.com. Just your local /fonts/*.woff2 files.

No Google CDN requests = no IP leaks = GDPR compliance restored.

What you might lose

In practice this matters less than people think. WOFF2 files are 15-30KB. On a modern broadband connection, that's a few hundred milliseconds the first time. After that, your origin's cache headers serve it from disk.

For most sites with English-only content, this is a non-issue. The Latin-only WOFF2 covers everything you'll render.

What about the rest of Google's CDNs?

This guide only covers fonts. Google Analytics, Tag Manager, Maps, reCAPTCHA, and Ads all have the same IP-transmission problem under GDPR. Each needs its own fix:

Fonts are the easiest fix and the lowest-stakes one to start with.

Quick recap

1. Identify the fonts and weights your site actually uses 2. Download pre-compressed WOFF2 files for each weight 3. Drop them into a /fonts/ folder 4. Replace the Google Fonts <link> with a local @font-face 5. Set long cache headers (1 year, immutable) 6. Verify no requests go to fonts.googleapis.com

That's it. Five minutes, no more IP leaks, no more demand letters.

Frequently asked

Is loading Google Fonts from fonts.googleapis.com really illegal in the EU?

A German regional court ruled in January 2022 that embedding Google Fonts via the CDN transmits the visitor's IP to Google without consent, which violates GDPR. Other EU jurisdictions have followed similar reasoning. Self-hosting eliminates the issue entirely.

Do I need to update my privacy policy if I self-host?

No. Self-hosting means no data leaves your server, so there's nothing new to disclose. If you previously had a Google Fonts disclosure in your privacy policy, you can remove it once you've fully migrated.

Will self-hosting be slower than the Google CDN?

On a modern host with HTTP/2 or HTTP/3, self-hosted fonts often load FASTER because there's no extra DNS lookup or cross-origin connection. Pre-compressed WOFF2 files are tiny enough that CDN distance rarely matters.

What about other Google services like Analytics?

This guide only covers fonts. Google Analytics, reCAPTCHA, Maps, and Tag Manager all transmit IPs and need separate consent or alternatives. Fonts are the lowest-effort fix and a common starting point.