---
title: "CLI"
description: "Audit and migrate unhead usage with the unhead CLI: source lint, prerendered HTML validation, and live URL inspection."
canonical_url: "https://unhead.unjs.io/docs/typescript/head/guides/tooling/cli"
last_updated: "2026-08-11T00:38:09.652Z"
---

`@unhead/cli` provides commands for source linting, migrations, rendered HTML validation, and live URL validation. Run the commands locally or in CI.

## Install

```bash
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.

```bash
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/**/*.vue` that do not call `useHead` or `useSeoMeta`, either directly or through a project composable. The call-graph analysis treats wrappers such as `useDefaultMeta()` → `useHead()` as coverage.
- **prefer-use-seo-meta** (`warning`, autofixable): finds `useHead` calls that only set `title`, `description`, or `meta`. The `migrate` command rewrites them to the typed `useSeoMeta` shape.
- **Title consistency**: collects static `title` and `titleTemplate` values from Unhead calls, `defineNuxtConfig`, and identified project composables. It reports mixed separators, repeated suffixes that belong in `titleTemplate`, 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.

```bash
unhead migrate
unhead migrate --dry-run       # report fixable count without writing
```

### `unhead validate-html [globs...]`

Runs the runtime [`ValidatePlugin`](/docs/typescript/head/guides/tooling/validate-plugin) 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.

```bash
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.

```bash
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:

<table>
<thead>
  <tr>
    <th>
      Rule class
    </th>
    
    <th>
      <code>
        audit
      </code>
      
       / <code>
        migrate
      </code>
      
       (source)
    </th>
    
    <th>
      <code>
        validate-html
      </code>
      
       / <code>
        validate-url
      </code>
      
       (rendered HTML)
    </th>
    
    <th>
      Runtime <code>
        ValidatePlugin
      </code>
      
       (live app)
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Typos in meta <code>
        name
      </code>
      
       / <code>
        property
      </code>
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Deprecated v2 props
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      —
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Numeric <code>
        tagPriority
      </code>
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Preload missing <code>
        as
      </code>
      
       / font <code>
        crossorigin
      </code>
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Twitter handle missing <code>
        @
      </code>
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Robots <code>
        index/noindex
      </code>
      
       conflict
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Non-absolute canonical / OG URLs
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Empty meta content / HTML in title
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Canonical vs <code>
        og:url
      </code>
      
       mismatch
    </td>
    
    <td>
      —
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        og:image
      </code>
      
       missing dimensions
    </td>
    
    <td>
      —
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Missing description / title
    </td>
    
    <td>
      —
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Missing OG title / description
    </td>
    
    <td>
      —
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Charset not within first N tags (SSR)
    </td>
    
    <td>
      —
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Meta tag past 1MB crawler limit
    </td>
    
    <td>
      —
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Too many preloads / preconnects / <code>
        fetchpriority="high"
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      Inline script / style size budget
    </td>
    
    <td>
      —
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      ✓
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        prefer-use-seo-meta
      </code>
      
       (meta-only <code>
        useHead
      </code>
      
       → <code>
        useSeoMeta
      </code>
      
      )
    </td>
    
    <td>
      ✓ (autofix)
    </td>
    
    <td>
      —
    </td>
    
    <td>
      —
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        page-missing-head
      </code>
      
       (no <code>
        useHead
      </code>
      
      /composable in <code>
        pages/**
      </code>
      
      )
    </td>
    
    <td>
      ✓ (info, cross-file fixpoint)
    </td>
    
    <td>
      —
    </td>
    
    <td>
      —
    </td>
  </tr>
  
  <tr>
    <td>
      Title separator / suffix consistency across pages
    </td>
    
    <td>
      ✓ (cross-file)
    </td>
    
    <td>
      —
    </td>
    
    <td>
      —
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parse-error
      </code>
      
       (script block oxc couldn't parse)
    </td>
    
    <td>
      ✓
    </td>
    
    <td>
      —
    </td>
    
    <td>
      —
    </td>
  </tr>
</tbody>
</table>

## 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.
