SEOCode
Framework-aware technical SEO review for your codebase. A zero-config CLI that catches deploy-blocking SEO regressions - accidental noindex, dynamic metadata that never renders, broken JSON-LD, missing titles - before you push, right in your terminal.
It understands your framework. Titles and descriptions set through the Next.js Metadata API / generateMetadata, Remix meta(), or Astro layouts are read the way the framework actually renders them - so you don't get false "missing title" noise on correct code.
npx @qobi/seocode check
Install
npx @qobi/seocode check
npm i -g @qobi/seocode
seocode check
Requires Node.js ≥ 20.
Commands
seocode check
seocode check src/ app/
seocode check --fix
seocode check --staged
seocode check --json
seocode init
seocode init --hook
Exit code is 1 when deploy-blocking (critical) issues are found, 0 otherwise - so it drops straight into a pre-commit hook or a CI step.
What it checks
Critical, deploy-blocking issues are surfaced first; lower-severity suggestions stay out of the way.
- Critical - accidental
noindex, missing <title>, broken/invalid JSON-LD, unrendered dynamic metadata, missing <h1>, duplicate <h1>, images missing alt
- Warnings - title/description length, missing Open Graph / Twitter tags, broken heading hierarchy, missing canonical, vague link text
- Info - lazy-loading hints, AVIF format, LCP preload, structured-data recommendations, and more
…across HTML, JS, JSX, TSX, Vue, Svelte, and Astro files. Framework shells, utility files, and component libraries are scoped automatically.
--fix
--fix applies only the transforms SEOCode can make with certainty - never a guess. Today that covers:
- adding
loading="lazy" to images that lack it
- adding
rel="noopener noreferrer" to external links that have no rel
Everything else is reported with the exact tag to add and the line to change.
Framework awareness
SEOCode reads framework metadata instead of just literal tags, so it won't false-flag idiomatic code:
- Next.js -
metadata / generateMetadata, App Router layouts & pages, next/og image routes, JSON-LD via dangerouslySetInnerHTML
- Remix -
meta() exports
- Astro - layouts with dynamic
<title>{title}</title>, pages that delegate their <head> to a layout
- Plain HTML / Vue / Svelte - the
<head> is checked directly
The head is composed by the framework across layouts, pages, and merged metadata - so on framework files, SEOCode reports only what it can prove, and stays silent where it can't. Real signal (like an accidental noindex) still comes through.
Configuration
Drop a .seocode.json in your repo root (all fields optional):
{
"exclude": ["emails/**", "public/legacy/**", "**/*.stories.tsx"],
"rules": {
"title-too-short": "off",
"missing-canonical": "info"
}
}
exclude - glob patterns to skip (* within a segment, ** across segments, trailing / for a whole directory)
rules - set a rule to "off" (or false) to disable it, or to "critical" / "warning" / "info" to change its severity
A missing or malformed config falls back to defaults - a typo can't break your reviews.
Pre-commit hook
seocode init --hook
…or with husky:
echo "npx @qobi/seocode check --staged" > .husky/pre-commit
SEOCode as a GitHub App
Prefer automated reviews on every pull request instead of (or alongside) the CLI? The hosted SEOCode GitHub App posts a critical-first review comment on every PR, offers one-click fixes, sets a merge status check, and judges each PR on what it changed (legacy debt never blocks your merge). See seocode.io.
License
MIT © SEOCode