A headless CMS like Contentful bills by the API call. If your site fetches content from the CMS on every request, every page view costs calls. So does every bot, every crawler and every 404. The bill grows with traffic, not with how often the content changes.
It is also silent. Nothing breaks and the pages still load. Nobody opens the usage page until an invoice or a throttling error turns up.
Find your plan's API call quota, and what happens when you go over it. Contentful's usage limits show the three shapes this takes:
Whichever plan you are on, uncached traffic ends up as either a bill or throttled requests.
Monthly API calls are roughly page views multiplied by calls per page view. Most teams know the first number and have never measured the second.
A CMS-driven page usually makes more calls than you expect. There is the page itself, then the navigation, the footer, global settings, related items and any listing on the page. The layout calls happen on every page, including 404s, and a sitemap can fan out into hundreds.
To measure it:
The second count is what a real visitor costs once your caches are warm. If it matches the first, you have no cache.
A local count proves the cache works on your machine. Production has real traffic, bots and cold starts, so keep the count running there too.
Count at the HTTP client, because that is the one place that sees every call, whichever SDK or cache made it. Record the calls that reached the CMS separately from the ones the cache answered, and attach both as numbers to each request's telemetry. Because every request carries its route, you can then average the calls per page, find the most expensive page, and see whether a release changed it. See Do you know how to set up Application Insights? and Do you know how to analyse your web application usage with Application Insights? for custom metrics.
Where your monitoring already records outgoing HTTP calls as dependencies, counting CMS calls per request is a query rather than new code. Check which HTTP clients Application Insights collects automatically for your stack before writing a counter.
Check the daily total against the CMS usage page, because that is what you are billed on. If the two do not match, something is calling the CMS outside a page request, such as a background job, a scheduled task or a sitemap build, or your telemetry is being sampled.
The most expensive cache is one that looks like it works. The code writes to the cache and the config looks right, but every read misses. These are the common causes, and none of them throws an error:
.htaccess rules) but production runs another (e.g. nginx), so cached pages are written and never servedThe only way to find these is to count calls. The second view of a page should cost far fewer calls than the first, and a page served from a page cache should cost none.
On the example site at the end of this rule, Application Insights showed the difference:
❌ Figure: Bad example - Production telemetry with the content cache off. Every call still goes to the CMS
✅ Figure: Good example - The same site with the content cache on. Most calls are answered by the cache, which proves it is being read
Hosted search services like Algolia bill per search request. If a listing page runs a search on the server every time it renders, it has the same problem, and bots paging through every filter and page number multiply it. Cache search results the same way. Use robots.txt to keep crawlers out of the filter and paging combinations, while leaving the articles themselves crawlable.
Check the CMS usage page as often as you check the cloud bill, and always after a release that changes how content is fetched. Better still, count calls per page on the PR before it merges, as part of comparing PR performance with production. Turn on usage alerts where the CMS offers them. If usage is heading past the quota, tell the client before the invoice does, the same way you would warn about a spike in Azure costs.
A marketing site on Contentful's Lite plan had a quota of 3 million API calls a month. From November to July it used between 18.7 and 30.7 million a month. Nearly every call came from the Content Delivery API, which means the website itself, not the editors.
Measuring locally showed 20 to 40 calls per page view. A 404 page cost 20. A repeat view cost exactly the same as the first. The site had a page cache, an app content cache and an SDK cache, and each one was broken by a cause on the list above. Every one of those calls was also a round trip the server made before it could send the page, so the site was slow as well as expensive.
Fixing the cache read and the navigation refetch took a warm homepage from 23 calls to 10, and a warm content page to 7. Serving the page cache from nginx means repeat views of cached pages never reach the app at all, so they cost nothing.
The page cache went live in production on 31 August. Monthly calls fell from 30.7 million in June to 5.1 million in September. That is still above the 3 million quota, but it is a sixth of the peak.
Figure: Monthly API calls from the CMS usage page. The first full month after the page cache went live is a sixth of the June peak