---
title: "Keep the HTML valid · Agent Wranglers"
url: https://agentwranglers.se/playbook/website/html-basics/valid-html
updated: 2026-10-20
licence: "All rights reserved"
---

# Keep the HTML valid

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Recommended
- Chapter: [HTML basics](https://agentwranglers.se/playbook/website/html-basics)
- Rule: Make every built page pass an HTML validator with zero errors, so every browser, crawler and screen reader reads the same structure.
- How: Run a validator over the build output in CI, for example the Nu Html Checker (`vnu`) or html-validate. Fail the build on any error. Fix the template that made the error, not the single page. Allow a warning only by turning off that one check by name in the validator's config.
- Check: The validator reports 0 errors for every HTML file in the build, and the build fails when you add a `<div>` inside a `<p>`.

Example:

```js
import { HtmlValidate } from 'html-validate';
import { readFileSync } from 'node:fs';
const validator = new HtmlValidate({ extends: ['html-validate:recommended'] });
const report = await validator.validateString(readFileSync('dist/pricing.html', 'utf8'));
if (!report.valid) {
  for (const m of report.results.flatMap(r => r.messages)) console.error(`${m.line}:${m.column} ${m.message}`);
  process.exit(1);
}
```

```python
import json, sys, urllib.request
# a local Nu Html Checker, started with: java -cp vnu.jar nu.validator.servlet.Main 8888
html = open("dist/pricing.html", "rb").read()
request = urllib.request.Request("http://localhost:8888/?out=json", data=html,
                                 headers={"Content-Type": "text/html; charset=utf-8"})
errors = [m for m in json.load(urllib.request.urlopen(request))["messages"] if m["type"] == "error"]
for m in errors:
    print(f"{m.get('lastLine')}: {m['message']}")
sys.exit(1 if errors else 0)
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers website playbook: https://agentwranglers.se/playbook/website/html-basics/valid-html`.

- Previous: [Fit the page to the phone](https://agentwranglers.se/playbook/website/html-basics/meta-viewport)
- Next: [Give every page its own title](https://agentwranglers.se/playbook/website/html-basics/title)
- [HTML basics](https://agentwranglers.se/playbook/website/html-basics)
