Contentful: a 2026 scout of the headless-CMS incumbent — real curl, real 404, real €300 wall
Contentful is the headless CMS that "headless CMS" used to mean. It is older than Strapi, older than Sanity, older than Hygraph; the API shape it published in 2013 is still the API shape every newer competitor is benchmarked against. We spent an evening on 2026-05-07 doing the basic-evaluation walk on it — pricing, free tier, a real curl against cdn.contentful.com — the way a developer with five tabs open would. The interesting part isn't a bug; it's where the friction lives in 2026 for a product that was first to market.
We're the team behind SimpleReview, a Chrome extension that drafts code-fix PRs on whatever element you click on a broken admin or storefront. We are not affiliated with Contentful, not partners, not customers. This page is a scouting note from one real evaluation session on 2026-05-07: public pricing page, public CDA reference, the actual cdn.contentful.com endpoint with a real curl. We did not buy a Lite seat, we did not sit through a demo call. If we got something wrong, open a GitHub issue and we'll fix it.
Friction 1 — the gap between Free and the next tier
Open contentful.com/pricing and the page actually does its job: there is a tier table with prices, unlike some of its enterprise-sales competitors. The friction is not "where are the numbers"; it's the shape of the numbers themselves.
https://www.contentful.com/pricing/ via headless Chrome at 1440×950. Above-the-fold is intentionally aspirational; the tier table itself sits below.Pulling the numbers out of the page on the day we tested:
| Tier | Price | Users | Locales | API calls / mo | CDN bandwidth |
|---|---|---|---|---|---|
| Free | €0 forever | 10 | 2 | 100K (no overage) | 50 GB |
| Lite | €300 / mo | 20 | 3 | 1M | 100 GB |
| Premium | contact sales | custom | custom | unlimited | custom |
This is a real pricing page — we want to be fair about that. But the shape is unusual. The Free tier is generous on API calls (100K is enough for a small marketing site that doesn't redeploy on every save) and brutal on locales (2 is "English plus one" — not even the EU floor). The next step up is €300 per month, and what you get for it is one extra locale, ten extra users, and 9× more API calls. There is no €30 / €50 / €100 step in between. For a freelancer or a six-person startup who's outgrown the Free tier on locales but not on traffic, the choice is "stay on Free with two locales" or "pay €3,600/year to add a third one." The middle of the curve is missing.
Roles cap at 2 on Free, 3 on Lite. If you want a fourth role — a separate "translator" identity, a "client reviewer" identity, a CI bot — you're moved into custom-pricing Premium. Same for environments past the default master setup, same for SSO, same for SLAs. Contentful's pricing isn't hidden — it's just bimodal: a hobby plan and an enterprise plan with no real prosumer rung in between.
Friction 2 — the delivery / preview / management token split
Where Contentful's API is hidden is in the access-token model. There are three different token classes and they live on three different hosts:
| Token | Host | What it reads | Cached |
|---|---|---|---|
| Content Delivery (CDA) | cdn.contentful.com | Published entries only | Yes (CDN) |
| Content Preview (CPA) | preview.contentful.com | Published + draft entries | No |
| Content Management (CMA) | api.contentful.com | Read + write everything | No |
The first time you build a Next.js / Nuxt / Astro front-end against Contentful, the lesson everybody learns is the same one: you build it against the CDA, deploy it, then realise editors can't see their drafts on the staging URL because drafts only exist on the preview API on a different host with a different token. There's a long and well-documented trail of tickets and Stack Overflow answers about this. It's not a bug — it's an architectural choice that makes the cached delivery layer fast — but it's the single most-asked friction question Contentful gets, and a fresh evaluator usually doesn't notice it until they're already shipping. Worth knowing on the way in.
What the API actually does — a real curl
The pricing page can ungate, hide, or rename things. The production API cannot. cdn.contentful.com is public-facing; you can hit it with no account and observe the real shape (you'll get an error, but the error is documentation).
First, the cleanest possible test — ask for a space that doesn't exist:
$ curl -sD - "https://cdn.contentful.com/spaces/INVALID/entries"
HTTP/2 404
content-type: application/vnd.contentful.delivery.v1+json
x-content-type-options: nosniff
server: Contentful
x-contentful-region: us-east-1
contentful-api: cda
access-control-allow-origin: *
access-control-expose-headers: Etag,x-contentful-ratelimit-second-limit,x-contentful-ratelimit-reset
via: 1.1 varnish, 1.1 varnish
x-served-by: cache-ewr-kewr1740028-EWR, cache-bma-essb1270035-BMA
x-cache: MISS
x-contentful-request-id: aaeeb664-5507-496f-81a7-d0870f99bf61
content-length: 165
Body, verbatim:
{
"sys": {
"type": "Error",
"id": "NotFound"
},
"message": "The resource could not be found.",
"requestId": "aaeeb664-5507-496f-81a7-d0870f99bf61"
}
That is a clean shape. Contentful's error envelope has lived in this form for the better part of a decade: a sys.type: "Error" wrapper, a stable sys.id string you can switch on (NotFound, AccessTokenInvalid, RateLimitExceeded, BadRequest...), a human message, and a requestId that you'll be asked for if you ever escalate to support. The headers are honest about what's serving the request — server: Contentful, fronted by Varnish (not Cloudflare, unlike most of the newer headless CMSes), with cache POPs visible in x-served-by (kewr = Newark, essb = Stockholm). The x-cache: MISS tells you the validation hit origin — consistent with a 404 that has to be authoritative.
Second test — a syntactically-valid space ID (their public demo space cfexampleapi) with a deliberately bogus token:
$ curl -sD - "https://cdn.contentful.com/spaces/cfexampleapi/entries" \
-H "Authorization: Bearer invalid_token_xyz"
HTTP/2 401
x-contentful-ratelimit-second-limit: 78
cf-space-id: cfexampleapi
cf-environment-id: master
x-contentful-route: /spaces/:space/entries
etag: "11677993936344935350"
contentful-api: cda
content-length: 174
{"sys":{"type":"Error","id":"AccessTokenInvalid"},"message":"The access token you sent could not be found or is invalid.","requestId":"c4dc9272-4de6-4c1c-94dc-e306d9c8ea30"}
This response is more interesting than the 404 because it's leaking useful diagnostics: cf-space-id echoes back the space they resolved (so we know cfexampleapi is a real space), cf-environment-id: master tells us they fell back to the default environment, x-contentful-route tells you which route handler matched, and x-contentful-ratelimit-second-limit: 78 tells you the per-second budget for an unauthenticated request before the token is validated. Their public docs cite the rate limit as "55 requests per second"; the live header reports 78 for this particular path. Two different numbers from the same vendor for the same dimension — the docs and the headers should reconcile, and on this date they don't quite.
Third test — the Content Management API at api.contentful.com, hit with no token at all:
$ curl -sD - "https://api.contentful.com/spaces"
HTTP/2 401
content-type: application/vnd.contentful.management.v1+json
server: Contentful
strict-transport-security: max-age=31536000
x-contentful-request-id: bce88fd6-367b-43a3-b5c4-d17f700b26ba
{"message":"An access token is required. Please send one through the HTTP Authorization header or as the query parameter \"access_token\".","requestId":"bce88fd6-367b-43a3-b5c4-d17f700b26ba","sys":{"id":"AccessTokenInvalid","type":"Error"}}
Note the access-control-allow-headers on the CMA host (we trimmed it from the snippet above) advertises a sprawling set of X-Contentful-* headers including X-Contentful-Async-Ai-Action, X-Contentful-Ai-Actions-Platform, X-Contentful-Personal-Intercept, and X-Contentful-Skip-Ui-Draft-Validation. The 2025-2026 AI-actions push is real and it's wired into the CMA — you can see the surface area without an account just by reading the CORS preflight allowlist.
The CDA reference page itself
contentful.com/developers/docs/references/content-delivery-api/, captured 2026-05-07. Note the explicit "Fair Usage Policy" note and the "API rate limits" section in the left-hand nav — both are downstream of having a paid model where overage matters.Two things about the docs page worth flagging. First: there's an honest, prominent "Fair Usage Policy" link in the introduction box — the kind of thing a vendor adds after enough customers have bumped into the soft limits. Second: the EU data-residency host (cdn.eu.contentful.com) is a separate base URL, not a regional hint on the main host. If a German customer asks "where is my content stored", the answer is "the host you point your SDK at" — and the SDK config lives in your code, so this is something to land in the architecture decision, not in the deployment scripts.
Honestly, next to Strapi / Directus / Payload
We've done the same scouting walk on the open-source side — Strapi, Directus, Payload — and we've also scouted the closer SaaS competitors: Contentstack, DatoCMS, Hygraph, Sanity. Contentful's place on that map is "the one everyone benchmarks against." Concretely:
| Dimension | Contentful (this scout) | Strapi / Directus / Payload |
|---|---|---|
Time to first curl against your own data |
Free-tier signup + space + token: ~10 minutes from zero. | ~10 minutes from docker run to authenticated GET. |
| Public pricing | Free / €300 Lite / Custom Premium. Numbers are real. | Self-host: free. Cloud tiers: published, usually $0/$10/$50 rungs. |
| Locale gating | Free = 2, Lite = 3, more = custom Premium. | Unlimited locales out of the box on all three. |
| Token model | Three classes (CDA / CPA / CMA), three hosts. Has friction. | One token per role; same host. Less elegant edge caching, simpler mental model. |
| Multi-region delivery | Two CDN hosts (US default + EU residency), Varnish-fronted. | Whatever you put in front of the container. CDN is your job. |
| SDK ecosystem | JS, TS, Ruby, PHP, .NET, Java, Python, Swift, Android — all maintained. | JS/TS first-class; rest is community. |
| Vendor lock-in | Medium-high. CMA export tooling exists; content model is theirs. | Low. The DB is yours. Migration is a SQL dump. |
| Compliance posture | SOC 2, ISO 27001, GDPR-ready EU residency. | You inherit your own posture. Audit reports require legal work. |
The right way to read this table is not as a verdict. Contentful is the right answer for an editorial team of fifteen-plus people who need a battle-tested CDN with an EU residency option, a mature SDK in whatever language their backend is in, and a vendor with a SOC 2 report a Fortune-500 procurement team will accept. The locale gating bites if you're a small team scaling into multi-language; the €300 Lite jump bites if you're prosumer-shaped. The open-source three are the right answer for a startup that wants to own the database, ship in a weekend, and not be priced into a tier change at month seven.
Things we'd change
- Add a €30-50 prosumer rung between Free and Lite. The current curve has a Grand-Canyon-shaped hole between 2 locales / 100K calls and 3 locales / 1M calls. A "Solo / Indie" tier at €30 with 4 locales, 250K calls, 5 users, would catch every freelancer and agency-shop that currently grows out of Free into a competitor.
- Reconcile the rate-limit numbers. Docs say 55 req/s. Live
x-contentful-ratelimit-second-limitheader on a 401 response says 78. Pick one and document the path-level differences if they're real. - Put the CDA / CPA / CMA distinction front-and-center in the getting-started. It's the single biggest source of "why don't I see my drafts" support load. A two-sentence callout on the first auth page would save thousands of tickets a year.
- Document the AI-actions surface like the Delivery API. The CMA CORS allowlist already advertises a half-dozen
X-Contentful-Async-Ai-Actionheaders. The reference page for that surface should exist before the headers do.
What we'd actually do
If we had a customer with a 30-person editorial team, four locales, and a Java backend that needs an SDK their security team has already approved, we'd recommend Contentful and not pretend otherwise — the API is clean, the regions are real, the SDKs are maintained, and the €300 Lite is a small line item next to a salary budget. If we had a five-person team building a localized product into 2027, we'd self-host one of Strapi, Directus, or Payload, accept the CDN-is-your-job tax, and not be priced out of a fourth locale on a quiet Tuesday. The mismatch between Contentful's tier curve and a small team's growth curve isn't a flaw — it's the segmentation. Worth knowing which side of it you're on before you pick.
Where this fits
Adjacent scouting notes from the same week: Contentstack — behind the "Contact us" wall, DatoCMS — the GraphQL-first SaaS, Hygraph — multi-region GraphQL, Sanity — the structured-content one, Strapi — the open-source default, Directus — SQL-first with a real admin, Payload — TypeScript-first headless, Ghost — the headless-blog wedge. SimpleReview is the Chrome extension that turns whatever element you click on a broken admin or storefront into a draft code-fix PR — it works on a Contentful-rendered front end the same way it works on a Strapi one, because by the time the page renders it's just HTML.