UX Encyclopedia

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

↑↓ to navigate · Enter to open · Esc to close