Google Fonts Tuned Right Still Trails Self-Hosting by 1.9 Seconds
Updated October 2026
Google’s own font guide states that Chromium-based and Firefox browsers block text rendering for up to 3 seconds when a web font has not arrived, and that Safari blocks it indefinitely. A direct fetch of the Google Fonts API on 5 October 2026 returned 9 @font-face blocks and not one font-display declaration unless the URL carried a display parameter. The advice that follows is everywhere. What is missing is what any of it is worth, so we measured the font delivery chain on 1,186 WordPress sites and ranked the fixes by what moved.
The ranking that came back is not the ranking the guides publish.
Quick summary: the four font gates, ranked by measurement
| If you want… | Do this | Why |
|---|---|---|
| The largest measured gap | Move fonts off a third-party host onto your own origin | The widest difference in the study, and it stays significant inside every page-weight band |
| The second largest | Cut the number of font families to one or two | Sites requesting 4+ families carry 2,681 ms more median LCP than sites requesting one |
| To stop invisible text | Add display=swap to every Google Fonts URL | 18.9% of Google Fonts sites still ship a link without it, and without it the browser applies auto |
| To stop guessing | Run the free xSpeed Scan and read check A1 | It reports the blocking set on your own URL, which is the only measurement that applies to you |
| To spend effort well | Skip preconnect as a performance fix | Sites with and without it were statistically indistinguishable, at p = 0.098 |
That last row is the uncomfortable one. Google’s own font guide calls preconnect “highly recommended” for third-party fonts. In this dataset it did nothing we could measure.
What we measured, what it cost, and what it cannot tell you
The method comes first, because every number below is bounded by it.
We harvested all 3,075 public reports in the xSpeed Scan archive on 5 October 2026 through the structured endpoint at /api/scan/{scanId}, with zero fetch errors. 2,071 of them are WordPress. We then fetched each of those sites live and parsed the <head> for every font declaration: provider links, their parameters, preconnect and preload hints, inline @font-face blocks and self-hosted font file references.
Two populations, and what fell out between them.
| Population | n | What it is |
|---|---|---|
| WordPress sites in the archive | 2,071 | Every WordPress report, one per distinct host |
| Did not answer | 134 | 66 connection, TLS or timeout failures; 45 HTTP 403; 23 other HTTP statuses |
| Answered without a readable head | 80 | Responded, but no </head> inside the first 400 KB |
| Declaration census | 1,857 | What these sites declare: providers, parameters, hints |
| Cost analysis | 1,186 | The subset whose report also carries a graded Lighthouse view and check A1 |
The cost population is smaller because the per-device devices block and check A1 only exist from rubric version 2026.09.3 onward. We checked before pooling: A1, S2 and S5 carry identical names and identical weights across every rubric version in the population, so pooling them is safe. That is not true of every check. Three definitions changed under this archive on 1 October 2026, which the measured fix-priority ladder documents, and none of the three is used here.
The limitations, stated before any result.
- This is observational. Nobody assigned a site to a cohort. Sites that self-host differ from sites that do not in ways we did not measure, including budget and who built them.
- Weight is the obvious confounder, so we controlled for it. Every comparison below is also run inside page-weight quartiles. Where a gap survives, we say so. Where it does not, we say that too, and one headline gap does not.
- A
<head>census sees declarations, not paint. The report does not name which element painted LCP, so nothing here claims a font was the LCP element. These are the sites that ask the browser for a font, and this is how they score. font-displayfor self-hosted fonts is largely invisible to us. It lives inside CSS. We read it in inline<style>blocks and in a Google Fonts URL, not inside an external stylesheet we did not fetch.- One URL per site, the page the scan graded, usually the home page.
- 45 sites carried more than 6 Google Fonts hrefs, above our storage cap, so their per-link state is partial.
Google Fonts ships no font-display at all unless you ask for it
This is the fact the whole display=swap convention rests on, so it is worth verifying rather than repeating. A direct fetch on 5 October 2026 returned:
| Request | @font-face blocks | font-display lines | Bytes |
|---|---|---|---|
css2?family=Roboto:wght@400 | 9 | 0 | 5,547 |
css2?family=Roboto:wght@400&display=swap | 9 | 9 | 5,745 |
css?family=Roboto | 9 | 0 | 5,547 |
css?family=Roboto&display=swap | 9 | 9 | 5,745 |
Both API versions behave the same way. Leave the parameter off and the served CSS declares no font-display property, which means the browser applies auto. Per Google’s own font best practices guide, auto leaves the decision to the browser: Chromium-based browsers and Firefox block text rendering for up to 3 seconds, and Safari blocks it indefinitely. The whole fix is one URL parameter and 198 bytes of extra CSS.
The swap gate is mostly closed already, and that is the surprise
Font advice is written as though nobody has done this. The census says otherwise.
| Gate | Closed on | Open on |
|---|---|---|
display=swap on every Google Fonts link | 615 of 816 (75.4%) | 201 sites (24.6%), of which 154 ship a link with no display at all |
Preconnect to fonts.gstatic.com | 374 of 816 (45.8%) | 442 sites (54.2%) |
| Preload at least one font file | 83 of 816 (10.2%) | 733 sites (89.8%) |
| One or two families only | 657 of 816 (80.5%) | 159 sites request 4 or more (19.5%) |
Across every Google Fonts stylesheet link in the cost population, 938 carried swap, 135 nothing, 58 auto, and 7 fallback, optional or block. Three sites in four have already done the thing the guides lead with.
The raw comparison looked promising. Sites with a link missing display have a median mobile FCP of 4,550 ms against 3,492 ms for sites with swap everywhere, and a median LCP of 11,517 ms against 7,764 ms. Both are significant on a two-sided Mann-Whitney U test, at p = 0.0014 and p = 0.010.
Then we stratified by page weight, and most of it evaporated.
| Weight band | Sites with no display | Sites with swap | Median FCP gap | Significant? |
|---|---|---|---|---|
| Under 943 KB | 12 | 68 | 2,576 vs 2,707 ms | ❌ |
| 943 KB to 1.9 MB | 21 | 94 | 3,751 vs 3,157 ms | ❌ |
| 1.9 MB to 3.7 MB | 23 | 90 | 4,701 vs 4,044 ms | ❌ |
| Over 3.7 MB | 40 | 108 | 5,552 vs 4,088 ms | ✅ |
The cohort missing display is also 968 KB heavier at the median, itself significant at p = 0.040. Inside a weight band the gap holds in one band of four. The honest reading is that sites which never set display are mostly sites nobody tuned at all, and the raw 1,058 ms gap is measuring that.
None of which argues against setting it. font-display: swap fixes invisible text, a user-visible defect whether or not it moves a metric, and what it trades away is covered in why font optimization makes text jump. Set it because the text should be readable. Do not set it expecting a second back.

