How to Use Claude Code Hooks as SEO/GEO Quality Gates

Use Claude Code hooks to run deterministic SEO/GEO checks for builds, metadata, robots, schema, analytics, and risky bulk edits.

What you will build

This tutorial shows how to use Claude Code hooks as practical SEO/GEO quality gates. The goal is not to make Claude “more careful” in a vague way. The goal is to run deterministic checks when Claude edits files that can damage search visibility: metadata helpers, schema, robots rules, sitemap generation, canonical tags, analytics, and content templates.

You will build:

.claude/
settings.local.json
scripts/
seo-geo-hook-guard.mjs
seo-geo-launch-gate.mjs
seo-geo/
qa/
hook-test-plan.md
hook-reports/

Start with warning hooks. After you trust the checks, turn only the high-confidence ones into blocking hooks.

Step 1: create a small hook guard script

Create the folders:

mkdir -p .claude scripts seo-geo/qa/hook-reports

Create a hook script that inspects the current git diff and flags high-risk SEO/GEO files:

cat > scripts/seo-geo-hook-guard.mjs <<'EOF2'
#!/usr/bin/env node
import { execSync } from 'node:child_process';
import { mkdirSync, writeFileSync } from 'node:fs';

mkdirSync('seo-geo/qa/hook-reports', { recursive: true });

function sh(cmd) {
try { return execSync(cmd, { encoding: 'utf8' }).trim(); }
catch { return ''; }
}

const changed = sh('git diff --name-only HEAD').split('
').filter(Boolean);
const riskyPatterns = [
/robots\.txt$/,
/sitemap/i,
/canonical/i,
/noindex/i,
/schema|json-ld|structured-data/i,
/middleware\.(js|ts)$/,
/analytics|gtm|ga4/i,
/seo\.(js|ts|tsx|mjs)$/,
/metadata|meta-tags/i,
];

const risky = changed.filter(file => riskyPatterns.some(pattern => pattern.test(file)));
const report = [
'# SEO/GEO Hook Guard',
'',
`Changed files: ${changed.length}`,
'',
risky.length ? '## Risky files' : '## Risky files
None detected.',
...risky.map(file => `- ${file}`),
'',
'## Required reviewer action',
risky.length
? 'Review crawl/indexing/schema/analytics impact before continuing.'
: 'No high-risk SEO/GEO file pattern detected.',
].join('
');

writeFileSync('seo-geo/qa/hook-reports/latest-guard.md', report);

if (risky.length) {
console.error(report);
// Exit 0 for warning mode. Change to exit 2 only after the team trusts the rule.
process.exit(0);
}
EOF2
chmod +x scripts/seo-geo-hook-guard.mjs

Run it once before wiring it into Claude Code:

node scripts/seo-geo-hook-guard.mjs
cat seo-geo/qa/hook-reports/latest-guard.md

If your repo is not Git-based, change the script to read a list of changed files from your build system or PR export.

Step 2: create a launch gate script

Hooks should be fast. Put heavier checks in a launch gate that Claude can run before final response or before a PR.

cat > scripts/seo-geo-launch-gate.mjs <<'EOF2'
#!/usr/bin/env node
import { execSync } from 'node:child_process';

const commands = [
['git status', 'git status --short'],
['changed files', 'git diff --name-only HEAD'],
];

let failed = false;
for (const [label, cmd] of commands) {
try {
const out = execSync(cmd, { encoding: 'utf8' }).trim();
console.log(`
## ${label}
${out || '(no output)'}`);
} catch (err) {
failed = true;
console.error(`
## ${label}
FAILED: ${err.message}`);
}
}

console.log('
## Manual SEO/GEO review still required');
console.log('- Check title/meta/canonical changes');
console.log('- Check schema and unsupported claims');
console.log('- Check robots, sitemap, redirects, noindex, analytics');
console.log('- Check internal links and answer extraction blocks');

process.exit(failed ? 1 : 0);
EOF2
chmod +x scripts/seo-geo-launch-gate.mjs

Add your real build command later, for example npm run build, npm run lint, or a site-specific crawler.

Step 3: ask Claude Code to propose the hook config

Do not paste a hook config blindly. Ask Claude Code to inspect your repo and produce the safest version for your current Claude Code installation:

Inspect this repository and help me configure Claude Code hooks for SEO/GEO quality gates.

Use these scripts:
- scripts/seo-geo-hook-guard.mjs
- scripts/seo-geo-launch-gate.mjs

Requirements:
- Start in warning mode, not blocking mode.
- Run the guard after file edits that may touch SEO/GEO files.
- Do not auto-approve edits.
- Do not publish, deploy, submit URLs, or change credentials.
- Put the proposed configuration in `.claude/settings.local.json` or the current Claude Code settings location recommended by the docs.
- Explain how I can test the hook with one harmless metadata edit.

Do not edit live content until I approve the settings.

Why ask Claude to generate the exact config? Claude Code hook syntax can evolve. Let Claude use the installed version and current docs, while your scripts and safety policy remain stable.

Step 4: use this starter settings pattern

If your Claude Code version supports JSON hook settings, your local settings will look similar to this:

{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "node scripts/seo-geo-hook-guard.mjs"
}
]
}
]
}
}

