Reviewing for cost
Lens two. In a market tool, cost is not an abstraction about performance — it is your daily allowance, and running out means the tool stops.
The N+1 that costs money
A screen returns forty rows. The designer wants a sector label and a short description per row. An assistant, asked for that, writes:
const rows = await screen(filters);
const enriched = await Promise.all(
rows.map(async (r) => ({
...r,
profile: await fetchFundamentals(r.code), // one call per row
})),
);
Correct output. Four hundred and five API calls where you expected five — a /screener request costs 5 and each /fundamentals request costs 10, both measured 2026-08-26 — and Promise.all fires them simultaneously, so you may also collect a rate-limit rejection on top.
The classic N+1, except each N is metered and billed. Notice it is invisible in the rendered page — the screen looks right, and the meter is the only thing that says otherwise. Which is why the meter has been on screen since course 1 lesson 4.
And the sector was already there. The screener response includes sector and industry:
{"code":"NVDA","sector":"Technology","industry":"Semiconductors", "...": "..."}
Forty extra calls to fetch a field that arrived in the first response. This is the most common cost bug in market tooling and it is always the same shape: not knowing what the payload already contains.
The refresh that never sleeps
Second pattern, from course 1 and worth re-checking here because a screen costs the same as a quote call:
useEffect(() => {
const t = setInterval(runScreen, 30_000);
return () => clearInterval(t);
}, [filters]);
Two calls a minute, from any open tab, whether or not anyone is looking. And the dependency on filters means every keystroke in a filter box tears down and restarts the timer — and if filters is rebuilt on each render rather than memoised, the effect re-runs every render, which is a screen per render.
There is no version of a screener that needs to auto-refresh every thirty seconds. It runs on the last completed session; the data does not change during your morning.
Three questions for the cost lens
- How many calls does this make? Count them, do not estimate.
- What does that number scale with? Rows, keystrokes, renders and open tabs are all multipliers, and only one of them is under your control.
- Is the data already in a response I have? Ask before adding a fetch, every time.
Measure rather than reason
You have an instrument. Note apiRequests from /user, do the thing, note it again.
Do this after any change that touches fetching, because the arithmetic in your head is reliably optimistic and the meter is not. A change that quietly triples your cost per view is invisible in every other way.
Try it now
Read your screener's fetching code and write down the predicted number of calls for one page view. Then measure it with the meter. If prediction and measurement disagree, the gap is a bug you have not found yet — go and find it before reading the next lesson.