# Google Fonts Tuned Right Still Trails Self-Hosting by 1.9 Seconds

> We measured web font delivery on 1,186 WordPress sites. The gate every guide leads with changed nothing we could detect, and the one Google hedges on was the largest gap.

- Published: 2026-10-05
- Author: xSpeed Cache Team
- Tags: Fonts, Core Web Vitals, Performance, Research, check:A1
- Canonical: https://xspeedcache.com/blog/web-fonts-lcp-wordpress/

---

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](https://xspeedcache.com/blog/wordpress-speed-fix-priority-order/) documents, and none of the three is used here.

**The limitations, stated before any result.**

1. **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.
2. **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.
3. **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.
4. **`font-display` for 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.
5. **One URL per site**, the page the scan graded, usually the home page.
6. **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](https://web.dev/articles/font-best-practices), `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](https://xspeedcache.com/blog/font-optimization-text-flash/). Set it because the text should be readable. Do not set it expecting a second back.

![The four font gates ranked by measured effect rather than convention: preconnect shows nothing, font-display is mostly page weight, family count is second, self-hosting is the largest gap](https://xspeedcache.com/images/blog/web-fonts-gate-ladder.webp)

## 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.

![Median mobile LCP for third-party font hosts against self-hosted fonts inside four page-weight quartiles, with the third-party cohort slower in every band](https://xspeedcache.com/images/blog/web-fonts-weight-bands.webp)

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.

![Median mobile LCP by cohort: Google Fonts with all three gates open at 12,826 ms, the tuned cohort at 7,501 ms, self-hosted at 5,562 ms, no web font at 4,726 ms](https://xspeedcache.com/images/blog/web-fonts-tuning-ceiling.webp)

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](https://xspeedcache.com/docs/scan-mcp/) 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](https://xspeedcache.com/features/) 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](https://xspeedcache.com/comparison/) sets that against what you run today.

Run the free scan on your own site before changing anything: [xspeedcache.com/scan/](https://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](https://xspeedcache.com/blog/caching-did-not-fix-slow-wordpress/) study sized. [xCloud](https://xcloud.host/) 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=swap` as 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](https://xspeedcache.com/blog/pass-lighthouse-fail-core-web-vitals/).
- **Minifying CSS and losing the font declarations.** Rare, visible and awful, with symptoms in [layout breaks after minification](https://xspeedcache.com/blog/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](https://xspeedcache.com/blog/page-weight-vs-lcp-wordpress/) 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](https://xspeedcache.com/docs/common-problems-and-troubleshooting/).

### 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:**

1. Fetch your home page and count the `fonts.googleapis.com` links in the head. Most teams are wrong about this number.
2. Add `display=swap` to every one of them. One parameter, and it stops invisible text.
3. Count the families. If it is more than two, the next second is there and not in your delivery hints.
4. Price self-hosting against your licences, because the ceiling on tuning sits above the floor on self-hosting.
5. Run the free scan, read check A1, and re-run after each change: [xspeedcache.com/scan/](https://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](https://xspeedcache.com/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](https://xspeedcache.com/blog/wordpress-core-web-vitals-scan-data/) that started this series. Re-run it, and tell us where your numbers disagree with ours.