Treat this as a starter pattern, not a universal copy-paste guarantee. After adding it, restart Claude Code or reload the session if your environment requires it.

Step 5: test the hook safely

Create a harmless branch:

git checkout -b test/seo-geo-hooks

Ask Claude Code:

Make a harmless test change to a temporary markdown file under `seo-geo/qa/`. Then confirm whether the SEO/GEO hook ran and show me `seo-geo/qa/hook-reports/latest-guard.md`.

Then test a risky filename without changing production logic:

mkdir -p seo-geo/qa/fake-risk
cat > seo-geo/qa/fake-risk/test-sitemap-note.md <<'EOF2'
This is a test note. It is not the real sitemap.
EOF2

Ask Claude:

Run the hook guard and explain whether it warns on this fake-risk file. Do not edit production sitemap, robots, canonical, schema, or analytics files.

Step 6: decide what should warn vs block

Use this table before making any hook blocking:

Gate

Start mode

When to block later

Build failure

Warn

When the build command is stable

Robots/noindex changed

Warn

When the file matcher is precise

Canonical helper changed

Warn

Usually keep human approval

Schema validation failed

Warn

Block if validator has low false positives

Analytics touched

Warn

Keep human approval

Many content files changed

Warn

Block only for unapproved bulk edits

A beginner-safe hook warns, writes a report, and forces review. A mature hook can block only when the failure is mechanical and low ambiguity.

Step 7: add the rule to CLAUDE.md

Hooks run commands. CLAUDE.md explains the policy behind them. Add a short section:

## SEO/GEO quality gates

Before final response on SEO/GEO tasks:
- summarize changed files
- run the available validation command
- read `seo-geo/qa/hook-reports/latest-guard.md` if it exists
- flag any robots, sitemap, canonical, noindex, schema, metadata, analytics, or routing change
- do not publish, deploy, or submit URLs without explicit approval

This keeps Claude's reasoning aligned with the hook output.

What good hook output looks like

A useful warning is specific:

Risky files:
- src/lib/seo.ts
- src/components/JsonLd.tsx

Required reviewer action:
Review canonical generation and JSON-LD output before continuing. Run build and inspect one rendered page.

A weak warning is vague:

SEO issue found. Be careful.

If the warning does not name files and review steps, improve the script before relying on it.

FAQ

Should hooks replace human review?

No. Hooks catch repeatable mechanical risks. Humans still review claims, positioning, legal language, competitor comparisons, redirects, analytics interpretation, and release timing.

Should I make hooks blocking on day one?

No. Start with warning mode. After several safe runs, block only the checks with low false-positive risk.

Where should hook scripts live?

Keep shared scripts in the repo under scripts/. Keep personal hook settings in local Claude Code settings unless the whole team has agreed to the same behavior.

Claude Code SEO/GEO learning path

This article is part of the Claude Code SEO/GEO operator series. If you are building the workflow from scratch, follow the sequence:

  1. How to Use Claude Code for SEO Automation
  2. How to Build a Claude Code SEO/GEO Workflow Cockpit
  3. How to Use CLAUDE.md and Memory for SEO/GEO Workflows
  4. How to Refresh SEO Pages with the Claude Code VS Code Extension
  5. Best GEO Claude Code Skills in 2026
  6. How to Use Claude Code Subagents for GEO Research
  7. How to Use Claude Code Hooks as SEO/GEO Quality Gates
  8. How to Connect Claude Code to SEO Data with MCP
  9. How to Use Claude Code GitHub Actions for SEO/GEO Reviews
  10. How to Run Daily SEO/GEO Monitoring in Claude Code

Sources and notes

Author: Julian Mercer, 14-Year Technical SEO Practitioner at Auspia. Julian writes about crawlability, schema, rendering, and technical foundations for AI-readable content.

Explore this topic

Keep following the same growth thread