Doctype must be declared first: what it means and the fix
A page with no doctype, an old one, or a doctype that is not the first thing in the document. squirrel reads the raw response.
What the doctype does
<!DOCTYPE html> is the first line of an HTML document. It has one job: it puts the browser in standards mode. Without it, or with something the browser does not recognise, the page renders in quirks mode, which emulates rendering bugs from browsers of the late 1990s. Box sizing, table cell heights, and inline element layout all change.
The parser tolerates whitespace and comments before the doctype, so those do not by themselves cause quirks mode. Text does: a stray character or a template fragment emitted before the declaration makes the parser treat the document as having no doctype. This rule is stricter than the parser and reports anything in front of the declaration except a byte order mark and an XML declaration.
What squirrel checks
The rule runs on every crawled page against the raw response body, before parsing. It emits one check named doctype:
- Skipped with the message
No HTML content availableand the reasonEmpty responsewhen the body is empty. - Passing with the message
Valid HTML5 doctype foundand the value<!DOCTYPE html>. The details note a byte order mark or an XML declaration when either was present. - Warning with the message
HTML5 doctype not at document startand the expectation<!DOCTYPE html> at very startwhen the doctype is correct but something precedes it. - Warning with the message
Non-HTML5 doctype found: XHTML,Non-HTML5 doctype found: HTML4orNon-HTML5 doctype found: legacy, with the declaration itself as the value, truncated to 50 characters followed by an ellipsis when it is longer. - Failing with the message
Missing doctype declarationand the expectation<!DOCTYPE html>when there is no doctype at all.
A byte order mark is stripped before the check, and an XML declaration matching <?xml ... ?> at the very start is skipped over, so neither on its own causes a failure. The doctype match is case-insensitive and allows leading whitespace, so <!doctype html> and a leading newline both pass. A comment before the doctype does not.
How to fix it
<!DOCTYPE html>
<html lang="en">Put it on the first line of the document with nothing before it. In a templating system the usual cause is a partial or a PHP block that emits a newline or a comment before the layout starts.
The common false positive is a comment before the doctype, which HTML parsers accept and this rule reports. Anything other than a byte order mark, whitespace or an XML declaration in front of the declaration is reported.
| Rule ID | core/doctype |
| Category | Core SEO |
| Scope | Per-page |
| Severity | warning |
| Weight | 5/10 |
Enable / disable
Disable this rule
[rules]
disable = ["core/doctype"]Disable all Core SEO rules
[rules]
disable = ["core/*"]Enable only this rule
[rules]
enable = ["core/doctype"]enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.
Related rules
- core/charset: the other declaration that has to come early in the document.
- content/broken-html: other structural markup faults in the same response.
- content/mime-type: the content type the server declared for the document.
- content/unrendered-markup: template output that reached the page unprocessed.
Core SEO findings ship in every audit next to the performance, security and agent experience rules. See Fix SEO issues with AI for how an agent works through a report.
References
Check your site
Run squirrel audit https://example.com and open the Core SEO section of the report. Each page reports the doctype it found, or that it found none. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.