Preconnect did nothing we could measure
220 of the 484 Google Fonts sites in the cost population preconnect to fonts.gstatic.com, at a median FCP of 3,511 ms. The 264 that do not sit at 3,756 ms, which does not reach significance at p = 0.098. On LCP the two are closer still, 8,138 against 8,546 ms at p = 0.56.
The theory is sound. A preconnect buys the DNS lookup, TCP handshake and TLS negotiation ahead of the request, and on a cold connection that is real time. What it does not price is that the font stylesheet is requested early anyway, from a head already carrying a dozen other blocking resources, so connection setup is rarely the thing on the critical path.
A null result is not proof of no effect. It bounds the effect to something smaller than 484 sites can resolve. Keep the hint, because it costs one line and carries no risk. Stop counting it as work done.
Families are the second-largest lever, and nobody ranks them second
The median Google Fonts site requests 2 families. 159 of 816 request 4 or more, and one asks for 13.
| Families requested | Sites | Median FCP | Median LCP |
|---|---|---|---|
| 1 | 215 | 3,427 ms | 7,951 ms |
| 4 or more | 91 | 3,758 ms | 10,632 ms |
The LCP difference is 2,681 ms at p = 0.034, and the FCP difference is 331 ms at p = 0.023. Most font checklists file family count under subsetting, below the delivery hints. Measured against the archive it is second on the list, and it is the one gate here that is usually a theme setting rather than a code change.
The weight lists say the same thing louder. 543 of 816 Google Fonts sites (66.5%) carry at least one link declaring 8 or more numeric weights, and the median site’s heaviest link declares 18. A browser downloads only the weights a page actually uses, so that is a declaration count and not a byte count. It is still the clearest marker in the data of a link nobody chose by hand.
The hosting gap is the largest in the study, and it survives page weight
853 of the 1,857 sites censused (45.9%) load a text font from a third party, and 816 of those use Google Fonts. Narrowing to the 1,186 that also carry a graded Lighthouse view, and comparing against sites that self-host with no third-party text provider at all:
| Cohort | n | Median FCP | Median LCP | Median Lighthouse | Median bytes |
|---|---|---|---|---|---|
| Third-party font host | 515 | 3,651 ms | 8,364 ms | 59 | 2,328 KB |
| Self-hosted only | 314 | 2,401 ms | 5,562 ms | 70 | 1,551 KB |
| No web font declared | 343 | 2,284 ms | 4,726 ms | 71 | 1,776 KB |
FCP differs by 1,250 ms at p below 10^-15. LCP differs by 2,802 ms at p = 2.1 × 10^-11. Lighthouse differs by 11 points at p = 7.6 × 10^-13.
Those cohorts also differ by 777 KB, so the obvious objection is that this is page weight wearing a font costume. It is not, or not only. Split every site into page-weight quartiles and compare inside each band: the third-party cohort is slower on FCP in all four, with p values from 3.3 × 10^-9 in the lightest quartile to 3.3 × 10^-4 in the heaviest. On LCP it holds in three of four.

