# Push Notifications That Engage Instead of Annoy

Practical push notification best practices for developers — opt-in strategy, timing, frequency caps, copy that converts, and deep links that actually work.

Author: The Tappd Team · Engineering at Tappd
Date: 2026-06-18
Category: Guides
Canonical URL: https://tappd.io/blog/push-notification-best-practices

Push notifications are the most direct line you have to a user who isn't in your app. They're also the easiest channel to abuse. One too many irrelevant pings and people disable notifications — or delete the app.

This guide covers the practices that separate useful push from noise, from a developer's perspective: when to ask for permission, how to time and cap sends, how to write copy that earns opens, and how to land users in the right place when they tap.

## Ask at the right moment, not the first screen

The iOS permission dialog is a one-time ask. If the user taps "Don't Allow," you're locked out until they manually re-enable in Settings — and almost nobody does.

**The pre-prompt pattern:**

1. User completes a valuable action (saves an item, creates an account, follows a topic).
2. You show a custom in-app screen: "Want to know when [specific thing] happens?"
3. Only if they tap "Yes" do you trigger the OS permission dialog.

On Android 13+ and web, the permission model is slightly more forgiving, but the principle holds: explain the value before you ask.

**What to promise in the pre-prompt:**

- "Get notified when your order ships"
- "Know when someone replies to your post"
- "Reminders before your trial ends"

**What not to promise:**

- "Stay up to date with our latest news"
- "Never miss out on great deals"

Specific beats generic every time.

## Segment before you send

The fastest way to burn a push channel is broadcasting the same message to your entire user base.

At minimum, segment by:

- **Lifecycle stage** — new users need onboarding nudges; active users need feature discovery; dormant users need a reason to return.
- **Consent and preferences** — only send promotional push to users who opted in for marketing. Transactional push (order updates, security alerts) is a separate channel with different rules.
- **Recent engagement** — if someone opened your last three pushes but didn't act, change the message or stop sending. Repeating the same CTA is how you train people to ignore you.

Behavioral segments update as events stream in. A user who was active yesterday and abandoned a cart today should get a different message than someone who hasn't opened the app in 30 days.

## Timing and frequency caps

**Timezone-aware delivery.** Store the user's timezone (or infer it from device/locale) and schedule sends for their local morning or evening — not yours.

**Quiet hours.** Default to no promotional push between 10 PM and 8 AM local time. Transactional and security alerts are exceptions.

**Frequency caps.** Set hard limits per channel:

| Channel type | Suggested cap |
|---|---|
| Promotional / marketing | 2–3 per week |
| Transactional (orders, alerts) | Unlimited, but batch when possible |
| Re-engagement | 1 per dormancy window, then stop |

If a user hasn't opened any of your last five pushes, remove them from promotional sends until they re-engage organically. Continuing to send is wasted effort and increases uninstall risk.

## Write copy that earns the tap

Push real estate is tiny. On most devices, you get ~40 characters in the title and ~100 in the body before truncation.

**Title:** Lead with the value or the user's context.

```
Good:  "Your cart expires tonight"
Bad:   "Tappd — Don't forget your cart!"

Good:  "Alex replied to your comment"
Bad:   "New activity in your account"
```

**Body:** One sentence. One action. No filler.

```
Good:  "The Nike Air Max you saved is down 20%. Tap to checkout."
Bad:   "Hi there! We noticed you left some items in your cart. We think you'll love them. Shop now!"
```

**Personalization that matters:**

- Name (when you have it)
- Specific item, action, or person — not "your recent activity"
- Time sensitivity when real ("expires in 2 hours", not "limited time offer")

**Avoid:**

- ALL CAPS and multiple exclamation marks
- Vague curiosity gaps ("You won't believe what happened")
- Emoji overload (one is fine; five is spam)
- Leading with your brand name (the OS already shows it)

## Deep links are non-negotiable

Every push should deep link to the exact screen the message references. Landing on the home screen after a push about a specific order is a broken promise.

**Checklist for every push campaign:**

- [ ] Tap target opens the correct screen on iOS
- [ ] Tap target opens the correct screen on Android
- [ ] Tap target opens the correct screen on web (if applicable)
- [ ] Fallback behavior if the app isn't installed (web URL or app store link)
- [ ] Cold-start handling — app opens to the right state, not a loading screen

Test on a physical device, not just the simulator. Universal links and app links have edge cases that only show up in production.

## Rich push when it adds context

Images, action buttons, and expanded layouts can lift open rates — but only when the visual adds information the text can't.

**Good use of rich push:**

- Product image on a cart-abandonment reminder
- Map thumbnail on a delivery update
- Action buttons ("Track order" / "View receipt") on a transactional push

**Bad use of rich push:**

- Generic brand banner on a promotional blast
- Stock photo that has nothing to do with the message content

On Android, use notification channels to let users control categories independently (orders vs social vs marketing). On iOS, category identifiers enable action buttons.

## Measure beyond opens

Open rate tells you if the copy worked. It doesn't tell you if the push was worth sending.

For every campaign, track:

| Metric | What it tells you |
|---|---|
| Open rate | Copy and timing effectiveness |
| Click-through rate (action button) | CTA clarity |
| Conversion rate (downstream event) | Whether the push changed behavior |
| Opt-out / disable rate | Whether you're over-messaging |
| Uninstall rate (within 24h of send) | Whether you crossed a trust line |

Run holdout tests: send to 90% of a segment, withhold from 10%, compare 7-day retention. If there's no lift, the message isn't working — change the trigger, the copy, or stop sending.

## A practical starting checklist

If you're setting up push for the first time or auditing an existing program:

1. **Audit current opt-in rate** — what percentage of users have push enabled?
2. **Map your triggers** — list every automated push and what event fires it.
3. **Add frequency caps** — per channel, per user, per day/week.
4. **Review copy** — read every title out loud; cut anything that sounds like an ad.
5. **Test deep links** — tap every push on every platform.
6. **Set up holdout groups** — measure retention impact, not just opens.
7. **Define an exit rule** — stop sending to users who ignore N consecutive pushes.

Push is a privilege, not a right. Treat it that way and your open rates — and retention — will reflect it.

---

[All posts](https://tappd.io/blog) · [Tappd](https://tappd.io/)