Spunto CMS

Notion as a headless CMS

What you run into when a website reads its content from the Notion API — rate limits, nested blocks, expiring file URLs, id-only webhooks — and how Spunto CMS handles each one.

Using Notion as the CMS of a website is a reasonable first move. The team is already writing there, the editor is excellent, and the API can query a database. Plenty of blogs and docs sites run on it.

This page is about what tends to show up once the site grows, and what Spunto CMS does differently. It tries to be fair to both: where Notion is better, it says so.

Sources

Every statement about Notion below comes from Notion's own developer documentation, as read in October 2026, and links to the page it comes from. Notion changes its API; check the link before you rely on a number.

What a site runs into

Request limits

Notion's API allows 180 requests per minute, an average of 3 per second, on most plans; Business and Enterprise get 600 per minute. Over the limit, you get a 429.

That is plenty for an editor clicking around, and tight for a static build: one page with its blocks is several requests (see below), so a site with a few hundred pages spends its build waiting on the limiter.

Nested blocks, one level per call

Retrieving block children "returns only the first level of children", with at most 100 results per call. A toggle, a nested list or a column layout is another level, so another request. Rendering one page is a recursive walk.

File URLs expire

A Notion-hosted file comes with a temporary URL valid for one hour, and the documentation says plainly: "Don't cache or statically reference these URLs." A statically built page that embeds them shows broken images an hour after the build — unless the build copies every file somewhere else first.

Change notifications carry identifiers

Notion does have webhooks. A delivery carries the page id and the event type, not the content, and page.content_updated events "are batched and may not be sent immediately" — the documentation suggests waiting a minute or two. To rebuild one page you fetch it again, through the same rate limit.

What Spunto CMS does instead

Spunto CMS is a workspace in the style of Notion — lists of cards, typed properties, block-structured page bodies, saved views — and the rows the team edits are the rows the API returns. Here is how it answers each point above.

Notion APISpunto CMS
Request limits3 req/s average on most plans, 10 on Business and EnterpriseNone today — stated as a fact, not a promise
A page bodyRecursive walk, one level and 100 blocks per callOne call: GET …/items/{itemId} returns the whole document — a flat list of blocks with an indent (page bodies)
ListingDatabase query, 100 per pageView query with a filter tree, 200 per page, keyset cursor (querying)
FilesTemporary public URL, valid one hourNo public URL at all: the API serves the bytes behind your token, and a file id never changes content — your site relays it once and caches it for good (files)
Change notificationsIds and event type; content updates batchedThe changed keys with before and after, signed (HMAC with a timestamp), retried, one delivery per bulk edit, and a log you can replay from a cursor (events and webhooks)
Types for your codeOfficial JavaScript SDK (@notionhq/client), typedGenerated from the OpenAPI specification in one command — TypeScript, or any language with an OpenAPI generator

The files row is the one people misread. Spunto does not give you a URL that works forever either — it gives you no URL. That is deliberate: a shareable link would be a second way in, weaker than the token. What changes is that the bytes behind an id are immutable, so one relay route on your site (example) caches them indefinitely instead of re-fetching them every hour.

Where Notion is ahead

Be clear about this before moving anything:

  • The editor and the database model are far richer. Spunto has ten property types and no relations, rollups or formulas. If your content model depends on those, stay.
  • Public pages. Notion can publish a page to the web by itself. Spunto has no public page and no share link; your site is the only public surface.
  • Maturity and ecosystem. Notion has years of integrations and community renderers. Spunto CMS is young.

Read what it does not do before deciding. It is short.

Moving a Notion database over

POST /workspaces/{workspaceId}/import exists for this. The request names its source (notion) and each card carries its Notion page id as externalId, so the import is replayable: run it again and it updates instead of duplicating, and a card that has not changed is not rewritten — no write, no event, no webhook. Imports always fail at least once; this one you can run again until it is right.

You map Notion's properties and blocks to Spunto's yourself: statuses to statuses, select to select, and Notion's blocks to the ten block types. The rules are in imports you can run twice.

Next

The Next.js guide wires a site to Spunto end to end: typed client, rendered bodies, images and webhook revalidation. A free account at /login is enough to follow it.

On this page