Blog · Engineering

TTL and urgency in web push: notifications on time, or not at all

What TTL and urgency mean for the people receiving your notifications, which values to use for codes, deliveries, appointments, news or promotions, and how to set them.

Leer en español

TTL decides how long a notification can still reach a device that was switched off or offline, and urgency decides whether a device that is trying to save battery delivers it now or later. Choosing them is a product decision: TTL should last as long as the notification stays true, and urgency should be high only when a delay costs the person receiving it something.

In short:

  • A stale notification is worse than none: a reminder that arrives after the appointment confuses people and erodes trust.
  • TTL = the number of seconds the notification stays useful. If the device does not connect in time, it is never delivered.
  • Low urgency = less battery drain in exchange for possible delays; high = immediate delivery even on low battery.
  • In castly, ttl defaults to 86400 (24 hours) with a maximum of 2419200 (28 days); urgency accepts very-low, low, normal (the default) and high.
  • For anything tied to a time, compute TTL at the moment you send.

What TTL means for the person receiving it

If the device is online when you send, the notification arrives within seconds and TTL never comes into play. If it is off or without signal, the browser's push service holds the message and delivers it when the device comes back, but only for the number of seconds set by TTL; after that, it is dropped.

From the recipient's point of view, TTL answers a simple question: would I rather get this late, or not at all? Say that on Friday at 6:30 p.m. you send "Your class starts at 7:00" with a 24-hour TTL. The student's laptop stays closed until Saturday at 10 a.m., and when she opens it, up pops a reminder for something that is already over. With a TTL of 1800 seconds, the notification would have been dropped at 7:00 and nobody would have seen a misleading alert.

A late notification is never neutral. An expired code makes people try it and fail, a sale that already ended looks like bait, and an alert about a problem already fixed causes needless alarm. Each of those moments teaches people your notifications cannot be trusted, and blocking them is usually the next step. The extreme case is ttl: 0, meaning "now or never": it is delivered if the device is reachable at that instant and dropped otherwise.

What urgency means: battery versus speed

Urgency is a hint to the device about how much of a hurry there is. A phone low on battery or a laptop in power-saving mode may hold back low-urgency messages until a better moment. The Web Push standard defines four levels, and each platform decides how to apply them:

  • very-low: can wait until the device is charging and on Wi-Fi. For promotions and content with no rush.
  • low: can wait until it is charging or on Wi-Fi. For updates and digests.
  • normal: regular delivery, no special conditions. For most personal notifications.
  • high: delivered even on low battery. For things that cannot wait.

Urgency does not change TTL, and it does not get a message to a switched-off device any sooner: it only affects online devices that are trying to save power. Marking everything high therefore does nothing for offline users while spending their battery on notifications that could have waited. And low urgency combined with a short TTL can mean the notification never arrives at all: if you pick very-low, give it room.

Which TTL and urgency to use for each case

The TTL question is: from what moment is this notification false, useless or annoying? For urgency: what does the person lose if it arrives ten minutes late? These values are rules of thumb, not figures from any standard:

Use casettl (seconds)urgencyWhy
One-time code or sign-in approval300, or however long the code lastshighUseless and confusing afterwards
Courier about to arrive900highIn 15 minutes they have arrived or left
Order shipped or another status change86400normalUseful for the day; details stay on your site
Appointment reminderSeconds until the appointmentnormal, or high in the last hourAfter the appointment it is a false alert
Breaking news3600highAfter an hour it is no longer breaking
Promotion with an end dateSeconds until it endslowNobody should see a deal that is over
Weekly digest604800very-lowValid until the next digest

Notice that time-bound notifications have no fixed TTL: it depends on when you send them. A reminder sent three hours before an appointment needs a TTL of about three hours; one sent the evening before needs almost a day.

How to set ttl and urgency when you send

In castly's API, POST /v1/notifications accepts two optional fields: ttl, in seconds from 0 to 2419200, and urgency. If you leave them out, the notification uses 86400 and normal: it can show up as much as 24 hours late, which is fine for general messages but not for anything time-bound. Every field is in the API reference.

// Appointment reminder: stops making sense at the appointment time
const secondsLeft = Math.floor((appointment.startsAt - Date.now()) / 1000);
const ttl = Math.min(secondsLeft - 300, 2419200); // 5-minute margin, 28-day cap

if (ttl > 0) {
  await fetch('https://castly.sh/v1/notifications', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.PUSH_SECRET_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      to: { type: 'users', userIds: [appointment.userId] },
      title: 'Reminder: your appointment is at 5:30 p.m.',
      body: 'Room 3. Tap for directions.',
      url: `https://example.com/appointments/${appointment.id}`,
      ttl,
      urgency: secondsLeft < 3600 ? 'high' : 'normal',
    }),
  });
}

Compute TTL right before calling the API, not when you schedule the reminder: if the send goes out later than planned, a TTL computed in advance would let through notifications that no longer make sense. And if it is already too late, send nothing.

To try it without writing code, the dashboard's Playground lets you pick the notification's lifetime (from "now or never" up to 28 days) and its urgency before sending a test push to your browser. A useful test: with a test device switched off, send a "now or never" notification and turn the device on a minute later. Nothing should appear.

What you will see in your metrics

A notification whose TTL runs out before the device connects stays sent but never becomes delivered. In the notification's detail view, or through GET /v1/notifications/:id, that device shows sent without moving on to delivered. Short TTLs lower your delivered-to-sent ratio, and that is expected: do not "fix" it by raising TTL.

Don't confuse this with an expired subscription: there, the device no longer exists for your site; here, it was simply offline while the notification mattered. And to judge whether your content works, measure clicks over delivered notifications, not over sent ones.

Frequently asked questions

Which TTL and urgency are used if I set nothing?

A TTL of 86400 seconds (24 hours) and normal urgency. They work for general notifications, but any message tied to a date or time deserves its own values.

What is the maximum TTL?

The API accepts up to 2419200 seconds, which is 28 days. It is a ceiling, not a promise: the browser's push service may keep the message for less time.

Does high urgency guarantee instant delivery?

No. It asks the device not to hold the message back to save battery, but if the device is off or offline the message waits anyway, at most until TTL runs out.

Does TTL remove a notification that was already shown?

No. TTL only limits how long a notification may wait before delivery; once on screen, it usually stays in the notification center until the person dismisses it. That is why the text should stay true for a while, or state the time it refers to.

Put it into practice with castlyWeb and PWA push notifications for developers: an SDK under 3 KB, a REST API and delivery logs for every device. Free up to 10,000 pushes a month.
Create a free account →

Send your first push notification today.

Create a project, add the SDK and send with one API call. Free to start.

Create a free account →