Why it matters
A web font usually carries far more than a page needs: accented letters for dozens of languages, Greek and Cyrillic, old-style figures, arrows and symbols. Every byte is on the critical path for the text that uses it, so a 120 KB font that could be 15 KB delays the first readable paint on every slow connection. Subsetting keeps only the glyphs your text uses, and unicode-range lets the browser download a script's file only when the page needs it.
This tool reads the font on your device, including WOFF2 files, which it decompresses with a Brotli decoder and the WOFF2 glyph transform. It maps your text to glyphs through the font's cmap, adds the glyphs that the default ligatures, fractions and contextual alternates can swap in, and follows accented letters to their parts, matching pyftsubset's glyph count on the sample fonts. It then builds a real subset you can preview and download, estimates the size a full subsetter would reach as WOFF2, splits the font into Google Fonts-style script ranges, lists characters the font doesn't have, and writes the @font-face rules and the exact pyftsubset command for production.
How it works
- InputA font file and the text your site shows
- In your browserGlyphs mapped, ligatures and accents followed, a real subset built
- OutputSizes, missing characters, @font-face CSS and the command
Where it fits in a designer's workflow
- Plan
- Design
- Build
- Test
- Launch
By the numbers
Show the numbers as a table
| Font | Glyphs in font | Glyphs kept | Original WOFF2 | Estimate | pyftsubset WOFF2 | pyftsubset glyphs |
|---|---|---|---|---|---|---|
| Inter | 518 | 91 | 47.1 KB | 11.9 KB | 13.7 KB | 90 |
| Fraunces | 245 | 70 | 65.7 KB | 28.5 KB | 26.8 KB | 70 |
| Lora | 282 | 67 | 36.9 KB | 11.5 KB | 12.1 KB | 67 |
| Merriweather | 290 | 86 | 95.3 KB | 28.0 KB | 20.9 KB | 86 |
| DM Sans | 270 | 76 | 61.3 KB | 21.3 KB | 22.9 KB | 76 |
| Montserrat | 322 | 84 | 37.1 KB | 13.3 KB | 14.2 KB | 84 |
| Playfair Display | 318 | 100 | 37.5 KB | 15.2 KB | 13.6 KB | 100 |
| Source Sans 3 | 324 | 96 | 28.2 KB | 10.4 KB | 10.0 KB | 90 |
| Space Grotesk | 291 | 85 | 21.8 KB | 7.9 KB | 7.7 KB | 85 |
| DM Serif Display | 241 | 68 | 24.2 KB | 10.1 KB | 9.8 KB | 67 |
How to use it
- Pick a sample font or open your own.
- Paste the text your site shows in it.
- Choose what to keep: your text, your text plus Basic Latin, or whole scripts.
- Read the sizes and missing characters, then copy the CSS and command.
FAQ
Is my font uploaded?
No. The file is read and subset in your browser. Nothing is sent anywhere.
Why is the .woff download bigger than the estimate?
It keeps the original glyph IDs, so the kerning and ligature tables stay whole. A full subsetter renumbers glyphs and trims those tables; the pyftsubset command gives you that WOFF2.
How accurate is the WOFF2 size?
On the ten sample fonts the typical error against pyftsubset's real WOFF2 was about 6%, and the worst was about a third. It's an estimate because the browser can decompress Brotli here but not compress it.
What happens to characters I didn't include?
The browser draws them with the next font in your font-family list. With unicode-range it can also fetch another subset file that covers them.
Does it keep ligatures and kerning?
Yes. The font's default features, such as fi ligatures and fractions, keep their glyphs, and kerning applies to the glyphs kept. Stylistic sets and small caps are left out unless you add them.
Can I subset variable fonts?
Yes. Each glyph's variation data is kept or dropped with the glyph, so the subset still covers the full weight range.