ByteScope

HTML file format

HyperText Markup Language, the structure format of web pages.

MIME type
text/html
Extensions
.html, .htm
Category
Text & markup

Magic-number signature

Plain text starting with '<!doctype html' or '<html'.

About the HTML format

HTML is defined by its parser rather than by a grammar. The standard does not describe a set of legal documents and reject everything else; it describes, byte by byte, what a browser must do with any input at all, including input that is malformed, truncated or not HTML in the first place. That is why there is no such thing as an invalid HTML file in practice, why two different browsers build identical trees out of identically broken markup, and why the format has no header, no length, no version and no trailer that a tool could check before it starts parsing.

Header layout, byte by byte

OffsetLengthFieldMeaning
03UTF-8 byte-order markEF BB BF. When it is present the browser stops looking: the standard says a mark makes the encoding certain, which overrides both the charset in the Content-Type header and any meta element inside the document. It is one of the very few things in HTML that is decided at a fixed byte offset.
015DOCTYPE3C 21 44 4F 43 54 59 50 45 20 68 74 6D 6C 3E, the fifteen bytes of the modern doctype. Case does not matter, and the browser sniffing rules only require the first fourteen of them - the letters up to and including HTML - followed by a space or a closing angle bracket.
05html start tag3C 68 74 6D 6C, plus a space or a closing bracket after it. Perfectly legal at offset 0, because the doctype is not mandatory; a document without one is parsed in quirks mode, where a set of decades-old layout behaviours comes back and box sizing stops matching what was designed.
0variableAny other recognised openerThe sniffing table also matches HEAD, SCRIPT, IFRAME, H1, DIV, FONT, TABLE, A, STYLE, TITLE, B, BODY, BR, P and a comment opener, each after optional leading whitespace and each needing a space or a closing bracket after the name. A fragment saved out of a page usually matches one of these rather than either of the first two rows.
01024Encoding prescan windowNot a field but a boundary worth carrying in your head: browsers are told to look for a meta charset only within the first 1024 bytes. A charset declaration pushed past that by a long licence comment or an inlined script is simply not seen, and the page falls back to guessing.

Telling it apart from its neighbours

Easily confused withHow to tell
XMLA document that opens 3C 3F 78 6D is XML, and XHTML delivered as application/xhtml+xml goes to the XML parser, where one unclosed tag is fatal. The identical bytes delivered as text/html are recovered silently and render fine. The difference is not in the file at all; it is in the header the server sent, which is why the same document can behave two completely different ways from one directory.
SVGA standalone .svg is XML with an svg root element and is parsed by the XML parser. The same markup written inline inside an HTML document is parsed by the HTML parser under foreign-content rules, where tag names are case-fixed and self-closing syntax is handled specially. Byte for byte the elements can be identical; which parser sees them decides what they mean.
Plain text/MarkdownThere is no reliable byte test. If none of the tag patterns match, the sniffing algorithm falls back to plain text so long as the leading bytes contain no binary data, so a README, a template that opens with a variable, or an email body is indistinguishable from prose at the byte level. Extension and Content-Type are all you have, and both are assertions rather than evidence.
Failed downloadsThe most useful thing to know about HTML in a hex viewer is that it is what a broken download usually turns out to be. A ZIP that will not open, an image that will not load, a PDF a reader rejects: open it and find 3C 21 44 4F 43 54 59 50 45 at offset 0 and you are looking at a login page, a rate-limit notice or a 404 saved under the name of the file you wanted.

How these files break

  • Something in front of the doctype. Whitespace and comments are ignored and cost nothing, but any actual text ahead of it - a warning emitted by a server-side language, a stray line from an included file - drops the document into quirks mode. The page still renders, because it always renders, with box sizing and inherited font sizes subtly different from the layout that was tested.
  • No encoding declared anywhere. With no mark, no charset on the Content-Type and no meta within the first 1024 bytes, the browser guesses, and the guess depends on the reader's locale. The page is correct in the office it was built in and full of mojibake somewhere else, from bytes that never changed at any point.
  • Truncation. A partial download has no tell at all: the parser closes every element still open when the input ends and renders what it has. A page missing its footer looks like a template bug rather than a file that stopped early, and the only way to be sure is to compare the byte count against the Content-Length that was advertised.
  • Double escaping. Text escaped twice on its way through a template renders as visible tag syntax instead of formatting, and the file is completely well-formed while it does. The bytes to search for are 26 61 6D 70 3B - an escaped ampersand - sitting in front of an escaped angle bracket.
  • A saved page that is not the page. Save-as rewrites URLs, relocates or inlines resources and injects a comment recording where the file came from, so the bytes on disk are not the bytes the server sent. Diffing a saved page against a fresh fetch mostly reports the browser's own edits, which makes saved copies close to useless as evidence.

Where the format stands today

HTML is not going to be replaced, so the interesting question about it is where it turns up outside a browser. Email is the largest case, and it runs on a fossil subset - table layouts and inline styles - because mail clients never adopted the parsing standard and never will. Electron and its imitators put a browser engine inside desktop applications, which means a large share of the software people use every day is HTML at the surface. Static site generators, documentation tools and design systems all emit it as a build product rather than as something anybody writes by hand any more. And as a file on disk it is most often met by accident: HTML is what you find when you open something that was supposed to be a different format and the server sent an error page instead, which makes recognising its first fifteen bytes one of the more useful things a person working with files can memorise.

Open HTML files on this site

Every one of these runs in your browser — the file never leaves your machine.

Related formats

Formats that are easy to confuse with HTML — compare their leading bytes.

FormatFirst bytesExtension
XMLno fixed signature.xml
JSONno fixed signature.json
SVGno fixed signature.svg

Frequently asked questions

What is a magic number in a file?

The first few bytes of a file, which identify its format regardless of what the name says. A PNG always starts with 89 50 4E 47; a ZIP with 50 4B 03 04. Operating systems, browsers and the file command all read these bytes rather than trusting the extension, which is why renaming a file does not change what it actually is.

How do I check a file's magic number myself?

On macOS or Linux, xxd -l 16 yourfile prints the first 16 bytes; on Windows, Format-Hex -Path yourfile -Count 16 in PowerShell. Or drop the file into the File Type Identifier on this site, which reads the bytes locally and names the format for you — nothing is uploaded.

Why do two formats share the same magic number?

Because one is built on the other. Every docx, xlsx, pptx, apk, jar and epub begins with the ZIP signature, since all of them are ZIP archives underneath; telling them apart means looking at the entries inside. Java class files and macOS universal binaries both start with CA FE BA BE and are distinguished by the field that follows.

Can a file have no magic number at all?

Yes. Text-based formats — XML, HTML, JSON, SVG, CSV — have no fixed byte signature, so they are recognized structurally instead: a leading <?xml declaration, a <svg element, or a { followed by a quoted key. That detection is a good guess rather than a certainty, which is why this reference marks those formats as probe-detected.

Does a matching magic number mean the file is safe?

No. It tells you what the format is, not whether the contents are harmless — a genuine PDF or docx can still carry a malicious payload. Identifying the true type is a useful first check, especially when the extension disagrees with the bytes, but it is not a malware scan.

Have a file that might be in the HTML format? Identify it with the File Type Identifier — it reads the magic number locally, nothing is uploaded. Or browse all formats.