Google’s own font guide hedges exactly here. It says self-hosting “should deliver better performance as it eliminates a third-party connection setup”, then adds that “in practice, the performance differences between these two options is less clear cut”. On 829 WordPress sites carrying both cohorts, it was the clearest difference we found.
The ceiling on a tuned font CDN sits above the self-hosted floor
The fair test is a well configured Google Fonts site against a self-hosted one, not a typical one. So we isolated the sites doing everything the guides ask: swap on every link, a preconnect to fonts.gstatic.com, and fewer than three families. That is 130 sites, 26.9% of the cohort.
| Cohort | n | Median LCP |
|---|---|---|
| Google Fonts, all three gates open | 31 | 12,826 ms |
| Google Fonts, whole cohort | 484 | 8,401 ms |
| Google Fonts, all three gates closed | 130 | 7,501 ms |
| Self-hosted only | 314 | 5,562 ms |
| No web font declared | 343 | 4,726 ms |
The tuned cohort sits about 900 ms below the Google Fonts average on median LCP. It still lands 1,939 ms above self-hosted sites, at p = 0.0004, and 2,775 ms above sites with no web font, at p = 0.0000005.

The decision is a sequence, not a checklist. Tune what you have, because it is free. Then accept that tuning has a ceiling, and the ceiling sits above the floor of serving the files yourself.
What our own scanner cannot tell you here, and why we are saying so
Check A1 in the xSpeed rubric grades render-blocking resources, and its evidence line names the blocking files. It looked like the obvious instrument for this study. It is not, and the bound is worth publishing.
A1 fails on 1,168 of the 1,322 WordPress reports that carry it, 88.4%. The median failing site has 8 blocking files. The evidence line names at most 3 of them, so 1,020 of those 1,168 lists, 87.3%, are truncated. fonts.googleapis.com is visible in 17 of them, 1.5%, while our own census shows that 42.9% of the same sites do link it.
A 1.5% reading against a 42.9% reality is not a finding about fonts. It is a finding about the instrument, and a study built on that evidence line would have concluded fonts almost never block paint. The delay A1 attributes is still useful in aggregate: a median of 2,400 ms across failing sites, 5,200 ms at the 90th percentile, 28,600 ms at worst. Use it to size the problem, not to attribute it.
Running this across a WordPress estate
One site is an afternoon. Forty client sites is a different job, because the answer and the fix both differ per theme.
The estate version of this study is three questions per site: which provider, how many families, and whether anything in the head blocks paint before the font is even requested.
xSpeed Cache is our own plugin, built by WPDeveloper. The useful part at estate scale is that its checks run from the command line and from an MCP client, so an agent can run the scan across fifty sites and hand back only the ones with a font in the blocking chain. The 80-capability comparison sets that against what you run today.
Run the free scan on your own site before changing anything: xspeedcache.com/scan/
Hosting is the other half and we do not pretend otherwise. If the first byte takes 600 ms, no font change rescues it, which is the cohort the caching did not fix it study sized. xCloud is our standing recommendation there, and it is ours: xCloud and WPDeveloper are both Startise companies.
Our own sites are in this dataset, and two of them are bad
Seven WPDeveloper and Startise properties were in the population and six carry a graded view. Publishing the flattering rows and hiding the rest would make every other number here worth less.
| Our site | Google Fonts | display | Preconnect | Median LCP |
|---|---|---|---|---|
| essential-blocks.com | ✅ | swap on all 4 links | ✅ | 4,801 ms |
| betterdocs.co | ✅ | swap on both links | ❌ | 3,901 ms |
| embedpress.com | ❌ | self-hosted | ✅ | 4,201 ms |
| easy.jobs | ✅ | swap on all 3 links | ✅ | 12,751 ms |
| wpdeveloper.com | ✅ | none on its one link | ❌ | 10,015 ms |
| docs.templately.com | ✅ | one none, one auto | ❌ | 21,301 ms |
docs.templately.com has a median mobile FCP of 20,101 ms, the 99.3rd percentile of every site measured. easy.jobs has every font gate closed and an LCP of 12,751 ms, which is the article’s own argument back at us: closing the font gates does not rescue a heavy page.
The plugin number is no kinder. 584 sites in the population run xSpeed Cache. Their median FCP is 3,044 ms against 2,733 ms for sites that do not, at p = 0.0001, and their median LCP is 7,002 ms against 6,068 ms at p = 0.010. Sites install a cache plugin because they are slow, so a cohort of them running slower is what selection looks like rather than evidence the plugin hurts. Observational data cannot settle it, which is the caveat applied to every cohort above and applies here too. The one row that goes our way: 77.5% of the Google Fonts sites running xSpeed set swap on every link, against 72.6% of the rest.
| Cache plugin | Google Fonts sites | swap everywhere | Preconnect | Median LCP |
|---|---|---|---|---|
| xSpeed Cache | 282 | 77.7% | 50.7% | 8,701 ms |
| None detected | 105 | 67.6% | 32.4% | 7,245 ms |
| LiteSpeed Cache | 46 | 73.9% | 34.8% | 6,524 ms |
| WP Rocket | 25 | 84.0% | 72.0% | 9,864 ms |
| WP Fastest Cache | 10 | 80.0% | 60.0% | 12,230 ms |
Common mistakes teams make with web fonts
- Adding preconnect and calling the font work done. It is the cheapest line in the head and, on this evidence, the one with the least to show for it.
- Treating
display=swapas a speed fix. It is a readability fix. The speed gap attached to it is mostly page weight. - Letting a page builder pick the families. 19.5% of Google Fonts sites request four or more, which is usually a theme default rather than a decision.
- Loading every weight of a family. Two sites in three declare eight or more weights on a single link.
- Self-hosting without subsetting. Moving files to your origin removes the third-party connection. It does not shrink a 400 KB CJK font.
- Measuring on desktop. The two views of one report disagree constantly, which is the subject of passing Lighthouse and failing Core Web Vitals.
- Minifying CSS and losing the font declarations. Rare, visible and awful, with symptoms in layout breaks after minification.
Frequently Asked Questions
My Lighthouse report says “Ensure text remains visible during webfont load”. Is that the same as this?
Close. That audit fires when a @font-face has no font-display value avoiding an invisible block period, so it catches the 18.9% cohort above. It will not tell you that your font host is costing more than your font-display value saves.
I added display=swap and my LCP did not move. Did I do it wrong?
Probably not. Inside a page-weight band the swap gap holds in one quartile of four. It stops invisible text, a real defect, and it moves FCP when text paints first. If an image paints your LCP, no font setting touches it.
My theme loads fonts and I cannot find where. How do I check?
Fetch the page and read the <head>. Look for <link> tags pointing at fonts.googleapis.com, use.typekit.net or fonts.bunny.net, for @font-face in inline <style> blocks, and for .woff2 references. The scan reports the blocking set under check A1, naming only the first three files.
We self-host already. Is there anything left to do?
Subsetting and weight count. Self-hosted sites are the fast cohort here, but the study cannot see inside their CSS, so their font-display state and file sizes are unmeasured. Page weight against LCP is where to start on size.
My site uses Font Awesome. Does any of this apply?
Partly. Icon fonts appeared on 4.6% of sites and were counted separately, because an icon font rarely paints the largest element. The delivery arguments hold. The invisible-text argument mostly does not.
Does moving fonts to our own server break anything?
Check the licence, not the technology. Google Fonts files are open licensed and can be served from your origin. Commercial foundry fonts frequently cannot, and self-hosting one can breach its licence.
I cannot reproduce your numbers on my own site. Why?
Because these are medians across cohorts of hundreds of sites, not a prediction for any one of them. The spread inside every cohort here is wider than the gaps between them. Scan your own URL and use that number, then read the troubleshooting guide.
Why not just remove web fonts entirely?
28.9% of the sites in the cost analysis do exactly that, and they are the fastest cohort at a median LCP of 4,726 ms. For many sites it is the right call. For a brand with a typographic identity it is not a performance decision at all.
My font files are on a CDN that is not Google. Does the hosting finding apply?
The measured cohort is third-party font providers as a class, with Google Fonts making up 816 of 853. A CDN serving files from your own domain is not a third party in this sense, because there is no extra origin to connect to.
Is a variable font better than four static weights?
Usually, and the study cannot prove it. Weight count is visible in a Google Fonts URL but file sizes are not, so this one is left open rather than answered badly.
How often does this change?
The archive grows daily and the rubric moved three check definitions on 1 October 2026. Every figure here is dated 5 October 2026 and should be re-measured rather than quoted a month from now. The harvest takes ten minutes.
Conclusion: the font roadmap for the rest of 2026
| If you are… | Do this first | Expected to move |
|---|---|---|
On Google Fonts with no display | Add display=swap to every link | Invisible text, not the metric |
| On Google Fonts, already tuned | Cut families to one or two | LCP, by the second largest gap measured |
| Already at one or two families | Self-host the files | The largest gap in the study |
| Already self-hosting | Subset and cut weights | Unmeasured here, and the open question |
| Unsure which of these you are | Scan the URL and read check A1 | Tells you which row you are on |
What to do this week:
- Fetch your home page and count the
fonts.googleapis.comlinks in the head. Most teams are wrong about this number. - Add
display=swapto every one of them. One parameter, and it stops invisible text. - Count the families. If it is more than two, the next second is there and not in your delivery hints.
- Price self-hosting against your licences, because the ceiling on tuning sits above the floor on self-hosting.
- Run the free scan, read check A1, and re-run after each change: xspeedcache.com/scan/. xSpeed Cache is ours and free to start, with paid plans from $29/yr and a 14-day money-back guarantee, set out on Free vs Pro.
Every figure came from one harvest of a public archive, and the method is in the first-party Core Web Vitals study that started this series. Re-run it, and tell us where your numbers disagree with ours.