← All posts

Self-hosting web fonts: why and how

When you set up a site, adding a nice typeface takes thirty seconds: you paste a <link> to fonts.googleapis.com and you're done. It's the default reflex. It's also, in my view, one of the worst reflexes on the modern web. On the sites I build, not a single font loads from Google. Here's why, and how I go about it.

The real problem: your visitors go through Google

A font loaded from Google's CDN isn't just a file. To fetch it, every visitor's browser opens a connection to Google's servers and hands over its IP address. Nobody asked, nobody agreed.

This isn't theoretical. In January 2022, the regional court of Munich ordered a site operator to pay €100 in damages to a visitor, precisely because the site passed their IP to Google via Google Fonts, without consent (case 3 O 17493/20). The court reaffirmed that an IP address is personal data under the GDPR — and, tellingly, it explicitly named self-hosting the fonts as the fix: installed on your own server, nothing goes to Google.

Since then, a wave of warning letters has targeted French and German sites on that single ground. Self-hosting isn't paranoia: it's compliance by design, with no extra consent banner.

The other reason: speed

Even setting the data question aside, loading a font from a third party is expensive in performance terms. Before it can even download the file, the browser has to resolve a new domain name, open a connection and negotiate encryption with fonts.gstatic.com. That's a string of network round trips during which the text waits to appear.

When the font lives on the same domain as the rest of the site, none of that happens: the connection is already open, the file arrives with everything else. On a static site built to be fast, this is exactly the kind of detail that shaves hundreds of milliseconds off the first paint.

How I do it, concretely

The method comes down to five steps, and it works for any open-licensed font.

  • Get the woff2 files. It's the only format we need today: compressed, and supported by every modern browser. No need to drag along the old formats.
  • Subset to the characters you use. A full font ships Cyrillic, Greek, Vietnamese and more. If the site is in French and English, I keep only the latin subset (and latin-ext if needed). The file drops from several hundred kilobytes to a few dozen.
  • Declare the @font-face locally. I drop the woff2 files into a /fonts folder and declare them in a small fonts.css:
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-latin-400.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

font-display: swap shows the text immediately with a system font, then switches to yours once it's loaded. No blank screen.

  • Preload the critical font. A <link rel="preload" as="font" type="font/woff2" crossorigin> in the <head> tells the browser to fetch the main font as early as possible.
  • Remove every link to Google. The last step, and the most important: strip out each tag pointing to googleapis.com or gstatic.com, then check the network tab in your dev tools that no request to Google remains. Zero. That's the only check that matters.

What it changes

The result is plain but clear: no visitor data leaves for a third party anymore, the site complies with the GDPR without a patch, and text appears faster because it no longer waits on an external connection. As a bonus, your fonts no longer depend on a third-party service being up — they're yours.

On this blog, everything is self-hosted in that spirit: not one request slips out to Google to render these lines. It takes ten minutes to set up once, and you never think about it again.

Want a site that's fast and clean on this front as on the others? Let's talk.

Got a project in mind? Let’s talk.

Get in touch