SEO and AI-answer checks
Deterministic checks for search engines and AI answers before you publish, on every plan.
Every post is checked for the things search engines and AI answer engines look for: titles and descriptions, heading structure, links, duplicates, an opening that can stand as an answer, sourced numbers, and passages short enough to quote. There are 31 rules, all plain code, and they run on every plan, Try free included. vibecms runs no AI model on your post. The judgment calls a rule can’t make (does the opening actually answer the title? which claims need a source?) are for your own agent, guided by the vibecms-seo skill.
Findings have a stable code, a severity of error, warn, or info, the field they attach to, a plain-language message, and a fix hint. They come back sorted by severity.
Where they show
posts.previewreturns the findings in itsseofield next towarnings, so the existing preview flow sees them for free.posts.seo_check({postId, focusKeyword?})checks a saved post’s current tip and returns{versionNumber, findings}. REST mirrors it atGET /api/v1/posts/{postId}/seo?focusKeyword=.- The editor’s SEO section lists findings grouped by severity, with a focus keyword field saved per browser and one-click jumps to the SEO fields a finding attaches to.
- The publish dialog lists open
errorfindings. It informs, it does not block.
Previewing unsaved Markdown (contentMarkdown instead of postId) skips the checks that attach to saved metadata — title, description, slug, duplicates, canonical — but still runs site context like site-not-indexable alongside the body checks.
Finding codes
26 rules for search engines (including the five focus keyword rules) and 5 for AI answers.
Title, description, slug
| Code | Severity | Meaning and fix |
|---|---|---|
title-length |
warn | Effective SEO title is outside 15-60 characters — write a more descriptive title or shorten it. |
description-missing |
warn | No SEO description or excerpt — write a 50-160 character description. |
description-length |
warn | Description is outside 50-160 characters — expand or shorten it. |
slug-long |
warn | Slug is over 75 characters — keep the essential words. |
slug-format |
warn | Slug has uppercase letters, underscores, or a date — use lowercase hyphenated words. |
Headings
| Code | Severity | Meaning and fix |
|---|---|---|
h1-in-body |
warn | Body contains an H1 other than a leading # <post title> — that one is removed before rendering, so demote any other body # headings to ##. |
heading-skip |
warn | A heading level jumps (H2 to H4) — use the next level so the outline stays intact. |
heading-empty |
warn | A heading has no text — fill it or remove it. |
heading-duplicate |
warn | The same heading text appears twice — rename it so each section is unique. |
Links
| Code | Severity | Meaning and fix |
|---|---|---|
link-internal-broken |
error | A root-relative or same-host link points to a slug with no published post — publish or fix the target. |
link-insecure |
warn | A link uses http:// — switch it to https://. |
link-anchor-generic |
warn | Link text like “click here” doesn’t describe the destination — use descriptive text. |
link-none-internal |
info | The post links to no other published post — link at least one related post. |
Content
| Code | Severity | Meaning and fix |
|---|---|---|
content-thin |
warn | Body is under 300 words — add substance or consolidate with a related post. |
paragraph-long |
info | A paragraph runs over 150 words — split it for readability. |
Images and sharing
| Code | Severity | Meaning and fix |
|---|---|---|
image-alt-missing |
warn | An image has no alt text — describe it for accessibility and image search. |
social-image-default |
info | No cover image — pick one, or the generated social card is used. |
Site and duplicates
| Code | Severity | Meaning and fix |
|---|---|---|
duplicate-title |
warn | Another published post uses this title — differentiate it. |
duplicate-description |
warn | Another published post uses this description — write a distinct one. |
canonical-external |
info | The canonical URL points off-site — remove it unless the post is syndicated from there. |
site-not-indexable |
info | The site isn’t indexable (search engines are told to skip it) — upgrade or enable indexing. |
Focus keyword
Pass focusKeyword to posts.seo_check (or fill the editor field) to add five warn findings, one for each place the keyword should appear: keyword-title, keyword-slug, keyword-intro (first 100 words), keyword-heading (a subheading; the title does not count), and keyword-description. Hyphens and underscores in a keyword match like spaces.
AI answers
AI answer engines quote short, self-contained passages. These rules check structure only; they can’t tell whether a passage is right or useful.
| Code | Severity | Meaning and fix |
|---|---|---|
answer-intro-missing |
warn | The post opens with a heading, list, or quote instead of a paragraph — start with a short paragraph that answers the title. |
answer-intro-long |
info | The opening paragraph runs over 80 words — keep the answer under 80 and move detail to the next paragraph. |
answer-claim-unsourced |
info | A paragraph states a percentage, a multiplier (“3x faster”), or a count in millions or more with no link in that paragraph — link the source or say where the number comes from. Footnote references count as links. Plain counts, versions, years, and prices are not flagged. |
answer-section-long |
info | The text under one heading runs over 400 words before the next heading — add subheadings so each part makes sense quoted on its own. |
answer-steps-prose |
info | A paragraph walks through steps in prose (three or more sentences starting with words like “First”, “Then”, “Finally”), or two or more paragraphs in a row start with “Step 1”, “Step 2” — use a numbered list. |
Code blocks never count toward these rules, and a number inside inline code is not a claim.
Agent guidance
Fix error and warn findings before asking for publish approval. error findings are broken promises — a link to a post that doesn’t exist yet; warn findings are things readers and crawlers will notice. info findings are optional improvements. Never invent a source to clear answer-claim-unsourced; say where the number comes from instead.
Then answer the judgment questions in the vibecms-seo skill with your own model before asking the human to approve.