File types · Explainer

The WOFF2 file (.woff2)

A WOFF2 file is a compressed font made for websites: a TrueType or OpenType font packed small enough to download with a page. This guide explains what's inside one, how browsers load it, the quirks worth knowing, and has free sample WOFF2 files to download for testing.

At a glance

Full name
Web Open Font Format 2.0
Extensions
.woff2
MIME type
font/woff2 (RFC 8081, 2017); older servers may send application/font-woff2 or application/octet-stream
Kind
Binary wrapper around a TrueType or OpenType font, compressed losslessly with Brotli
Standard
W3C Recommendation, first published in 2018; current edition 8 August 2024
Opens with
Web browsers (through CSS @font-face), font editors such as FontForge, the fontTools and Google woff2 command-line tools
Typical size
Tens of kilobytes for a Latin text font; megabytes for full Chinese, Japanese or Korean fonts unless subset
Compression
One Brotli stream for all tables, after reshaping the glyf and loca tables
Browser support
Every current browser; not Internet Explorer
Magic number
77 4F 46 32 (wOF2)

The basics

What is a WOFF2 file?

A WOFF2 file is a font, packaged for the web. Inside is an ordinary TrueType or OpenType font, the same kind you would install on a computer, compressed so that a browser can download it quickly when a page asks for it. Once the browser has unpacked it, the font is used exactly like the original: same letters, same spacing, same features.

It is the format to use for custom fonts on a website today. Every current browser supports it, and it is usually the smallest of the font formats. Google Fonts and most other web font services deliver WOFF2 to current browsers.

A few things it is not:

  • Not a different font design. Converting a TTF or OTF to WOFF2 and back gives you a working font with the same glyphs and metrics. Only the packaging changes.
  • Not something you double-click. Browsers don't display font files on their own, and Windows and macOS don't install WOFF2 directly. To use the font in desktop apps, convert it to TTF or OTF first, if its licence allows.
  • Not a new licence. A WOFF2 file is as protected, or as free, as the font it came from. The format adds no copy protection.

Anatomy

What's inside a WOFF2 file

A WOFF2 file is a 48-byte header, a compact table directory, and one Brotli-compressed block holding every table of the original font. Below is our sample-regular.woff2, byte by byte. Numbers in the header are big-endian: 00 00 11 4C is 0x114C, which is 4,428.

sample-regular.woff2 (hex)
offset  bytes                          meaning
000000  77 4F 46 32                    signature "wOF2"
000004  00 01 00 00                    flavor: TrueType outlines
000008  00 00 11 4C                    length: 4,428 bytes
00000C  00 0A                          10 tables
00000E  00 00                          reserved
000010  00 00 2D C4                    decoded font size: 11,716
000014  00 00 10 FF                    compressed data: 4,351
000018  00 01 00 00                    font version 1.0
00001C  00 00 00 00 … (20 bytes)       no metadata, no private data
000030  06 60                          table: OS/2, 96 bytes
000032  00 82 06                       table: cmap, 262 bytes
000035  0A BE 4C AD 69                 table: glyf, 8,012 → 5,865
00003A  01 36                          table: head, 54 bytes
00003C  02 24                          table: hhea, 36 bytes
00003E  03 83 0C                       table: hmtx, 396 bytes
000041  0B 81 48 00                    table: loca, 200 → 0
000045  04 20                          table: maxp, 32 bytes
000047  05 91 29                       table: name, 2,217 bytes
00004A  07 81 68                       table: post, 232 bytes
00004D  …                              one Brotli stream, 4,351 bytes
00114C                                 end of file: 4,428 bytes
  1. 177 4F 46 32

    The signature

    The ASCII letters wOF2. Browsers and tools check these four bytes, not the file extension, to recognise the format.

  2. 200 01 00 00

    The flavor

    What kind of font is inside: 00 01 00 00 for TrueType outlines, OTTO for CFF outlines, ttcf for a font collection. Decoding gives back a font that starts with exactly these bytes.

  3. 300 00 2D C4 / 00 00 10 FF

    Two sizes

    11,716 bytes is how big the font will be once decoded; 4,351 bytes is the compressed block. A decoder can allocate memory before it starts.

  4. 400 00 00 00 … (20 bytes)

    Optional blocks

    Offsets and lengths for an extended metadata block (XML licence and credits) and a private data block. Both are zero here; browsers ignore both anyway.

  5. 506 60

    A table entry

    One flags byte and a length. The low 6 bits of 06 are an index into a fixed list of 63 common table names (6 is OS/2), so common tables need no 4-byte name. 60 is the length, 96, written in a variable-length format called UIntBase128.

  6. 60A BE 4C AD 69

    The transformed glyf table

    Index 10 is glyf, the glyph outlines, with transform bits 0, meaning transformed. BE 4C is the original length (8,012 bytes) and AD 69 the transformed length (5,865). The transform splits points, flags and contour counts into separate streams that compress better.

  7. 70B 81 48 00

    The loca table

    loca lists where each glyph starts in glyf. When glyf is transformed, loca is stored with a length of 0 and rebuilt by the decoder from the glyphs themselves.

  8. 800004D …

    The compressed data

    All ten tables, concatenated in directory order and compressed together as a single Brotli stream. WOFF 1.0 compressed each table separately with zlib, which is one reason WOFF2 files are smaller.

