Where it runs
The marketing editor
A Pre-publish check section sits above Status in the item’s sidebar, so its findings are above every publish control: a score chip out of 100, errors under Fix before publishing, warnings under Worth a look. Each row names the field and clicking it jumps there (title, slug, meta title, meta description, target keyword, alt text, body). The report is fetched when the item opens and re-run locally on every edit, so it tracks what is being typed.
The publish gate
Every publish entry point in the editor (the header action, Publish changes in the sidebar, the Publish to dialog, the status flip on an unlinked item) goes through one gate: unsaved edits are saved, the server check runs again, and errors open Publish anyway? listing them, with Go back and Publish anyway. Warnings never interrupt, and a check that cannot run never blocks.
The APIs
GET /api/olympus/marketing/content/:contentId/seo-check under an Olympus API key, and its dashboard twin GET /api/marketing/content/{id}/seo-check for a signed-in user with marketing.content read. Same loader, same response; a row outside the account is a 404. From an MCP client the content_seo_check tool calls the Olympus route.The publish route
POST /api/olympus/marketing/content/:contentId/publish-to-site (content_publish_to_site) runs the check on the row as it is about to go out and returns warnings: string[] (one line each, Error (field): ... or Warning (field): ...) plus the structured seo_check. The note tells the department to state each one before treating the publish as done. Unpublish is not checked.What it checks
Two levels. An error is something the site will visibly get wrong: a missing meta description, a body with two H1s, an image with no alt text, a banned phrase, an empty body. A warning is a ranking or editorial miss the writer should look at: keyword placement, heading order, few internal links, a figure with no source.
Three rules behind the table are worth knowing:
- One H1 is the page title. Site templates render the item’s title as the page H1, so a body with no H1 is the normal, correct shape. A body with exactly one H1 is accepted (some imports carry the title inside the body); two or more is an error.
- Markdown and HTML are both read. Rows hold either, and the stored format hint is not reliable (the editor converts markdown to HTML on load and saves the HTML back), so the format is detected from the content and the hint only breaks ties. Code blocks are ignored; image syntax and links are reduced to prose before words are counted.
- Internal is relative to the site. A site-relative path counts as internal, and so does an absolute URL on the linked project’s production host, so a link back to
https://www.example.com/blog/...counts onwww.example.com. Anchors,mailto:andtel:links count as neither.
The score and the response
ok is true when there are no errors; warnings never flip it. score is 100 minus 15 per error and 5 per warning, floored at 0. checks lists errors first, then warnings, each in the order above.
context is what the check was given, so a client can re-run it locally on edits without another request: the target keyword from settings.target_keyword, the forbidden phrases from the account’s default active brand guide (empty when there is none), the linked project’s production host (its active primary production domain, else its custom domain, else its hiveku.com host), the stored format hint, and linked, which is true when the item is bound to a website project and a CMS collection. The slug checked is the site entry’s slug once the entry exists, otherwise the library slug.
What it does not do
- It never blocks. The editor asks Publish anyway? on errors; the publish route publishes and reports. A check that fails to run yields an empty list, not a failed publish.
- It checks the item, not the collection. A
meta_titlethat has no home in the collection (noseoTitleormetaTitlefield) is dropped at publish time and named in the publish response’sunmappedlist. The check cannot see that from the row, so readunmappedas well. - It does not read the live page. Word counts, links and images are those of the stored body. The rendered template, the blog index and the deploy are outside its view.
- Unpublish is not checked. Taking a page down never waits on a meta description.
Related pages
- The Content Department — the writer that states this list before it publishes, and links to real URLs so the internal-link check passes on merit
- Scheduling and the Content Calendar — a scheduled item is checked when it is published, and shows on the calendar
- Use the Marketing Content Review Workflow — the editor the check panel lives in
- SEO Delivery Tools — the page audit and rank tracker that measure the published result