Performance
Web fonts: fonts from your own server
Why fonts from third-party servers are a legal risk in Germany, which format and how many weights you need, and how the text stays visible until the font arrives.
9 min read
By Timo Wessels Published
A web font is a file that has to be loaded just like an image. How it is embedded affects three things: data protection, loading time and what visitors see before the font arrives. The short answer: serve the fonts from your own server, as WOFF2 only, in as few weights as possible, with font-display: swap and a matching fallback font. The most important part is your own server — not because of speed, but because of a court judgement.
Four questions for every font
Fonts do not show up in the visible part of a website. They are embedded in CSS files, in a theme or in a plugin, and so often go unnoticed for years. According to the 2025 Web Almanac, 88 percent of websites use web fonts. Ask each of them four questions:
- Where does it come from — your own server or someone else's?
- How much does it weigh in total, across all weights and styles?
- What format is it in?
- What happens until it arrives — does the text stay visible or disappear for a moment?
The legal side: fonts from someone else's server
When fonts are loaded from a third-party server — the best-known case is Google Fonts — the visitor's browser opens a connection there as the page loads. Google's own FAQ lists what arrives: the IP address, the requested URL and the HTTP headers, including the browser identifier and the referring page.
IP addresses are personal data. The Court of Justice of the European Union ruled so for dynamic IP addresses on 19 October 2016 in the Breyer case (C-582/14): it is enough that the operator could have the person identified with the help of third parties.
The judgement of the Munich I Regional Court of 20 January 2022 (case 3 O 17493/20) builds on this. A website had loaded Google Fonts from Google's server without consent. The court ordered the operator to stop and to pay 100 euros in damages. The reasoning is the core: a legitimate interest under Art. 6(1)(f) GDPR was ruled out because Google Fonts can also be used without a connection to Google's servers and without transmitting the IP address. It is a regional court's decision, not a ruling from the highest court — but its reasoning applies to any website that loads fonts from third-party servers without need.
The good news: with self-hosted fonts, no IP address goes to Google when the font loads. This is one of the few points where a technical change resolves a legal question instead of managing it. According to the 2025 Web Almanac, around a third of websites now serve only their own fonts, while Google Fonts is still embedded on 54 percent of desktop and 47 percent of mobile websites.
Speed: no automatic gain
A third-party font source needs extra connections — for Google, two: to fonts.googleapis.com for the CSS and to fonts.gstatic.com for the files. Self-hosted fonts save these connections.
The former advantage of the central service is gone: a visitor used to load a popular font once and reuse it on every website. Since version 86 (2020), Chrome partitions its cache by website, and Safari partitions too. Google's FAQ itself states that cross-site caching no longer holds.
To be honest, self-hosting is still not automatically faster. web.dev points out that the Web Almanac even measured faster rendering on sites using third-party fonts, and advises checking before the switch that your site is served through a CDN and over HTTP/2. In Germany the decisive argument is the legal one. Speed is a bonus if the server is right.
The format: WOFF2
Here the answer is clear. According to web.dev, WOFF2 compresses 30 percent better than WOFF and is supported everywhere. web.dev advises serving WOFF2 only. Adding older formats such as TTF, EOT or WOFF brings nothing but longer CSS rules and the risk of double downloads.
The web has largely caught up: according to the 2025 Web Almanac, WOFF2 accounts for around 65 percent of font requests. If you download a font as TTF, convert it before building it in.
The scope: weights and characters
Every font family in every weight and style is a separate file. Three families with four weights each make twelve files. According to the 2025 Web Almanac, the median mobile home page loads 122 KB of fonts.
Fewer weights. Most websites need very few — regular and bold, italic only if it really occurs. A common mistake: the embed requests every weight from 100 to 900 and two are used. The browser loads what was requested.
Fewer characters. A font often contains Cyrillic, Greek and Vietnamese characters a German website never needs. A subsetting tool reduces the file to what is needed, and unicode-range in the @font-face tells the browser which characters it contains. The Google Fonts API offers the text= parameter for this, which according to Google can make the file up to 90 percent smaller — useful for logos and short headings with known text.
Variable fonts. A variable font holds all weights in one file. In an experiment by Monotype, 48 individual files became one, 88 percent smaller. web.dev adds a caveat: if you only use a single weight, you gain nothing, because the variable file is larger than a single static one. According to the 2025 Web Almanac, around 40 percent of websites use at least one variable font.
What happens while it loads
Between the moment the text is there and the moment the font arrives, the browser has to decide what to show. You control that decision with font-display.
Without a setting the browser decides, and many hide the text until the font is there. With block, according to web.dev, this invisible phase lasts two to three seconds. On a slow connection the visitor stares at an empty area although the text loaded long ago.
With font-display: swap the text appears at once in a fallback font and is swapped as soon as the web font arrives. That is almost always the right choice — according to the 2025 Web Almanac, around half of pages use it:
@font-face {
font-family: "Onest";
src: url("/fonts/onest-regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
The price of swap: if the fallback and the web font run at different widths, lines break differently at the swap and the page shifts. Three remedies:
- Match the fallback font. With
size-adjustandascent-overridein a separate@font-facefor the fallback, it can be scaled so that the swap is barely noticeable. - Preload the critical files so they arrive earlier.
crossoriginis mandatory here, even when the file comes from your own server:
<link rel="preload" href="/fonts/onest-regular.woff2" as="font" type="font/woff2" crossorigin>
font-display: optional, when stability matters more than the font on the first visit: if it does not arrive straight away, the fallback stays.
Preloading belongs only on the one or two files needed for the visible area. Preloading everything gains nothing.
And the fastest solution of all: a system font. It is already on the device, and the text is there at once. If the typeface is not essential to the brand, it is a serious option — for body text, say, while the brand is carried by the headings.
How to check it yourself
The Network tab. Open the developer tools (F12), Network tab, filter "Font", reload the page. You see every font file with its origin and size. Three questions for the list:
- Does
fonts.gstatic.comorfonts.googleapis.comappear anywhere? - How many files are there?
- What is the total?
The page source quick test. Ctrl+U, then Ctrl+F and search for fonts.googleapis.com. A hit is a finding. But: a plugin or theme can also request the font from a CSS file loaded later. Then it is not in the page source but does appear in the Network tab. The Network tab is the more reliable check.
The throttling test. Set a slow connection in the Network tab and reload. If the text only appears after a while, font-display: swap is missing. If it appears and the page shifts afterwards, you are seeing the swap effect.
What to do
- Bring the fonts onto your own server. By hand: download the files as WOFF2, put them in a folder in the project, remove the third-party embed, create one
@font-facerule per weight with the matchingfont-weightandfont-style, and name a fallback in the font stack. In WordPress from version 6.5, the Font Library in the editor does this: installing a Google font there puts the file on your own server, stored under/wp-content/uploads/fonts. - Add
font-display: swapto every@font-facerule. - Reduce the weights to those actually used.
- Preload the one or two critical files, with
crossorigin. - Check again after every plugin or theme change. Some bring their own fonts and load them from third-party servers again — even when yours were switched long ago. That is the most common reason a fixed problem comes back.
And if you are building from scratch: settle the font question before the layout, not after. Removing weights later means touching the design.
Sources
- Munich I Regional Court, judgement of 20.01.2022, case 3 O 17493/20 — injunction, 100 euros damages, no legitimate interest because Google Fonts can be used without a connection to Google: gesetze-bayern.de
- dejure.org, CJEU, judgement of 19.10.2016, C-582/14 (Breyer) — dynamic IP addresses as personal data: dejure.org
- Google Fonts, FAQ — data transmitted with a request, no more cross-site caching: fonts.google.com
- Chrome for Developers, Gaining security and privacy by partitioning the cache — partitioned cache since Chrome 86: developer.chrome.com
- web.dev, Best practices for fonts — self-hosting not automatically faster, two Google origins, WOFF2 30 percent better than WOFF, block period,
size-adjust: web.dev - HTTP Archive, Web Almanac 2025, Fonts — 88 percent with web fonts, Google Fonts 54 and 47 percent, a third self-hosted only, 65 percent WOFF2, around half with
swap, around 40 percent variable fonts: almanac.httparchive.org - HTTP Archive, Web Almanac 2025, Page Weight — 122 KB of fonts on the median mobile home page: almanac.httparchive.org
- Google Fonts, CSS API v2 —
text=parameter up to 90 percent smaller,display=swap: developers.google.com - web.dev, Introduction to variable fonts on the web — 48 files in one, 88 percent smaller: web.dev
- MDN,
font-display— block, swap and failure periods of the values: developer.mozilla.org - Chrome for Developers, Ensure text remains visible during webfont load — invisible text while loading: developer.chrome.com
- web.dev, CSS size-adjust for @font-face — matching the fallback font against shifts: web.dev
- MDN,
rel=preload—crossoriginon fonts even from your own server: developer.mozilla.org - WordPress Core, New Feature: Font Library — Google fonts downloaded to your own server on install: make.wordpress.org
- WordPress Developer Blog, How to register custom font collections for the Font Library — stored under
/wp-content/uploads/fonts: developer.wordpress.org