Under the hood

How WOFF2 makes fonts smaller

A desktop font is a collection of tables, each with a four-letter name: cmap maps characters to glyphs, glyf or CFF holds the outlines, hmtx the widths, name the font's names and licence, and so on. WOFF2 keeps all of them but stores them more compactly, in three steps:

  1. 1A shorter directory. Common table names are stored as a 6-bit number instead of four letters, and lengths use a variable-length number format, so small tables take two bytes to describe.
  2. 2Transforms. The glyf table is reorganised so that similar data sits together: all contour counts, then all point counts, then all flags, then all coordinates. Compressors find repeating patterns more easily that way. The loca table is dropped and recomputed, and the hmtx table can optionally drop side bearings that can be worked out from the outlines.
  3. 3Brotli compression. Everything is compressed as one stream with Brotli, a compression format published by Google (RFC 7932), which has a built-in dictionary and handles small files well.

The W3C's evaluation, made while the format was designed, measured median savings over WOFF 1.0 of about 24 to 27% for TrueType fonts and about 13% for fonts with CFF outlines. Against the uncompressed desktop font the saving is bigger still, as our own samples show:

The same font, 99helpers Sample Regular, in each format
FormatSample fileSize
TTF (uncompressed)sample-regular.ttf11,588 bytes
OTF with CFF outlinessample-regular.otf12,172 bytes
WOFF (zlib)sample-regular.woff6,092 bytes
WOFF2 (Brotli)sample-regular.woff24,428 bytes

Lossless, with one subtlety

WOFF2 is lossless in what matters: the decoded font draws exactly the same glyphs. It is not always byte-for-byte identical to the input, because the glyf transform may rebuild loca and pad glyphs differently. Font checksums are recalculated, so tools treat the result as a valid font.

On the web

Loading a WOFF2 font with @font-face

A web page uses a font file through a CSS @font-face rule, which gives the font a name and says where to download it. Each weight and style is its own file and its own rule, joined by the shared font-family name:

