Is your font the problem at all?
A font costs you in two ways: it delays text that is the largest element, or it moves the page when it arrives. PageSpeed Insights on mobile names the largest element and shows a "Font display" insight when a font hides text. If the largest element is an image, with one small font and nothing moving, there's little to win.
MarketingTracer's Core Web Vitals page shows how often the largest element was text or an image ("LCP in detail") and the layout shifts per week and device ("CLS in detail"). It covers the whole site, from Chrome visitors over a rolling 28 days, and never names the font.
Step 1: load fewer font files
WOFF2 is the only format you need. One variable file holds every weight. Subsetting keeps only the characters your language needs. Host the files yourself; icon fonts are a job of their own.
All five of my sites load each font family as one variable woff2 file of 27 to 48 KB from their own server.
Step 2: swap or optional?
Use swap when the brand font must show on a visitor's first page, with a same-size fallback (step 4). optional fits when a first visit in the system font is fine: your font gets about 100 ms, or the fallback stays for that page.
A marketingtracer.com article with its 28 KB font, Geist, was loaded six ways on October 30, 2026 (phone width, Slow 4G, 4x slower CPU, median of nine loads):
| Set-up | Text on screen | Font in | CLS | Brand font on first page |
|---|---|---|---|---|
| swap + preload | 796 ms | 1,334 ms | 0.004 | yes |
| swap, no preload | 668 ms | 1,655 ms | 0.004 | yes |
| optional + preload | 796 ms | 1,336 ms | 0 | no |
| optional, no preload | 664 ms | 1,654 ms | 0 | no |
| swap + preload + matched fallback | 776 ms | 1,337 ms | 0.0003 | yes |

A test on marketingtracer.com, Slow 4G, October 30, 2026.
With optional, a phone visitor never saw Geist on the first page (0 of 36 loads, Slow and Fast 4G); it comes from the cache on the next one. swap always delivered it, and the page moved just 0.004, as Geist is about as wide as the system font. A condensed headline font moves far more; a good CLS is 0.1 or less.
I try to keep it to two critical fonts at most, the ones that are really visible. Those I preload, so we usually beat the flash of unstyled text. What you do with the rest is a choice: speed, UX or a mix, and how bad it is if a slow visitor never gets the font. Four of my sites run optional; marketingtracer.com runs swap:
@font-face {
font-family: "Geist";
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url("/static/font/geist.woff2") format("woff2");
}
Skip block, auto and fallback: the "Font display" insight passes only swap and optional. Each value per browser is on corewebvitals.io.
Step 3: is a preload worth it?
Preload only the fonts of the text at the top, and only to get them there sooner: a preload delays the first text a little. In the test the preload made the text 128 ms later on Slow 4G and 104 ms on Fast 4G, and the font 321 and 112 ms sooner. With optional it's the font's only chance: on a fast connection, 9 of 9 loads got the font with a preload, 0 of 9 without.
<link rel="preload" href="/static/font/geist.woff2" as="font" type="font/woff2" crossorigin>
Keep crossorigin, even on your own domain. And never preload a font the page doesn't use: two extra preloads in the test made the real font 256 ms later on Slow 4G.
Step 4: give the fallback font the same size
swap moves the page when the fallback is wider or narrower than your font and the lines break elsewhere. Scale the fallback to match:
@font-face {
font-family: "Geist Fallback";
src: local("Arial");
size-adjust: 102.37%;
}
body {
font: 16px/1.5 "Geist", "Geist Fallback", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}
The percentage is your text's width in your font divided by its width in the fallback. Fontaine and Capsize calculate it, and Next.js's next/font does it itself. In the test it cut the shift from 0.004 to 0.0003. Safari has supported size-adjust since version 17.
Check it with the font switched off
Before you tick fonts off in a site audit, check the change in Chrome. In DevTools, reload with Network on the Font filter: one file per family, from your own domain. Right-click the font file, choose Block request URL and reload at phone width; the lines should break where they did with your font. PageSpeed Insights should stop flagging "Font display", and real visitors' numbers follow within four weeks.