@unhead/cli provides commands for source linting, migrations, rendered HTML validation, and live URL validation. Run the commands locally or in CI.
Install
pnpm add -D @unhead/cli
The binary is registered as unhead (run unhead --help to discover commands).
Commands
unhead audit [globs...]
Lints Unhead usage in source files. The parser reads Vue and Svelte SFCs as well as the app.head block in nuxt.config.ts; ESLint is not required.
unhead audit # default: all .{js,ts,vue,svelte,...}
unhead audit src/**/*.ts # narrowed glob
Exits with code 1 when any rule fires at error severity. Warnings and info findings don't fail CI by themselves so you can adopt the rules incrementally.
The output includes a green ✓ line for each scanned file that uses useHead or useSeoMeta and has no diagnostics. A parse-error warning identifies any script block that oxc-parser could not read.
Project insights
Beyond per-file lints, audit runs cross-file checks:
page-missing-head(info): flags files under**/pages/**/*.vuethat do not calluseHeadoruseSeoMeta, either directly or through a project composable. The call-graph analysis treats wrappers such asuseDefaultMeta()→useHead()as coverage.prefer-use-seo-meta(warning, autofixable): findsuseHeadcalls that only settitle,description, ormeta. Themigratecommand rewrites them to the typeduseSeoMetashape.- Title consistency: collects static
titleandtitleTemplatevalues from Unhead calls,defineNuxtConfig, and identified project composables. It reports mixed separators, repeated suffixes that belong intitleTemplate, and titles that duplicate an existing template suffix.
unhead migrate [globs...]
Applies every autofixable rule. On a v2 codebase, this renames deprecated properties, wraps tag literals in defineLink or defineScript, converts meta-only useHead calls to useSeoMeta, and applies the other enabled fixes.
unhead migrate
unhead migrate --dry-run # report fixable count without writing
unhead validate-html [globs...]
Runs the runtime ValidatePlugin over rendered HTML files. This covers checks that depend on the final tag set, such as canonical and og:url mismatches, missing og:image dimensions, charset position, and meta tags beyond the 1 MB crawler limit.
unhead validate-html '.output/public/**/*.html'
unhead validate-html dist/index.html --json
Exits with code 1 on any rule with warn severity (the runtime plugin only emits warn / info, not error).
unhead validate-url <url>
Fetches a live URL and runs the same validation against its response. Use it to check a production or staging page.
unhead validate-url https://example.com
unhead validate-url https://example.com --json
unhead validate-url https://example.com --user-agent 'Twitterbot/1.0'
The default user agent is facebookexternalhit/1.1 (+https://unhead.unjs.io), so social-crawler-aware rules such as meta-beyond-1mb run against the response.
What runs where
Validation runs at the source, rendered HTML, and live application layers:
| Rule class | audit / migrate (source) | validate-html / validate-url (rendered HTML) | Runtime ValidatePlugin (live app) |
|---|---|---|---|
Typos in meta name / property | ✓ | ✓ | ✓ |
| Deprecated v2 props | ✓ | — | ✓ |
Numeric tagPriority | ✓ | ✓ | ✓ |
Preload missing as / font crossorigin | ✓ | ✓ | ✓ |
Twitter handle missing @ | ✓ | ✓ | ✓ |
Robots index/noindex conflict | ✓ | ✓ | ✓ |
| Non-absolute canonical / OG URLs | ✓ | ✓ | ✓ |
| Empty meta content / HTML in title | ✓ | ✓ | ✓ |
Canonical vs og:url mismatch | — | ✓ | ✓ |
og:image missing dimensions | — | ✓ | ✓ |
| Missing description / title | — | ✓ | ✓ |
| Missing OG title / description | — | ✓ | ✓ |
| Charset not within first N tags (SSR) | — | ✓ | ✓ |
| Meta tag past 1MB crawler limit | — | ✓ | ✓ |
Too many preloads / preconnects / fetchpriority="high" | — | ✓ | ✓ |
| Inline script / style size budget | — | ✓ | ✓ |
prefer-use-seo-meta (meta-only useHead → useSeoMeta) | ✓ (autofix) | — | — |
page-missing-head (no useHead/composable in pages/**) | ✓ (info, cross-file fixpoint) | — | — |
| Title separator / suffix consistency across pages | ✓ (cross-file) | — | — |
parse-error (script block oxc couldn't parse) | ✓ | — | — |
DevTools integration
When the Unhead Vite plugin is active, the devtools /audit tab provides Run audit and Apply migrate buttons. The panel loads @unhead/cli, renders its results, and links each message to its source location.