style.css
@font-face {
  font-family: "99helpers Sample";
  src: url("/fonts/sample-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "99helpers Sample";
  src: url("/fonts/sample-bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

body {
  font-family: "99helpers Sample", system-ui, sans-serif;
}
  • format("woff2") tells the browser what the file is before it downloads it. A browser that can't read a format skips that source and tries the next one in the list.
  • Do you still need a WOFF fallback? Only for very old browsers. Every current browser reads WOFF2, so most sites now list WOFF2 alone. Older guides add WOFF, TTF and an EOT file for Internet Explorer; that is no longer needed.
  • font-weight and font-style must match the file. If you declare only a regular file and use bold text, the browser fakes bold by thickening the letters, which looks smudged.
  • font-display controls what visitors see while the font downloads (see below).

Fonts are only requested once the browser finds text that needs them, which happens late, after the CSS has loaded. For the one or two fonts used above the fold, a preload hint starts the download straight away. The crossorigin attribute is required even for fonts on your own site, because browsers always fetch fonts in CORS mode:

index.html
<link rel="preload" href="/fonts/sample-regular.woff2"
      as="font" type="font/woff2" crossorigin>

Troubleshooting

Why isn't my web font loading?

  • Blocked by CORS. The font is on a different domain from the page (a CDN, a separate storage bucket) and that server doesn't send an Access-Control-Allow-Origin header. The CSS Fonts specification requires browsers to fetch fonts in CORS mode, so the request fails and the console shows a CORS error. Fix it on the server that hosts the font, or host the font on the same site as the page.
  • Wrong path. URLs inside a CSS file are relative to the CSS file, not to the page. url(fonts/x.woff2) in /css/style.css points to /css/fonts/x.woff2.
  • Wrong MIME type. Browsers detect the format from the file's bytes, so a generic type such as application/octet-stream usually still works. font/woff2 is the correct one, and audit tools flag the others.
  • A file that isn't really WOFF2. A file renamed from .ttf to .woff2 has the wrong signature and is rejected, or works only by accident. Check the first four bytes: they must be wOF2.
  • Invisible text, then a sudden swap. That is the browser waiting for the font: invisible text is called FOIT (flash of invisible text), a visible fallback that changes later is FOUT (flash of unstyled text). font-display decides which you get.
  • Rejected as invalid. Chrome and Firefox run every web font through the OpenType Sanitizer before use, and drop fonts with broken tables that a desktop app might tolerate. The browser console says so.
font-display values (timings as described by Chrome's documentation)
ValueWhile loadingIf the font arrives late
autoBrowser's choice, usually like blockBrowser's choice
blockInvisible text for up to about 3 secondsSwaps in whenever it arrives
swapFallback font straight awaySwaps in whenever it arrives
fallbackInvisible for about 100 ms, then fallbackSwaps in only within about 3 seconds
optionalInvisible for about 100 ms, then fallbackNot used on this page view; may be cached for the next

Performance

Subsetting and unicode-range

Most of a font's size is its glyphs, and most pages only need a fraction of them. Subsetting removes the glyphs you don't need. A font that covers Latin, Greek and Cyrillic can be split so that an English page downloads only the Latin part. Our sample-digits-subset.woff2 keeps just the digits and a few punctuation marks: 1,400 bytes instead of 4,428.

  • Make a subset with pyftsubset from fontTools: pyftsubset font.ttf --unicodes="U+0000-00FF" --flavor=woff2 --output-file=font-latin.woff2. Google's glyphhanger and online tools do the same.
  • Load subsets on demand with the unicode-range descriptor: several @font-face rules share one family name, each with its own file and range, and the browser only downloads files whose range covers characters actually on the page. Google Fonts serves its fonts this way.
  • Check the licence first. Subsetting modifies the font. Open-source licences such as the SIL Open Font License allow it; some commercial licences don't, and the OS/2 table's fsType field can carry a no-subsetting flag.

Subset too tightly and visitors see missing letters, often as boxes or in a fallback font. Names, addresses and user-generated text bring in accents you didn't plan for, so keep at least the full Latin-1 range for European languages.

One file, many weights

Variable fonts in WOFF2

A variable font holds a whole range of styles in one file. Instead of separate files for light, regular and bold, it stores one set of outlines plus instructions for how each point moves along an axis such as weight (wght) or width (wdth). Variable fonts were added to OpenType in version 1.8 (2016), and WOFF2 compresses them like any other font.

style.css
@font-face {
  font-family: "99helpers Sample Variable";
  src: url("/fonts/sample-variable.woff2") format("woff2");
  font-weight: 300 700; /* the range the wght axis covers */
}

h1 { font-weight: 650; } /* any value in the range works */

Our sample-variable.woff2 covers weights 300 to 700 in 9,236 bytes, against 8,832 bytes for the separate regular and bold files together, and it can produce every weight in between. Older articles use format("woff2-variations"); current browsers accept plain format("woff2") for variable fonts.

How to

How to open, install and convert a WOFF2 file

  • See what it looks like: load it in a page with @font-face, or open it in a font editor such as FontForge. The live specimen on this page does exactly that with our sample.
  • Install it on your computer: convert it to TTF or OTF first. Windows and macOS install desktop fonts, not web fonts.
  • Convert TTF or OTF to WOFF2: Google's command-line tool woff2_compress font.ttf, or in Python with fontTools: TTFont('font.ttf'), set font.flavor = 'woff2', then save. fontTools needs the brotli package for this.
  • Convert WOFF2 back: woff2_decompress font.woff2 writes the decoded font as font.ttf, and fontTools does the same when you set flavor to None and save.
  • Inspect it: ttx -l font.woff2 lists the tables; ttx font.woff2 dumps everything as XML.

Converting is technically easy, so licences matter more than tools here. A desktop licence often doesn't cover web use, and a web licence often doesn't cover installing the font. Open-source fonts, such as those on Google Fonts, usually allow both.

Rights and risks

Licences, protection and safety

A font file is software, and fonts are licensed like software. Commercial foundries sell separate licences for desktop use, web use (often priced by page views), apps and e-books. Inside the font, the name table usually carries the copyright and licence, and the OS/2 table has an fsType field with embedding permissions such as installable, editable, preview and print, or restricted. Browsers generally don't enforce fsType; the licence is what counts.

WOFF2 doesn't encrypt anything. Anyone who visits a page can save its fonts from the browser's network panel and decompress them. That is why web font licences rely on contracts rather than technical protection.

Fonts are complex binary formats, and font parsers have had serious security bugs over the years. Chrome and Firefox guard against this by checking every web font with the OpenType Sanitizer before handing it to a font engine. A WOFF2 file can't run code, and the risk from a downloaded font is in bugs, not in a feature of the format.

Free downloads

Sample WOFF2 files to download

Free sample WOFF2 fonts for testing @font-face set-ups, CORS and MIME configuration, font loaders and converters. They use 99helpers Sample, an original geometric typeface we drew for these pages, with Latin letters, digits, common punctuation and a few accented letters.

sample-regular.woff2 · 4.3 KBDownload

Aa Gg 99

ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789 .,:;!?&@#()

14pxThe quick brown fox jumps over the lazy dog

20pxThe quick brown fox jumps over the lazy dog

32pxThe quick brown fox jumps over the lazy dog

48pxThe quick brown fox jumps over the lazy dog

What's inside sample-regular.woff2

The regular weight, encoded with fontTools. The specimen above is drawn with this exact file.

  1. Header

    The wOF2 signature, the TrueType flavor 00 01 00 00, and a total length of 4,428 bytes.

  2. Table directory

    Ten entries in 29 bytes: OS/2, cmap, glyf, head, hhea, hmtx, loca, maxp, name, post.

  3. Transformed glyf and loca

    The outlines of 99 glyphs, reorganised into separate streams; loca is rebuilt on decoding.

  4. Brotli stream

    All tables in one compressed block of 4,351 bytes. Decoded, the font is 11,716 bytes.

  5. Character set

    A to Z, a to z, 0 to 9, .,:;!?&@#()-'"/ and space, plus á à â ä é è ê ë í ï ó ô ö ú ü ñ É Ü Ñ.

  6. Names and licence

    Family 99helpers Sample, style Regular, weight class 400, with the licence and a link back to this page in the name table.

All sample WOFF2 files

  • Regular weight

    sample-regular.woff2 · 4.3 KB (4,428 bytes)

    99helpers Sample Regular (weight 400) with TrueType outlines: 99 glyphs, Latin letters, digits, punctuation and a few accents.

    • Testing `@font-face` and font loading
    • Checking a server sends `font/woff2`
  • Bold weight

    sample-bold.woff2 · 4.3 KB (4,404 bytes)

    The same family at weight 700, drawn with a heavier stroke rather than faked by the browser. Pair it with the regular file under one font-family name.

    • Testing weight matching across two `@font-face` rules
    • Spotting synthetic bold
  • Variable font, weight 300 to 700

    sample-variable.woff2 · 9.0 KB (9,236 bytes)

    A variable font with one wght axis from 300 (Light) to 700 (Bold), with fvar, gvar, HVAR and STAT tables and five named instances.

    • Testing variable-font support and `font-weight` ranges
    • Animating or fine-tuning weight
  • Digits-only subset

    sample-digits-subset.woff2 · 1.4 KB (1,400 bytes)

    The regular font subset to 17 glyphs: 0 to 9, space and .,:-/. Letters fall back to another font, which makes subsetting and unicode-range behaviour easy to see.

    • Testing `unicode-range` and font fallback
    • A tiny valid WOFF2 for upload and parser tests

Ways to test with them

  • CORS: serve sample-regular.woff2 from a second domain and load it from a page; without Access-Control-Allow-Origin the browser refuses it and logs a CORS error.
  • MIME type: request the file with curl -I and check for Content-Type: font/woff2.
  • Weights: declare the regular and bold files under one family and compare font-weight: 700 with the regular file alone, where the browser fakes bold.
  • Variable fonts: load sample-variable.woff2 with font-weight: 300 700 and step through weights; text should get gradually heavier and wider.
  • Fallback: use sample-digits-subset.woff2 for a paragraph of mixed text; only the digits should change font.

Free to use for testing, teaching and demos, commercially or not, with no attribution needed. A link back to this page is always appreciated.

Put it online

Have a WOFF2 file? Give it a link.

Drop a WOFF2 file on 99helpers and it gets its own address in seconds. Opening the link downloads the font, since browsers don't display font files on their own, and a page or site you host on 99helpers can load it with @font-face.

Questions

WOFF2 files, frequently asked

What is a WOFF2 file?

A compressed font for websites. It contains a TrueType or OpenType font, compressed with Brotli so pages load faster, and browsers use it through CSS @font-face.

How do I open a WOFF2 file?

Browsers don't show font files on their own. Use it in a web page with @font-face, open it in a font editor such as FontForge, or convert it to TTF to install it on your computer.

Can I install a WOFF2 font on Windows or macOS?

Not directly. Convert it to TTF or OTF first, for example with woff2_decompress, and check that the font's licence allows desktop use.

What's the difference between WOFF and WOFF2?

Both wrap the same kinds of fonts. WOFF compresses each table with zlib; WOFF2 reorganises the outlines and compresses everything with Brotli, which typically makes files about a quarter smaller. Every current browser supports both.

Do I still need WOFF, TTF or EOT fallbacks?

For current browsers, no: WOFF2 alone is supported everywhere. EOT was only ever for Internet Explorer, and WOFF only matters if you still support browsers from before about 2016.

What is the MIME type of WOFF2?

font/woff2, registered in RFC 8081 in 2017. Servers configured before then sometimes send application/font-woff2 or application/octet-stream.

Why does my WOFF2 font work locally but not online?

Usually CORS: the font is on another domain without an Access-Control-Allow-Origin header. Other causes are a wrong relative path in the CSS file or a server sending an HTML error page instead of the font.

Is converting a font to WOFF2 legal?

The format doesn't decide that; the licence does. Open-source fonts generally allow it. Many commercial desktop licences don't cover web use, so check before you convert and upload a font you bought.

Related formats

Other file types explained

Keep going

Related

Sources

Last reviewed 27 October 2026.