---
title: Scheduling Travel Notifications Without Losing Your Mind
description: "How we schedule gate change alerts, departure reminders, and check-in nudges across every time zone — priority ordering and quiet hours enforcement."
canonical: https://nowah.xyz/blog/scheduling-travel-notifications
lastModified: "2026-08-07T03:54:10.388Z"
---

# Scheduling Travel Notifications Without Losing Your Mind

How we schedule gate change alerts, departure reminders, and check-in nudges across every time zone — priority ordering and quiet hours enforcement.

A gate change alert that arrives 10 minutes after you've already been standing at the wrong gate is worse than useless. It's actively harmful because it means you trusted the system to tell you, and it failed.

Travel notifications sit at the intersection of two hard problems: time sensitivity and global distribution. The notification needs to arrive at exactly the right moment, and "the right moment" depends on the traveler's time zone, their current location, the departure airport's local time, and whether they're asleep.

We spent more time on our notification scheduling infrastructure than most people would expect. It turns out that sending the right message at the right time to the right person is a surprisingly deep engineering problem.

## The priority hierarchy

![Illustration for this section](https://pics.nowah.xyz/website-media/infrastructure-008-img-1.webp)

Not all notifications are created equal. A gate change 20 minutes before boarding is life-or-death for making your flight. A marketing email about fare sales is nice to have. Treating them the same would be negligent.

We enforce a strict priority hierarchy:

**Critical** notifications override everything, including quiet hours. Gate changes, flight cancellations, significant delays, security alerts. These go out immediately and through every available channel: [push notification](/blog/push-notification-travel-alerts), email, and in-app.

**Time-sensitive** notifications respect quiet hours but get priority processing. Departure reminders 24 hours and 2 hours before the flight, check-in reminders when the window opens, payment confirmation after booking. These wait if the traveler is in quiet hours but jump to the front of the queue otherwise.

**Informational** notifications follow normal scheduling and respect all preferences. Trip itinerary updates, document availability, price drop alerts for watched routes. These queue normally and deliver during the traveler's active hours.

**Promotional** notifications are the lowest priority. Feature announcements, travel inspiration, partnership offers. These never interrupt. They deliver only during optimal engagement windows and respect aggressive suppression rules.

The priority level determines queue routing, quiet hours behavior, retry aggressiveness, and channel selection. A critical notification retries faster and through more channels than a promotional one.

## Time zone calculations

Here's where things get fun. Consider a traveler who lives in New York, is currently in London for a conference, and has a flight tomorrow morning from Heathrow to Tokyo.

When should we send their departure reminder? 24 hours before departure in which time zone? Their home time zone (New York)? Their current location (London)? The departure airport time zone (also London, in this case)?

We use the departure airport's local time as the anchor for flight-related notifications. The traveler needs to be at Heathrow at a specific local time, so the reminder should reference that local time. "Your flight departs at 9:15 AM from Heathrow. Check-in opens in 1 hour."

But we deliver the notification based on the traveler's current time zone. If it's 3 AM where they are, even a time-sensitive departure reminder should wait until they're likely awake (unless the flight is imminent enough to be critical).

All times are stored in UTC internally. At delivery time, we convert to the relevant local times for the notification content and make delivery decisions based on the traveler's current zone. This means we need to track or infer where the traveler is, which we do through their most recent activity location and their trip itinerary.

## Quiet hours enforcement

![Supporting diagram](https://pics.nowah.xyz/website-media/infrastructure-008-img-2.webp)

Quiet hours are user-configurable. By default, we suppress non-critical notifications between 10 PM and 7 AM in the traveler's local time. Travelers can adjust this window.

The implementation is straightforward in concept and annoying in practice. When a notification is ready to deliver, we check:

1. What is the traveler's current time zone?
2. What is their local time right now?
3. Is it within their quiet hours window?
4. What is the notification's priority level?

If it's quiet hours and the notification is time-sensitive, we hold it and schedule delivery for the end of the quiet window. If it's informational or promotional, we delay it further to a calculated optimal delivery time (usually mid-morning local time).

If it's critical, we send it regardless. You don't suppress a gate change notification because it's midnight. The traveler has a flight, they need to know.

The annoying part is edge cases. Travelers who cross time zones mid-trip. Quiet hours that span midnight (10 PM to 7 AM crosses the date boundary). Travelers who haven't set a time zone explicitly so we're inferring from their IP or phone locale. Each of these requires careful handling to avoid either over-suppressing (missing an important notification) or under-suppressing (waking someone up for a fare sale).

## Scheduling future notifications

When a booking is confirmed, we schedule several notifications for future delivery.

A 24-hour departure reminder gets enqueued with a "deliver at" timestamp calculated from the departure time minus 24 hours. A 2-hour reminder does the same. A check-in notification gets scheduled based on the airline's check-in window, typically 24 hours before departure.

These scheduled jobs sit in the queue until their delivery time. The queue infrastructure handles the delay internally, holding the job and releasing it to a worker when the scheduled time arrives.

There's a catch with scheduled notifications: things change. The flight might get delayed. The traveler might cancel the trip. The departure time might shift. We need to be able to cancel or reschedule pending notifications when the underlying data changes.

We handle this by storing the scheduled job ID with the booking record. When a booking changes, we cancel the existing notification jobs and schedule new ones based on the updated data. This creates a tight coupling between booking state changes and notification scheduling, which we manage through the same event system that triggers post-booking jobs.

## Delivery reliability

For critical and time-sensitive notifications, delivery reliability matters enormously. A departure reminder that silently fails to deliver is unacceptable.

Our delivery pipeline works like this:

1. The notification job runs and attempts push notification delivery.
2. If push delivery succeeds (the device token is valid and the push service accepted the message), we log the delivery.
3. If push delivery fails (expired token, revoked permissions, service error), we retry with exponential backoff.
4. After push retries exhaust, we fall back to email delivery for critical notifications.
5. Delivery status is recorded in a NotificationLog for every attempt.

The NotificationLog is our audit trail. For any notification, we can see: when it was scheduled, when delivery was attempted, which channel was used, whether it succeeded, and if it failed, why.

We track delivery rate as a key metric. For booking confirmations, our target is above 99% successful delivery. For departure reminders, above 98%. Below these thresholds, we investigate.

## Measuring notification effectiveness

Sending notifications is only half the job. The other half is knowing whether they're actually useful.

We track three metrics:

**Delivery rate** is whether the notification reached the device. This is a technical metric about infrastructure reliability.

**Open rate** is whether the traveler saw and tapped the notification. This tells us about relevance and timing. A high delivery rate with low open rate means we're sending notifications that people don't care about, or we're sending them at the wrong time.

**Action rate** is whether the traveler did something after the notification. Tapped it, opened the app, completed the suggested action. This is the real measure of value.

We use these metrics to tune our scheduling algorithms. If departure reminders sent 2 hours before have a higher action rate than 24-hour reminders, we might adjust the default or make the 2-hour reminder more prominent. If promotional notifications sent on Tuesday mornings outperform Friday afternoons, we shift the delivery window.

## Building a notification scheduler

If you're building notification infrastructure for a travel platform, here's the minimal viable setup.

Store all times in UTC. Convert to local time only at the moment of delivery or display. Never store local times in your database.

Implement quiet hours from day one. Getting this wrong early means training users to distrust your notifications. Once they mute you, they don't come back.

Use a priority system, even a simple one. At minimum, distinguish between "must deliver now" and "can wait." You can add more granularity later.

Track delivery status for every notification. You need to know when things fail. Without a delivery log, failed notifications are invisible, and invisible failures are the worst kind.

Test across time zones. Your server is probably in UTC. Your developers are probably in one time zone. Your travelers are everywhere. Test what happens when a traveler in Tokyo gets a notification scheduled by a server that thinks in UTC. The bugs are always in the time zone math.

---

Nowah is an AI travel agent that searches and books real flights and hotels through conversation — no filters, no thirty open tabs. [Plan your next trip](https://app.nowah.xyz).
