All guides · SEO

Doctype and Character Encoding: Two Lines Every Page Needs

Two small declarations at the very top of a page decide how browsers interpret everything after them: the doctype, which selects the rendering mode, and the character encoding, which decides how bytes turn into letters. Both are easy to get right and surprisingly annoying to debug when wrong.

Why the doctype matters

<!doctype html> tells the browser to render in standards mode. Without it, or with an old HTML 4 or XHTML doctype that lacks a URL, browsers fall back to quirks mode, which emulates 1990s browser bugs: box sizes are calculated differently, table cells inherit font sizes oddly, and some CSS behaves unexpectedly. The page may look fine in one browser and broken in another.

Why the character encoding matters

If the browser guesses the encoding wrong, accented and non-Latin characters turn into garbage (“ç” instead of “ç”). Search engines may index that garbage too. UTF-8 covers every language and is what the web standard recommends, but it still has to be declared.

What we check

Doctype (seo.doctype): the first thing in the document, after optional whitespace and comments.

Result When
Passed <!doctype html> (any capitalization)
Needs attention an older doctype, such as HTML 4.01 or XHTML 1.0
Failed no doctype

Charset (seo.charset): the charset in the Content-Type header, else <meta charset>, else <meta http-equiv="Content-Type">.

Result When
Passed UTF-8 is declared
Needs attention another encoding, such as ISO-8859-9 or Windows-1254
Failed no encoding is declared anywhere

How to fix

Start every page like this:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <!-- everything else -->
  </head>
</html>
  • Put nothing before the doctype except whitespace. A byte-order mark is fine; stray output from a server-side script is not.
  • Put <meta charset="utf-8"> first in <head>: the browser only looks within the first 1,024 bytes.
  • Also send the encoding in the HTTP header: Content-Type: text/html; charset=utf-8. Most frameworks do this already; in Nginx it’s charset utf-8;.

Moving an old site to UTF-8

If your pages are stored in a legacy encoding, declaring UTF-8 isn’t enough: the files or database content must be converted too, otherwise every special character breaks. Convert the data first (for MySQL, to utf8mb4), then change the declaration, and test pages with non-ASCII text.

Further reading: MDN: Quirks mode and W3C: Declaring character encodings in HTML.

Last updated October 25, 2026