How to detect font format from file magic bytes
- Step 1Rename to a font extension first — The upload box accepts only `.ttf`, `.otf`, `.woff`, and `.woff2`. If your mystery file is `mystery.bin` or has no extension, rename it to `mystery.ttf` first — the byte check ignores the extension for detection, but the upload gate checks it.
- Step 2Drop the file — Click the drop zone or drag the file in. Free tier accepts up to 5 MB, Pro up to 50 MB, Developer up to 1 GB. The size limit applies even though only the first bytes matter for detection, because the file is read into memory before the magic is inspected.
- Step 3Press Process — There are no options for this tool — it has a single button. The first 4 bytes are matched against the known sfnt magic values, and for WOFF/WOFF2 the wrapper header at offsets 4 and 16 is read for the extra fields.
- Step 4Read the metric pills — The result panel shows Format, Magic (hex without the `0x` prefix), and Extension match (yes/no). For raw sfnt you also get Tables; for WOFF/WOFF2 you get Wrapped flavor plus the wrapped/decompressed size in KB.
- Step 5Check extension_matches_format — In the JSON body, `extension_matches_format` is `true` only when the filename ends with `.<detected-format>` (lower-cased). If it is `false`, the extension is lying — rename the file to match the real format.
- Step 6Copy or download the report — Use Copy to clipboard for pasting into a ticket, or Download to save `{stem}.format.json`. Both contain `filename`, `file_size_bytes`, `format`, `magic`, `description`, `extension_matches_format`, and any format-specific extras.
Magic values the tool recognises
The exact 32-bit big-endian values matched by the detector. Anything not in this list returns format unknown with the raw magic hex echoed back.
| Bytes (hex) | ASCII | Reported format | Description in the JSON |
|---|---|---|---|
00 01 00 00 | (none) | ttf | TrueType outline font (sfnt with TrueType glyphs) |
4F 54 54 4F | OTTO | otf | OpenType / CFF outline font (sfnt with PostScript glyphs) |
77 4F 46 46 | wOFF | woff | Web Open Font Format 1.0 — zlib-compressed sfnt wrapper |
77 4F 46 32 | wOF2 | woff2 | Web Open Font Format 2.0 — Brotli-compressed sfnt wrapper |
74 74 63 66 | ttcf | ttc | TrueType Collection — multi-face container |
74 72 75 65 | true | ttf | TrueType (Apple variant — "true" magic) |
| anything else | varies | unknown | Unknown 4-byte magic (the hex is echoed in the message) |
What appears in the output for each format
Fields are always present; the extras are computed only when the format and buffer length allow. Sizes are read from the wrapper header, not by decompressing.
| Format | Always present | Format-specific extras |
|---|---|---|
| TTF / OTF | format, magic, description, file_size_bytes, extension_matches_format | Tables — uint16 at offset 4 (the sfnt table count) |
| WOFF | same as above | Wrapped flavor (uint32 @4, e.g. 0x00010000) and Wrapped sfnt size (uint32 @16, shown in KB) — only when the file is ≥ 16 bytes |
| WOFF2 | same as above | Wrapped flavor (uint32 @4) and Decompressed size (uint32 @16, in KB) — only when the file is ≥ 16 bytes |
| TTC | same as above | none — the collection header is reported but individual faces are not enumerated here |
| unknown | same as above | none |
Cookbook
Realistic before/after scenarios. The JSON shown is the literal shape the tool downloads as {stem}.format.json. If you need to act on the result — convert, repackage, or strip tables — the cross-links point to the right sibling tool.
An OTF wearing a .ttf extension
ExampleThe classic mislabel: a CFF-flavoured OpenType font renamed to .ttf so a glob picked it up. extension_matches_format catches it.
Input: Brand-Regular.ttf (actually OpenType/CFF)
{
"filename": "Brand-Regular.ttf",
"file_size_bytes": 184320,
"format": "otf",
"magic": "0x4F54544F",
"description": "OpenType / CFF outline font (sfnt with PostScript glyphs).",
"extension_matches_format": false,
"Tables": 12
}
Fix: rename to Brand-Regular.otf, or convert for the web (see ttf-to-woff2).A genuine TrueType font
ExampleMagic 0x00010000, extension honest, table count looks healthy. Nothing to do.
Input: Inter-Regular.ttf
{
"filename": "Inter-Regular.ttf",
"file_size_bytes": 309876,
"format": "ttf",
"magic": "0x00010000",
"description": "TrueType outline font (sfnt with TrueType glyphs).",
"extension_matches_format": true,
"Tables": 18
}A WOFF2 with its wrapper header read
ExampleThe tool reads the WOFF2 header at offset 16 for the original decompressed size — without running the Brotli decoder.
Input: Inter.woff2
{
"filename": "Inter.woff2",
"file_size_bytes": 96420,
"format": "woff2",
"magic": "0x774F4632",
"description": "Web Open Font Format 2.0 — Brotli-compressed wrapper around an sfnt font.",
"extension_matches_format": true,
"Wrapped flavor": "0x00010000",
"Decompressed size": "312.4 KB"
}A TrueType Collection renamed to .ttf
ExampleTTC has its own magic (ttcf). It is reported as format ttc, so the .ttf extension does not match — most browsers cannot load a TTC.
Input: PingFang.ttf (actually a collection)
{
"filename": "PingFang.ttf",
"file_size_bytes": 24117248,
"format": "ttc",
"magic": "0x74746366",
"description": "TrueType Collection — multi-face container.",
"extension_matches_format": false
}
Note: extract a single face on the desktop (fonttools) before using on the web.An Apple 'true' font — still TTF
ExampleLegacy Mac fonts use the magic 'true' instead of 0x00010000. The tool folds it into ttf, so a .ttf extension matches and you don't get a false 'unknown'.
Input: Geneva.ttf
{
"filename": "Geneva.ttf",
"file_size_bytes": 51200,
"format": "ttf",
"magic": "0x74727565",
"description": "TrueType (Apple variant — \"true\" magic).",
"extension_matches_format": true,
"Tables": 14
}Edge cases and what actually happens
Every row below was probed against the live API. Some documented requirements (alphabetical axis order, numerical tuple order) are not actually enforced in practice — useful to know if you've been blaming the wrong thing for a 400.
File renamed to .bin or no extension
Rejected at uploadThe upload gate calls isSupportedFontFile, which checks only the extension against ttf/otf/woff/woff2. A font saved as mystery.bin is rejected with "File ... is not a supported font (TTF/OTF/WOFF/WOFF2)" before any bytes are inspected. Rename it to .ttf (the detection ignores the extension entirely) and re-upload — the magic bytes will then reveal the real format.
File larger than your tier limit
413-style blockDetection only needs the first 4 bytes, but the whole file is read into an ArrayBuffer before the magic is inspected, so the tier size cap still applies: 5 MB free, 50 MB Pro, 1 GB Developer. A 30 MB CJK TTF is blocked on the free tier with "exceeds the free tier per-job limit (5.0 MB)". This is a usage gate, not a detection limit.
Truncated file under 4 bytes
unknownIf the buffer is shorter than 4 bytes the detector returns format unknown with an empty magic and the message "Buffer is too short to identify." This is the signature of a download that died at byte one — re-fetch from upstream.
A ZIP, PDF, or image renamed to .woff2
unknownThe extension passes the upload gate, but the magic won't match any font value. A ZIP (50 4B 03 04) or PNG (89 50 4E 47) returns format unknown with its real magic echoed (e.g. 0x504B0304). Useful for spotting an asset that was zipped or screenshotted and mislabelled.
WOFF/WOFF2 file under 16 bytes
By designThe wrapper extras (Wrapped flavor, sizes) are only computed when the file is at least 16 bytes long. A truncated WOFF whose header was cut off still reports format: woff from the 4-byte magic, but the extra fields are simply omitted rather than reading past the end of the buffer.
Valid sfnt but corrupt past the header
Detected as validThis tool only reads the magic and a couple of header integers — it does not parse the glyph outlines or checksum the tables. A file with the correct TTF magic but a corrupt body still reports format: ttf. To catch deeper corruption, pair this with /font-tools/font-metadata-extractor (which actually opens the font) or /font-tools/font-fingerprinter for a hash comparison against a known-good copy.
Uppercase extension (.TTF, .WOFF2)
Handledextension_matches_format lower-cases the filename before comparing, and the upload filter lower-cases the extension too. Brand.TTF with TrueType magic correctly reports extension_matches_format: true.
EOT or SVG font dropped in
Not supportedEOT (.eot) and SVG fonts (.svg) fail the upload extension gate, so they never reach the detector. Even if forced through by renaming, EOT's identifier sits at offset 34 and SVG is XML — neither matches an sfnt magic, so both would read as unknown. These formats are effectively dead on the modern web; convert your real font instead.
Datafork (dfont) Mac font
unknown / rejectedOld Mac suitcase/dfont resource files store the sfnt in the resource fork, not at offset zero, so the magic at byte zero is not a font magic. They also fail the extension gate. Extract the sfnt on the desktop (fontforge) before bringing it to the web.
Frequently asked questions
Does the file get uploaded anywhere?
No. The file is read in your browser with the File API and the magic bytes are inspected locally. The result panel shows a "0 bytes uploaded" badge to make this explicit.
Why does it only accept .ttf, .otf, .woff, and .woff2 files?
The upload box filters by extension before reading any bytes. If your file has a different or missing extension, rename it to .ttf and re-upload — the format detection itself ignores the extension and reads the actual magic bytes.
It says my .ttf is actually OTF — is the file broken?
No. A CFF-flavoured OpenType font (magic OTTO) is a perfectly valid font; only the extension is wrong. Rename it to .otf, or if you are shipping to the web, convert it to WOFF2 with /font-tools/ttf-to-woff2 where the inner outline format no longer matters.
What does the Tables metric mean?
For raw TTF/OTF it is the sfnt table count read from the uint16 at offset 4 — the number of tables (cmap, glyf, head, name, etc.) in the font directory. A healthy font usually has roughly 9–20. A value of 0 or something absurd is a red flag.
How is the WOFF2 'Decompressed size' computed without decompressing?
The WOFF2 header stores the total uncompressed sfnt size as a uint32 at offset 16. The tool reads that integer directly. It never runs the Brotli decoder, so the number is the header's claim, not a verified decompression.
What is the 'Wrapped flavor' field?
Both WOFF and WOFF2 store the sfnt version of the font they wrap in a uint32 at offset 4. 0x00010000 means the wrapped font is TrueType-flavoured; 0x4F54544F (OTTO) means it wraps CFF/OpenType. It tells you the outline format inside the web wrapper.
Why is the Apple 'true' magic reported as TTF?
Apple's early TrueType files use the magic true (0x74727565) instead of 0x00010000. They are functionally TrueType, so the tool folds them into the ttf format rather than reporting a confusing unknown.
Can it identify the individual faces inside a TTC?
No. It reports format: ttc from the ttcf magic but does not enumerate the contained faces. Most browsers cannot load a TTC at all — split out a single face on the desktop with fonttools before web use.
What does 'unknown' mean in the result?
The first 4 bytes did not match any font magic. The message echoes the actual hex (e.g. 0x504B0304 for a ZIP), which usually identifies what the file really is. Common causes: a ZIP, image, or HTML error page saved with a font extension, or a truncated download.
Does it validate that the font actually works?
No — it is a header check, not a full parse. A file with correct magic but a corrupt body still reads as valid here. For a real structural check, open it with /font-tools/font-metadata-extractor or compare a hash with /font-tools/font-fingerprinter.
What format is the downloaded report?
A JSON file named {stem}.format.json containing filename, file_size_bytes, format, magic, description, extension_matches_format, and any format-specific extras (Tables, Wrapped flavor, sizes).
I need to fix a mislabelled font — what next?
If only the extension is wrong, rename it to match the detected format. If you need to ship it to the web, convert with /font-tools/ttf-to-woff2 or /font-tools/woff2-to-ttf. To embed it inline, use /font-tools/font-to-base64.
Privacy first
Every JAD Font tool runs entirely in your browser using opentype.js and the wawoff2 WASM Brotli encoder. Your fonts never leave your device — verified by zero outbound network requests during processing.