Implementing AI Optimization of Notification Send Time in Mobile Application
Marketer schedules send for 10:00 Monday — "business hours, everyone's awake". Half audience in different timezone, third wakes at 7:00 AM already swamped with tasks. One notification at right time for specific user works better than ten at "universal" time.
What Optimal Send Time Really Is
Task: for each user predict what time of day they're most likely to open a notification. Classic regression/classification on time series with historical open data.
Input features for model:
- History of notification opens with timestamp (last 90 days)
- Day of week and hour for each open
- Notification content type (transactional, marketing, editorial)
- Device timezone
- Last activity time in app
Target variable: probability of open for each hourly slot (24 hours × 7 days = 168 binary classifiers, or one multiclass).
Solution Architecture
Minimal variant without ML: heuristic based on aggregated stats. For each user build histogram of opens by hour. Optimal time = hour with most opens in last 30 days. Works, needs no ML infrastructure, deployed in 1–2 weeks.
ML variant: segment or individual user level model.
For segments (if little per-user data): cluster users by activity patterns via K-Means or DBSCAN. Clusters like "early birds" (active 6:00–9:00), "office hours" (12:00–13:00, 18:00–20:00), "night owls" (21:00–00:00). Each cluster gets its optimal send time.
Individual prediction: LightGBM with temporal features. Daily batch training, inference at send task scheduling.
Cold Start: Few User Data Points
New user — no open history. Fallback strategy:
- First 7 days: send at average optimal time for segment (determine by timezone, platform, device type)
- 7–30 days: switch to individual pattern once 10+ events accumulated
- 30+ days: full individual optimization
Implemented via feature flag in feature store: user:{id}:send_time_model = "cohort" | "individual", updates automatically at threshold crossing.
Technical Send Pipeline
- Marketer creates campaign in CMS with
send_time = "optimal"parameter - Campaign launch — instead of immediate send, tasks scattered in queue with delayed timing
- For each user:
optimal_hour = get_optimal_send_time(user_id)→ task queued in Bull Queue with delay until next optimal slot (today or tomorrow) - Worker sends push at right time
Limitation: "next optimal slot" might be tomorrow. For time-sensitive campaigns set max_delay = 24h — if optimal today passed, send tomorrow; if tomorrow too — next available within week.
Frequency Capping
Related task: don't overload user regardless of optimal time. Best practice — max 2–3 marketing notifications/week per user.
Implemented via Redis: INCR user:{id}:push_count:{week} on each send, EXPIRE at week end. Before queuing — check counter.
Combination of optimal send time + frequency cap + relevance scoring (from AI-personalization) — full-fledged push notification intelligence system.
Monitoring and Feedback
Metrics to track constantly:
- CTR lift vs baseline (random or fixed time)
- Send distribution by hour — no anomalous peaks
- Coverage: how many users have enough data for individual prediction
Dashboard in Grafana or Metabase with daily updates. Model degradation (CTR drop) — trigger for retrain or feature revision.
Implementation Timeline
| Variant | Description | Timeline |
|---|---|---|
| Heuristic | Histogram from history + Bull Queue | 1–2 weeks |
| ML segments | Clustering + optimal per cluster | 3–5 weeks |
| Individual ML | LightGBM per-user + feature store + A/B | 8–12 weeks |
Cost calculated after analyzing current notification system and audience size.







