Blocks
The block types, rich text, and the JSON Schema.
An article's body is an ordered array of blocks, each with a type. Render the types you know and skip the rest. A type added later is then missing from the page instead of breaking it.
| Type | Fields | |
|---|---|---|
heading | level: 2 | 3 | 4, text, id | id is an anchor derived from the text, unique within the article; a rewrite that changes the heading changes it. The article title isn't a block. |
paragraph | content: RichText | |
list | ordered, items: RichText[] | |
quote | content: RichText, attribution? | |
code | language?, code | Plain text; don't interpret. |
image | url, alt, caption? | On the SEO for SaaS CDN; alt is always set. |
callout | variant: "info" | "tip" | "warning", content: RichText | |
cta | heading, body?, buttonLabel, buttonHref | A call to action into your product. |
faq | items: { question, answer: RichText }[] | Also in seo.jsonLd as FAQPage. |
table | headers: string[], rows: string[][] | Plain-text cells. |
video | provider: "youtube", videoId, url, title | A YouTube video taken from the search results for the topic. |
Every block also carries an id, unique within the article. Each type has a page with a live render under Components.
Rich text
Paragraphs, list items, quotes, callouts and FAQ answers are RichText: an array of runs.
| Field | Type | |
|---|---|---|
text | string | Plain text. Render it as text, never as HTML. |
bold, italic, code | boolean? | Inline styling. |
href | string? | Makes the run a link: https: or http:, a site path (/pricing), or a # anchor. Nothing else. |
rel | string? | Set on every link to a research source, currently nofollow ugc noopener. Pass it to the anchor unchanged. |
{ "type": "paragraph", "content": [ { "text": "Google describes the process in its " }, { "text": "guide to how Search works", "href": "https://developers.google.com/search/docs/fundamentals/how-search-works", "rel": "nofollow ugc noopener" }, { "text": "." } ]}JSON Schema
https://api.seoforsaas.dev/public/v1/schema/blocks.json describes the block array. It's generated from the schema the API validates with, so it always matches what the API returns. The API enforces the link-scheme and rel rules.