DEV Community

Hannes
Hannes

Posted on • Originally published at howsafeismyapp.com

Self-hosting Google Fonts: the 15-minute fix for a classic GDPR finding

Originally published on howsafeismyapp.com.

If your app's <head> contains a line like

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

then every visitor's browser contacts Google's servers before your page even renders — transmitting their IP address along the way. In 2022, a German court (LG München I) ruled that exactly this, done without consent, violates visitors' rights, and awarded damages to a website visitor. The decision triggered a wave of warning letters (Abmahnungen) against site operators, aimed precisely at small sites that had copied the standard embed code.

It remains one of the most common findings on AI-built apps, because font embeds are baked into templates and AI-generated layouts. It is also one of the easiest to fix. (Practical guidance, not legal advice.)

Why this is a GDPR issue at all

An IP address is personal data. Sending it to a third party requires a legal basis (Art. 6 GDPR), and transfers to US providers raise the additional third-country questions of Art. 44 GDPR. "The CSS loads faster from Google's CDN" is not a legal basis — especially since self-hosting is equivalent in practice: fonts served from your own domain are cached, local, and remove a DNS lookup and TLS handshake to a foreign origin. The details are on our check page: Google Fonts loaded directly from Google.

Fonts are the famous example, but the same logic applies to anything your page pulls from third-party CDNs on first load — icon fonts, CSS frameworks, JS libraries.

Find out if your app is affected

Fastest way: our free Google Fonts checker answers this in seconds. Manually: open your app in a private window with DevTools → Network, reload, and filter for fonts.googleapis.com or fonts.gstatic.com. In a Lovable/Bolt/v0 project you can also just search the code for googleapis — the embed usually sits in index.html or a global CSS file.

The fix: serve the fonts yourself

  1. Download the font files. The open-source tool google-webfonts-helper packages any Google Font as .woff2 files with ready-made CSS — or download from the font's official repository. .woff2 alone is enough for every current browser.
  2. Put the files in your app's public/static folder, e.g. public/fonts/inter-v13-latin-regular.woff2. In Lovable, add them to the project's public assets.
  3. Replace the Google <link> with local @font-face rules:
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/inter-v13-latin-regular.woff2") format("woff2");
}
Enter fullscreen mode Exit fullscreen mode
  1. Delete the fonts.googleapis.com link tag — this step is the actual fix; the scanner (and the warning-letter industry) looks for the request, not your intentions.
  2. Reload with the Network tab open: there should be no request leaving your domain for fonts.

Total effort for a typical two-font app: about 15 minutes.

Two upgrades while you're at it

  • Long cache lifetimes for font files. They never change; a year-long Cache-Control header makes repeat visits faster than the Google CDN ever was.
  • Check the rest of your first load. If fonts came from a third party, other resources often do too. Loading anything over plain HTTP is its own finding — resources loaded over unencrypted connections — and third-party tracking scripts are a much bigger consent problem than fonts: tracking loads before anyone could consent.

Verify from the outside

The nice thing about this class of problem: it is fully visible from the outside, no access to your code needed. Our free passive scan requests your app like any anonymous browser would and reports every third-party request on first load — fonts included — plus 14 other checks. Takes about a minute; nothing gets stored.

Common questions

Does font-display: swap or preconnect help legally?

No. Those are performance tweaks — the legal issue is the request to Google's servers itself, which transmits the visitor's IP address. Only removing the request fixes it.

What about Bootstrap, jQuery or icon CDNs?

Same logic. Any resource loaded from a third-party CDN on first paint transmits visitor IPs to that provider without a legal basis. Self-host what you can; whatever remains needs a justification and a mention in your privacy policy.

Is this a fine risk or a warning-letter risk?

In practice, warning letters and small damages claims — the 2022 Munich decision awarded a visitor damages, and copycat claims followed in waves. The cost of a single response letter to a lawyer exceeds the cost of self-hosting many times over. If you're doing a broader consent cleanup anyway, start here: Do you need a cookie banner?.

Top comments (0)