Claude
Skills
Sign in
Back

push-notification-best-practices

Included with Lifetime
$97 forever

Comprehensive mobile push notification guide for iOS (APNS) and Android (FCM). Use when setting up push notifications, debugging delivery issues, implementing background/foreground handlers, managing push tokens, integrating deep linking, or troubleshooting platform-specific issues.

General

What this skill does


# Push Notification Best Practices

## Overview

Comprehensive guide for implementing and troubleshooting push notifications in mobile applications. Covers iOS (APNS), Android (FCM), React Native, Expo, and Flutter platforms with platform-specific configurations, token management, message handling, and deep linking patterns.

## Platform Support Matrix

| Platform | Offline Push | Notification Bar | Click Navigation | In-App Toast | Background Handler |
|----------|--------------|------------------|------------------|--------------|-------------------|
| iOS | APNS | System | Deep Link | Custom | data-only payload |
| Android | FCM | System | Intent | Custom | data-only payload |
| React Native | APNS/FCM | System | React Navigation | Custom | setBackgroundMessageHandler |
| Expo | Expo Push | System | Linking | Custom | TaskManager |
| Flutter | APNS/FCM | System | Navigator | Custom | onBackgroundMessage |

## Decision Trees

### Permission Request Timing

**When to request notification permission?**

```
User installing app
        |
        v
  [First launch?] ──Yes──> [Show value proposition first]
        |                          |
        No                         v
        |                  [User action triggers need?]
        v                          |
  [Already granted?]              Yes
        |                          |
       Yes                         v
        |                  [Request permission] ──> 70-80% acceptance rate
        v
  [Notifications ready]
```

| Timing | Acceptance Rate | Use Case |
|--------|-----------------|----------|
| Immediate (app launch) | 15-20% | Low engagement apps |
| After onboarding | 40-50% | Standard apps |
| User-initiated action | 70-80% | High engagement apps |

**Recommendation:** Request after explaining value or when user enables a related feature.

### Silent vs Visible Notification

**Which payload type should I use?**

```
[What's the purpose?]
        |
        +──> Time-sensitive user alert ──> Visible (notification payload)
        |
        +──> Background data sync ──> Silent (data-only payload)
        |
        +──> Custom UI required ──> Silent (data-only payload)
        |
        +──> Need background processing ──> Silent (data-only payload)
```

| Scenario | Payload Type | Reason |
|----------|--------------|--------|
| New message alert | Visible | User needs immediate attention |
| Order status update | Visible | Time-sensitive information |
| Background sync | Silent | No user interruption needed |
| Custom notification UI | Silent | Full control over display |
| Update badge count | Silent | Background processing needed |

### Extension Strategy (iOS)

**When to use Notification Service Extension?**

- Need to modify notification content before display
- Need to download and attach media (images, videos)
- Need to decrypt end-to-end encrypted payloads
- Need to add action buttons dynamically

**When to use Notification Content Extension?**

- Need custom notification UI beyond system template
- Need interactive elements in expanded view

## Anti-patterns (NEVER Do)

### Permission Handling

| NEVER | Why | Instead |
|-------|-----|---------|
| Request permission on first launch without context | 15-20% acceptance rate | Explain value first, then request |
| Re-ask after user denies | System ignores repeated requests | Show settings redirect |
| Ignore provisional authorization | Misses iOS 12+ quiet delivery | Use `.provisional` option |

### Token Management

| NEVER | Why | Instead |
|-------|-----|---------|
| Cache tokens long-term | Tokens can change on reinstall/restore | Always use fresh token from callback |
| Assume token format | Format varies by platform/SDK | Treat as opaque string |
| Send token without user association | Can't target notifications | Associate with userId on backend |
| Store tokens without device ID | Duplicate tokens per user | Use deviceId as unique key |

### Message Handling

| NEVER | Why | Instead |
|-------|-----|---------|
| Use `notification` payload for background processing | onMessageReceived not called in background | Use data-only payload |
| Rely on silent notifications for time-critical delivery | Delivery not guaranteed | Use visible notifications |
| Execute heavy operations in background handler | System kills app after ~30 seconds | Queue work, process quickly |
| Forget to handle both payload types | Missing notifications | Handle notification + data payloads |

### iOS Specific

| NEVER | Why | Instead |
|-------|-----|---------|
| Register for notifications before delegate setup | Delegate methods not called | Set delegate before `registerForRemoteNotifications()` |
| Skip `serviceExtensionTimeWillExpire()` implementation | Content modification fails | Always implement fallback |
| Use .p12 certificates | Expires yearly, deprecated | Use .p8 authentication key |

### Android Specific

| NEVER | Why | Instead |
|-------|-----|---------|
| Skip NotificationChannel creation | Notifications don't appear on Android 8.0+ | Create channel at app start |
| Use priority `normal` for background handlers | Doze mode blocks delivery | Use priority `high` |
| Use colored notification icons | Android ignores colors, shows white square | Use white-on-transparent icons |

## Skill Format

Each rule file follows a hybrid format for fast lookup and deep understanding:

- **Quick Pattern**: Incorrect/Correct code snippets for immediate pattern matching
- **When to Apply**: Situations where this rule is relevant
- **Deep Dive**: Full context with step-by-step guides and platform-specific details
- **Common Pitfalls**: Common mistakes and how to avoid them
- **Related Rules**: Cross-references to related patterns

**Impact ratings**: CRITICAL (fix immediately), HIGH (significant improvement), MEDIUM (worthwhile optimization)

## When to Apply

Reference these guidelines when:
- Setting up push notifications in a mobile app
- Debugging push notification delivery issues
- Implementing background notification handlers
- Integrating deep linking with push notifications
- Managing push tokens and device registration
- Troubleshooting platform-specific push issues
- Reviewing push notification code for reliability

## Priority-Ordered Guidelines

| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | iOS Setup | CRITICAL | `ios-` |
| 2 | Android Setup | CRITICAL | `android-` |
| 3 | Token Management | HIGH | `token-` |
| 4 | Message Handling | HIGH | `message-` |
| 5 | Deep Linking | MEDIUM | `deeplink-` |
| 6 | Infrastructure | MEDIUM | `infra-` |

## Quick Reference

### Critical: iOS Setup

**Setup checklist:**
- Generate APNs authentication key (.p8) from Apple Developer
- Upload to Firebase Console with Key ID and Team ID
- Enable Push Notifications capability in Xcode
- Set UNUserNotificationCenter delegate in didFinishLaunchingWithOptions
- Request notification authorization before registering
- Implement foreground presentation options

### Critical: Android Setup

**Setup checklist:**
- Add google-services.json to app/ directory
- Apply google-services Gradle plugin
- Create NotificationChannel (Android 8.0+)
- Request POST_NOTIFICATIONS permission (Android 13+)
- Implement FirebaseMessagingService
- Set notification icon (transparent background + white)
- Use priority 'high' for Doze mode compatibility

### High: Token Management

**Token lifecycle:**
```javascript
// 1. Register token with server
const token = await getToken();
await registerToken(token, userId);

// 2. Handle token refresh
onTokenRefresh((newToken) => {
  updateTokenOnServer(newToken, userId);
});

// 3. Handle invalidation
if (error.code === 'DeviceNotRegistered') {
  deleteTokenFromDatabase(token);
}
```

### High: Message Handling

**Payload types:**
- **data-only**: Background handler runs on both platforms
- **notification + data**: iOS/Android behavior differs
  - iOS: Always shows notification
  - Android: Backgroun

Related in General