All articles

The bill nobody capped

Your app has been costing you twenty dollars a month, and then one morning the invoice has four figures on it. It is almost never your users. It is usually a crawler, a scraper, someone's script hitting one endpoint in a loop, or a retry inside your own code that ran all night.

The best known story of this kind happened to a real product. TechCrunch reported on 6 June 2024 that Jingna Zhang, who built the artists' network Cara, opened her email to a Vercel bill of $96,280 for a single week, after the app grew from 40,000 to 650,000 users. That was genuine traffic, and she still had to ask publicly for the charge to be forgiven. When the traffic is not genuine, there is nobody to ask.

The reason is that none of this is billed by the month. A page view does not cost a fixed amount, it costs whatever ran during it: an image resized on the fly, a function that wakes up for every request, a query written without an index that reads the whole table. If your app calls a model, each visit also spends tokens. And nowhere in a generated codebase is there a question about who the visitor is, so the money gets spent on anyone.

First check: your own expensive routes. Go through the routes in your app and mark the ones that call a model, send an email or an SMS, generate an image, or write a file. For each of them, answer who is able to call it. If anyone with the link can, that is the whole exposure: a script hits it a thousand times a minute and you pay for every hit. A check for a signed-in user closes half of the problem, a rate limit per user and per IP closes the other half.

Second check: the cap on your hosting, which is usually not what people think it is. Vercel's Spend Management, per its documentation as of September 2026, lets you set a spend amount, but the amount by itself stops nothing: pausing your projects is a separate option you have to switch on. Vercel checks usage every few minutes rather than continuously, and warns that the pause can trigger several minutes after you cross the amount. So the number goes in with room to spare underneath it.

Third check: the cap on your database, which works the other way around. Supabase enables its spend cap by default on the Pro plan, and per its billing documentation as of September 2026, going over quota with the cap on restricts the service instead of turning into a bill; you switch the cap off in order to pay for over-usage. The trouble is that it stays off. If it was ever switched off to unblock something in a hurry, that is still how you are running today.

Fourth check: your model provider, where the word limit means two different things. In OpenAI's documentation as of September 2026, a spend alert only notifies you and traffic carries on; what stops requests is a hard limit, which has to be turned on separately with the "Enforce a hard limit" option. A number typed into the billing page without that switch is a notification. Set the limits at both the organization and the project, and put the alert well below them, so you hear about it before anything stops.

Fifth check: the other services that send you invoices. Maps, email and SMS, image generation, file storage, analytics, error tracking, the thing that builds and deploys your code. Each has its own account, its own billing page and its own idea of what a limit is. Google is the one people forget most often, because it comes in from the side: a map on a page, Gemini behind one feature, Firebase under the whole app. Google's Cloud Billing documentation, as of September 2026, says it plainly: an alerts-only budget does not cap usage or spending in Google Cloud or Google Maps Platform. Two other things stop the money. The first is a quota on the individual API, which limits how many requests you may make in a period, after which the service stops answering. The second is a spend cap budget, available for eligible services, which pauses usage once spend reaches the amount, until you lift it by hand. Google notes that this does not take effect instantly, because of the lag in cost reporting, so again the number goes in with room underneath.

The keys are a separate matter. A cap here is the last line of defence rather than the first: if a secret key ever went into your frontend, appeared in a screenshot, or landed in a public repository, someone else may already be spending on it. Rotate first, cap second.

The repair runs in the opposite order to the way this broke. Caps first, because they take minutes and they bound the worst case tonight. Then authentication and rate limits on the expensive routes, since that is where the spending starts. Then the slow part: reading the usage breakdown line by line and matching each line against what your code does on a single request.

Setting the caps is an evening. Working out why the bill grew is not, particularly when the answer turns out to be a query an agent wrote eight months ago that has been reading the whole table on every page load since.

Read next