Notification Flows
A notification flow maps what happens between a system event and a (possibly) informed user: trigger → decision (notify at all?) → channel selection → delivery → user action → dismissal/preference loop. This file maps the DECISION TREE each event runs through; the evidence (interruption cost, platform permission rules, email law, badge etiquette) lives in Notifications & Communication. The core reframe: a notification is not a message you send, it's a flow every event must EARN its way through — and most events should exit at the first gate.
The per-event decision tree
Run every event type through this tree at design time and record the answers in a notification matrix (event × decision × channel × cap). If the team can't fill the row, the event doesn't ship a ping.
System event occurs
→ GATE 1: Should this notify AT ALL?
├─ user explicitly asked to be told (order shipped, mention,
│ security alert) → continue
├─ product wants attention (streak, promo, "we miss you")
│ → default NO; if kept, marketing category, strict caps
└─ system bookkeeping (sync done, minor state change)
→ NO ping → in-product status only
→ GATE 2: Now, or batched?
├─ time-critical (human waiting, security, delivery at door)
│ → real-time
├─ useful soon → batch window ("5 new comments", hourly roll-up)
└─ useful eventually → digest branch (daily/weekly, user-chosen)
→ GATE 3: Quiet hours / Focus?
├─ inside recipient's quiet hours + not critical → HOLD until
│ window opens (don't drop, don't fire at 3am)
└─ critical (security, fraud) → deliver anyway, say why
→ GATE 4: Frequency cap reached? (per category AND global)
├─ over cap → collapse into existing thread/summary or drop
└─ under → continue
→ GATE 5: Channel selection (urgency × context × consent)
├─ user currently IN APP → in-app surface, no push
├─ push opted-in → push (deep link required)
├─ push not granted/denied → email if consented
├─ needs a findable record (receipt, confirmation) → email
│ REGARDLESS of push (channels are jobs, not fallbacks only)
└─ SMS → highest urgency + explicit SMS consent only
→ Delivery → user response
├─ opens → DEEP LINK to the exact object → mark handled
│ everywhere (badge cleared, email thread updated, other
│ devices synced — one read = read everywhere)
├─ dismisses → count it; repeated dismissals of a category
│ = signal → auto-offer down-shift for that category
├─ ignores → do NOT re-send the same ping; at most one
│ escalation for critical items, via a DIFFERENT channel
└─ long-press/settings → per-category preference controls
(one tap from the notification itself)
Worked example: "Processing complete"
Export finishes rendering
→ notify? user started a job and left — YES (they asked)
→ now or batch? single awaited result → now
→ quiet hours? respect; hold if asleep (result isn't perishable)
→ channel: user in app? → inline "Done" toast + result link
else push opted-in? → push "Your export is ready"
else → email with the file/link (also send email anyway if
the artifact should be re-findable later)
→ user opens → deep-link STRAIGHT to the result (not the home
screen, not a list they must search)
→ mark handled: badge cleared, in-app indicator cleared, the
email's job done — no follow-up "did you see your export?"
Preference management — a first-class route
The preferences flow deserves the same rigor as the sending flow, because it's the pressure-release valve that keeps users from the nuclear option (OS-level block, spam report):
Any notification → "Manage notifications" (one tap, no hunting)
→ per-category toggles in user language (orders, mentions, tips,
promos) — mirrored across push AND email
→ per-category cadence: real-time / batched / daily digest / off
→ quiet hours (where the OS doesn't provide them: web, email)
→ pause all (30 days) as an alternative to off
→ mute changes honored EVERYWHERE immediately, and never
programmatically re-enabled (Android channels enforce this;
replicate the contract on iOS/web/email)
The failure path: the opt-out spiral
Map the failure path explicitly, because it's where notification systems actually die. Each low-value ping raises the odds the user doesn't just dismiss but disables — and users disable CHANNELS, not messages: one promo too many kills the push channel that your security alerts and shipping updates also ride on. The spiral: low-value ping → dismiss → more pings → mute category (if you're lucky and offer it) → OS-level block / unsubscribe-as-spam-report → critical messages now undeliverable → product invents NEW channels (email more, badge more) → those die too. Instrument the spiral: opt-out, block, and complaint rates per category are first-class health metrics, and the designed response to falling engagement is fewer, better messages — never more (the Gmail/Yahoo 0.3% spam-complaint ceiling makes this survival, not taste; see Notifications & Communication).
Common mistakes
- No Gate 1: every event type ships with a push "to be safe."
- Channel fallback logic only (push→email) with no channel-job logic (receipts need email even when push succeeds).
- Deep links to the app home instead of the triggering object.
- Read-state not synced: user handles it on phone, badge lives on forever on tablet (trains badge blindness).
- Re-sending ignored notifications on the same channel.
- Preferences buried in settings instead of one tap from the notification; category mutes that don't apply to email.
- No caps, no quiet hours, no digest branch — the spiral, scheduled.
Checklist
- Notification matrix: every event × gates 1–5 answered in writing
- Gate 1 defaults to NO for product-initiated (non-user-requested) events
- Batch/digest branch exists and is user-selectable per category
- Quiet hours in recipient's timezone; critical-override rule written down
- Frequency caps per category and global; collapse behavior defined
- Channel-by-job mapping (in-app / push / email / SMS) with consent state per channel
- In-app presence suppresses push for the same event
- Every notification deep-links to the exact object
- Handled-everywhere sync: one read clears all surfaces
- Escalation (if any) is once, cross-channel, critical-only
- Preference route one tap from any notification; mutes honored across channels
- Opt-out spiral instrumented: opt-out/block/complaint rates per category
- Permission ask mapped as moment-of-need branch (Onboarding Flows)
- Walked against Flow Design Checklists
Sources
- Notifications & Communication — the evidence base this file's decision tree operationalizes, including: Android 13+ POST_NOTIFICATIONS opt-in and notification channels (developer.android.com); Apple provisional authorization and permission guidance (developer.apple.com); Mark, Gudith & Klocke (CHI 2008) and Iqbal & Horvitz (CHI 2007) on interruption cost; Pielot et al. (MobileHCI 2014) on notification volume; Gmail/Yahoo bulk-sender rules (2024) and RFC 8058 one-click unsubscribe.
- Cross-references: Decision Flow (branch-logic notation), Onboarding Flows (permission priming as a flow branch), Checkout Flows (abandoned-cart recovery as a capped loop), Attention, Scanning & Perception (alert fatigue).