Blog · Product
How many push notifications to send before people opt out
There is no safe weekly number. Split notifications by type, cap the promotional ones low and measure opt-outs per send to tune the cap with real data.
There is no weekly number of push notifications that is safe for everyone: people opt out when a notification is useless to them, not when they get the fifth one. What works is splitting notifications by type, capping only the ones you decide to send, and measuring opt-outs per send so you can tune that cap with your own data.
In short:
- Notifications the user triggers (an order, a reply, an alert they set up) rarely annoy anyone; the ones you choose to send are the ones to limit.
- Start with a low cap for promotional or editorial pushes and raise it only if opt-outs stay flat.
- Let each person pick topics and pace, store those choices as tags and target sends by segment.
- Track opt-outs, expired subscriptions and clicks per send and per notification type, not just as a monthly total.
- Chrome can revoke permission from sites that send a lot and get little engagement, so overdoing it also costs reach.
Why there is no magic number
How much someone tolerates depends on what they expected when they granted permission. If your site asked with "we'll tell you when your order status changes", four notifications in two days (confirmed, shipped, out for delivery, delivered) are exactly what was promised. If a news site asked for "breaking news" and sends four generic headlines a day, the same volume feels like noise.
So the useful question is not "how many?" but "would this person have asked for this one if I asked them right now?". If the answer is unclear, the send costs you: every irrelevant notification teaches people to ignore the next one, including the ones that matter.
The browser has a say too. Since late 2025, Chrome on Android and desktop automatically revokes notification permission from sites that combine a high volume of notifications with very low user engagement (installed web apps are excluded). Google does not publish the exact thresholds, so there is no "safe" figure to hide behind. The only real protection is sending notifications people actually open.
Split notifications by type before setting limits
A single limit for everything either punishes useful notifications or lets too many promotional ones through. Classify first:
| Type | Example | Triggered by | Sensible policy |
|---|---|---|---|
| Transactional | Payment confirmed, order shipped | A user action | No cap, but no duplicates |
| User-defined alert | Price drop, new reply | A rule the user chose | Batch bursts into a digest |
| Promotional or editorial | Sale, product news, article | You | Low cap per person per week |
Only the last row needs a frequency cap. The other two follow events, but they carry their own risks. A duplicated transactional push ("your order has shipped", twice) erodes trust, and ten "new reply" alerts in five minutes should arrive as one: "You have 10 new replies in your thread". Duplicates usually come from retries, which an Idempotency-Key prevents.
Start with a low cap and enforce it on your server
A rule of thumb to start with (not a standard, and not from any study): at most one promotional push per person per day and two or three per week, never at night in their time zone. Raising a cap later is much easier than winning back someone who already blocked your site.
The cap belongs in your backend, right before you call the send API, because that is where you know what each user already received. A per-user daily counter is enough:
// Before sending a promotional push to one user
const day = new Date().toISOString().slice(0, 10); // UTC date
const key = `promo-cap:${userId}:${day}`;
const count = await redis.incr(key);
await redis.expire(key, 2 * 24 * 3600);
if (count > 1) return; // already got today's promotional push
// sendPush: your function that calls POST /v1/notifications
await sendPush({
to: { type: 'users', userIds: [userId] },
title: 'Free shipping until midnight',
url: 'https://yourshop.com/deals',
}); Note the trade-off: a send to a whole segment ({ "type": "segment", "tags": { … } }) is convenient, but it cannot know how many pushes each person got this week. If you need per-person caps, filter in your database first and send with { "type": "users", "userIds": [ … ] }. For timing, store each user's time zone and trigger sends from your own cron job in time-zone batches.
Let people choose topics and pace
Many opt-outs don't mean "I want nothing"; they mean "I want less of this". If blocking is the only way out, people use it. A small preference center next to the enable button changes that: orders always, deals "weekly" or "never", blog posts on or off.
Those preferences fit nicely as subscriber tags. With the castly browser SDK you store them like this (note that setTags replaces the whole set, so always send every key):
// When a toggle in the preference center changes
await Castly.setTags({ deals: 'weekly', blog: 'off' }); When sending, you target only the people who chose that pace:
{
"to": { "type": "segment", "tags": { "deals": "weekly" } },
"title": "This week's 5 best deals",
"url": "https://yourshop.com/deals/week"
} Offering "less" alongside "none" gives an exit to people who only want less noise, and it tells you which topics are wearing out their welcome.
Watch out for bursts on reconnect
One detail inflates perceived frequency without you changing anything. When a device is off or offline, the push service holds messages for their TTL and delivers them all at once when it reconnects. A laptop closed all weekend can get three stale promotions in a row on Monday morning, even though you sent one a day.
Match the TTL to the message's useful life: a deal that ends in three hours should go out with "ttl": 10800, not a full day. For pushes that are not time-sensitive, an urgency of low or very-low lets the device hold them for a better moment, such as when it is charging. The full field list is in the API reference.
How to measure whether you send too much
Opt-outs come through three different paths, and it pays to count them separately:
- Explicit opt-outs: the person turns notifications off in your UI. You record these yourself, for example by listening to the SDK's
unsubscribedevent. - Revoked permission: blocking in browser settings, the unsubscribe button Chrome may show on the notification itself, or automatic revocation. Nothing tells you at that moment; you find out when the next push to that device returns 404 or 410. castly then marks that subscription as expired and fires the
subscriber.expiredwebhook (see the webhooks docs). - Silence: pushes get delivered, but the person hasn't clicked any of the recent ones.
From there, track one simple metric per notification type and per week: expired subscriptions per 1,000 deliveries, next to click-through rate (clicks divided by deliveries). Some expiry is natural (people clear browser data or switch devices), so the absolute value matters less than how it moves when you change frequency. Because expiry is only detected when you send, look at a trend over several weeks, not a single day.
To compare two paces fairly, assign a random tag at subscription time, cohort: 'a' or 'b', and send the extra weekly promotion only to cohort b for a month. castly has no built-in A/B testing, but tags, the per-device logs from GET /v1/notifications/:id (sent, delivered, clicked) and webhooks are enough for this experiment.
Frequently asked questions
How many push notifications per week is too many?
It depends on the notification type and on what you promised when asking for permission. For promotional pushes, it is too many when raising frequency increases expired subscriptions per 1,000 deliveries and click-through drops. Start low and only go up while both numbers hold.
Do transactional notifications count toward the cap?
They shouldn't, because the user triggered them and expects them. What you must avoid is duplicating them through retries, and you should batch bursts of alerts into a single digest.
How do I know if someone blocked notifications in their browser?
The browser does not tell your server. You find out when the next push to that device fails with 404 or 410, or when the person returns to your site and Notification.permission reads denied.
What time should I send non-urgent notifications?
During each person's daytime, never at night in their time zone. Store the time zone when they subscribe and send in batches from your own scheduler.
Can Chrome remove my site's permission without the user asking?
Yes. Chrome on Android and desktop revokes permission from sites with a high volume of notifications and very low engagement, tells the user, and lets them restore it. Installed web apps are not affected, but it is wiser not to rely on that exception.