Free tool

What is your notification bell actually costing?

An unread count on a timer is the path of least resistance, and for a lot of apps it is genuinely the right call. Put your own numbers in and find out which side of that line you are on.

10,000

Concurrent, not total signups. Only open tabs poll.

15s

How stale the badge is allowed to get, in the worst case.

24h

A dashboard people leave open all day is very different from a five-minute visit.

Defaults to $1.00, roughly an HTTP API gateway rate. This is the request charge only, and it is the part you should argue with. See the assumptions below.

667 requests per second, steady state
Per minute40,000
Per day57.6 million
Per month1.75 billion
Request cost, per month$1,728
Of those, answering “nothing new”~99.9%
Same load over SSE10,000 open connections
SSE requests per day~10,000

What the numbers mean

Polling is your app asking “anything new?” on a timer and hearing “no” almost every time. The request count is simple arithmetic: every open tab sends 3600 / interval requests an hour, and you multiply by the number of open tabs. That part is not an opinion, and it is the number worth looking at first.

The “nothing new” figure is the share of those requests that return an unchanged count. It assumes a fairly chatty product, at a few notifications per user per day. Most apps are quieter than that, which makes the ratio worse, not better.

The interval is the real lever, and it is a genuine trade-off rather than a free win: doubling it halves the cost and doubles how stale the badge can be. Polling makes you choose between feeling slow and being expensive.

What this does not count

Be suspicious of the dollar figure. It is the easiest number to quote and the least reliable, because the request charge is usually the smallest part of what polling costs you. Not included:

  • The work behind each request. Every poll is at least one authenticated database read. On most stacks that dwarfs the per-request charge.
  • Compute you are already paying for. If you run containers rather than functions, polling does not show up as a line item. It shows up as needing more containers.
  • Load balancer and egress charges, which vary far too much between providers to guess at.
  • The connection cost on the other side. SSE is not free either. See below.

Treat the dollar output as an order of magnitude. The requests-per-second number is the one to take literally.

SSE is not free either

Swapping polling for a stream trades a request problem for a connection problem. An idle user costs an idle socket instead of four requests a minute, which is usually a much better deal, but it is still a cost:

  • Every open connection holds a file descriptor and some memory for as long as it is open.
  • Load balancers have idle timeouts, so the transport needs heartbeats to survive them.
  • A deploy drops every connection at once, so reconnection needs backoff and jitter or the reconnect stampede takes you down instead.
  • Clients that were disconnected have to catch up on what they missed, which means the durable inbox is still the source of truth and the stream is only an accelerator.

That last list is most of the work. Getting a stream open is the easy part; everything after it is the reason this ends up being a bigger project than it looks.

When polling is the right answer

Often. If the calculator is showing you single-digit requests per second, stop reading and keep your setInterval. A streaming transport has real operational surface, and adopting it to save a few requests a second is a bad trade you will maintain for years. The arithmetic only turns against polling when concurrency is high, the interval is short, or both.

The longer argument, including the multi-tenant branding half of the problem, is in the notification system you didn't plan to build.

Or don't build either one

Elaan gives you an in-app inbox that updates over SSE with an automatic polling fallback, plus email and push from the same trigger. The reconnect, catch-up and heartbeat work is already done.