|
| 1 | +# Best Practices |
| 2 | + |
| 3 | +Push notifications can help drive engagement, increase player retention, and build habit loops for players—all good things for your game. The examples below are from [Syllo](https://www.reddit.com/r/syllo/), a word game that integrated Push Notifications into the game experience. |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | +This guide provides instructions for implementing developer-authored push notifications for Reddit games. |
| 8 | + |
| 9 | +:::note |
| 10 | +This is currently an experimental feature, and you'll need to [apply](https://docs.google.com/forms/d/e/1FAIpQLScB3eXHVCBf3kyHueyf3G_raxH9_BsCGiXyGjQOOmPxWz6fEg/viewform?usp=publish-editor) for a spot in our beta program to implement push notifications in your app. |
| 11 | +::: |
| 12 | + |
| 13 | +## How it works |
| 14 | + |
| 15 | +### Push notification copy review |
| 16 | + |
| 17 | +All push notifications in this Beta must be pre-approved by Devvit admins to ensure alignment with Reddit’s notification standards and content policy (see [Effective Copy](#write-effective-copy) for tips\!). |
| 18 | + |
| 19 | +The Devvit team will review and approve all submissions before activation to ensure a safe and consistent experience across games. |
| 20 | + |
| 21 | +Notifications should be: |
| 22 | + |
| 23 | +- **Time-sensitive or highly important** (e.g., a new puzzle is available, a live event is starting, a challenge has ended). |
| 24 | +- **Respectful and Reddit-appropriate**, avoiding spammy, click-bait, or overly promotional language. |
| 25 | +- **Short and clear** — titles ≤ 60 characters, body ≤ 100 characters. |
| 26 | +- **Transparent** about the context of the notification (what the user will see when they tap). |
| 27 | + |
| 28 | +You can send a maximum of two push notifications per day per user. |
| 29 | + |
| 30 | +### Opt-in / opt-out UX |
| 31 | + |
| 32 | +Push notifications are opt-in only. and this is enforced at the API level. In the future, additional opt-out controls will also be available in Reddit settings. |
| 33 | + |
| 34 | +Games must provide an in-game notifications control that: |
| 35 | + |
| 36 | +- Allows users to explicitly turn notifications on and off |
| 37 | +- Clear text indicating the user’s current state (on or off) on the initial screen |
| 38 | + |
| 39 | +#### UX best practices |
| 40 | + |
| 41 | +- Use Reddit’s notification-on and notification-off icons |
| 42 | +- Clearly indicate if game notifications are on or off |
| 43 | +- Always provide an easy way to toggle on or off notifications from your initial app view or a settings page |
| 44 | +- Show visual confirmation of actions, like adding a “Notifications enabled” toast or change to the button styling |
| 45 | + |
| 46 | +#### Component examples |
| 47 | + |
| 48 | + |
| 49 | + |
| 50 | +## Designing high-quality notifications |
| 51 | + |
| 52 | +Push notifications are most effective when strong content and strong copy work together. High-quality messages start with meaningful in-game events and use clear, motivating language to bring that value to life. |
| 53 | + |
| 54 | +### Create meaningful events |
| 55 | + |
| 56 | +Your push notifications should deliver clear, immediate value to players. |
| 57 | + |
| 58 | +- **Make player progress visible**. Streaks make player progress tangible and gives players a clear, low-effort goal: show up, keep the streak alive, and continue progressing. **Make sure to include the number of days in the streak**. This makes the player’s progress concrete and strengthens their motivation to return to keep it going. |
| 59 | + |
| 60 | + |
| 61 | + |
| 62 | +- **Provide tangible player benefits**. Tie notifications to real outcomes, like rewards ready to claim, streak milestones, live games, or limited-time challenges. Give the user a clear payoff for returning to the game. High-value events drive high conversion. If there’s no clear payoff, it’s better not to send the notification at all. |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | +- **Layer urgency onto broadly relevant moments**. Create momentum by promoting events that are time-sensitive (“happening now” or “ending soon”) and matter to a wide audience, like a daily puzzle going live or the final hour of a tournament. |
| 67 | + |
| 68 | + |
| 69 | + |
| 70 | +- **Treat pushes as a limited resource**. Use notifications selectively for moments where value is obvious at a glance, like completing a weekly challenge, collecting a reward, joining a live match, or entering a newly unlocked mode. These are the moments most likely to drive immediate play and long-term retention. |
| 71 | + |
| 72 | +### Optimize timing |
| 73 | + |
| 74 | +Send push notifications when players are most likely to engage with your game. |
| 75 | + |
| 76 | +- **Localize delivery by user time zone** |
| 77 | + |
| 78 | + - Schedule sends using the player’s local time, not a single global batch time. |
| 79 | + - Treat night-time sends as disallowed by default; players are more likely to mute or opt out if they’re woken up or interrupted late. |
| 80 | + |
| 81 | +- **Aim for late afternoon to early evening** |
| 82 | + |
| 83 | + - Platform data shows peak PN opens in late afternoon and early evening by GEO. Use this as the default window if you don’t have game-specific signals. |
| 84 | + - Start with a conservative window like **16:00–21:00 local time**, then refine based on your game’s metrics (CTR and disable rates). |
| 85 | + |
| 86 | +- **Align timing to moments of natural intent** |
| 87 | + |
| 88 | + - For streak reminders, send close to when players typically play (e.g., a few hours before their usual daily play time), not as a “last second” midnight panic. |
| 89 | + - For event and reward PNs, send: |
| 90 | + - Shortly before the value becomes available (e.g., event starting soon, reward about to unlock), or |
| 91 | + - When the value is immediately redeemable and you can deeplink straight into the relevant screen. |
| 92 | + - Avoid “just because it’s morning” or daily cron-style sends; timing should always correspond to a clear in-game reason to come back right now. |
| 93 | + |
| 94 | +- **Use timing metrics to iterate** |
| 95 | + - Track **CTR by hour-of-day and day-of-week** in local time buckets for your game. |
| 96 | + - Watch **notification disable rates** after bursts of sends; spikes usually mean you’re hitting players at the wrong time (too early, too late, or too often). |
| 97 | + - If you don’t have enough volume for fine-grained experiments, stick to: |
| 98 | + - No night-time delivery |
| 99 | + - Late afternoon/evening windows |
| 100 | + - Only sending when a concrete, time-bound value is available (streak, event, reward). |
| 101 | + |
| 102 | +### Write effective copy {#write-effective-copy} |
| 103 | + |
| 104 | +Push notifications act as **motivational nudges** that get to the crux of why users are playing your game. Here are some ways you can incorporate these nudges into your game. |
| 105 | + |
| 106 | +- **Add behavioral triggers**. Behavioral triggers respond to real user actions, like completing tasks, returning after a break, or reaching milestones. This makes each message feel timely and personal. Examples might include: |
| 107 | + |
| 108 | + - “You’re 1 game away from finishing your weekly challenge\!” |
| 109 | + - “You were in the top 5% last week—can you do it again?” |
| 110 | + - “You have 2 new puzzles waiting for you\!” |
| 111 | + |
| 112 | +- **Engage with social dynamics**. Highlighting status changes and community milestones inspire connection and friendly competition. Examples might include: |
| 113 | + |
| 114 | + - “Your team just moved up a division\! Jump in to keep the momentum going\!” |
| 115 | + - “Someone just stole your place on the leaderboard. Want it back?” |
| 116 | + |
| 117 | +- **Leverage personal motivation.** The user’s history with the game reinforces progress. Examples might include: |
| 118 | + - “Your crops are thriving\! Come collect your rewards\!” |
| 119 | + - “You’re close to genius rank\! Solve 3 more puzzles to claim your crown\!” |
| 120 | + - “You’re one mission away from unlocking your next rank\! Time to jump back into action\!” |
| 121 | + |
| 122 | +To learn more about creating deeper engagement loops, check out the best practices for [building community games](https://developers.reddit.com/docs/guides/best-practices/community_games). |
| 123 | + |
| 124 | +## Adding push notifications to your app |
| 125 | + |
| 126 | +### Step 1: Update the push notification module |
| 127 | + |
| 128 | +In your terminal, navigate to your project directory and run this command to update the push notification to the latest release. |
| 129 | + |
| 130 | +``` |
| 131 | +npm install @devvit/notifications |
| 132 | +``` |
| 133 | + |
| 134 | +### Step 2: Import the push notification module |
| 135 | + |
| 136 | +``` |
| 137 | +import { notifications } from '@devvit/notifications'; |
| 138 | +``` |
| 139 | + |
| 140 | +**Note**: If you already have the PN module, enter |
| 141 | +`npm install @devvit/notifications@next` to get the latest version. |
| 142 | + |
| 143 | +### Step 3: Use bulk push notification endpoint with templating |
| 144 | + |
| 145 | +To send a push notification to a group of users, you can use the double curly brackets ( { { } } ) to reference variables in a Mustache template. |
| 146 | + |
| 147 | +``` |
| 148 | +await notifications.enqueue({ |
| 149 | + title: 'Hello {{name}}!', |
| 150 | + body: 'You have {{score}} new points.', |
| 151 | + recipients: [ |
| 152 | + { |
| 153 | + userId: 't2_abc123', |
| 154 | + link: 't3_xyz987', |
| 155 | + data: { |
| 156 | + name: 'Alex', |
| 157 | + score: '42', |
| 158 | + }, |
| 159 | + }, |
| 160 | + { |
| 161 | + userId: 't2_def456', |
| 162 | + link: 't3_xyz987', |
| 163 | + data: { |
| 164 | + name: 'Jordan', |
| 165 | + score: '7', |
| 166 | + }, |
| 167 | + }, |
| 168 | + { |
| 169 | + userId: 't2_ghi789', |
| 170 | + link: 't3_xyz987', |
| 171 | + data: { |
| 172 | + name: 'Sam', |
| 173 | + score: '13', |
| 174 | + }, |
| 175 | + }, |
| 176 | + ], |
| 177 | +}); |
| 178 | +``` |
| 179 | + |
| 180 | +**Note:** Mustache templating is optional. Here's a simplified example without it: |
| 181 | + |
| 182 | +``` |
| 183 | +await notifications.enqueue({ |
| 184 | + title: 'Winner!', |
| 185 | + body: 'Congrats on your win', |
| 186 | + recipients: [ |
| 187 | + { |
| 188 | + userId: 't2_abc123', |
| 189 | + link: 't3_xyz987', |
| 190 | + }, |
| 191 | + ], |
| 192 | +``` |
| 193 | + |
| 194 | +**Note**: If the app hasn’t been published, you can only send push notifications to yourself for testing. **Pre-release apps in testing are not subject to the rate-limits below**. |
| 195 | + |
| 196 | +Once your app is published, you can pass different data per user for the same template. For each app, you can send: |
| 197 | + |
| 198 | +- 2 push notifications per user per day\* |
| 199 | +- Up to 25K per app per day |
| 200 | + |
| 201 | +If you need higher limits, let us know. |
| 202 | + |
| 203 | +### Step 4: opt-in / opt-out |
| 204 | + |
| 205 | +Users will be able to opt in or out of receiving notifications triggered by a button in your UI: |
| 206 | + |
| 207 | +``` |
| 208 | +await notifications.optInCurrentUser(); |
| 209 | +await notifications.optOutCurrentUser(); |
| 210 | +``` |
| 211 | + |
| 212 | +You will also be able to retrieve a list of users who have opted in (if not managing it manually): |
| 213 | + |
| 214 | +``` |
| 215 | +//This will just return the first 1000 users |
| 216 | +const recipients = await notifications.listOptedInUsers(); |
| 217 | +
|
| 218 | +const recipients = await notifications.listOptedInUsers({ |
| 219 | + after: '1764876078573:t2_ltrlsg7l', |
| 220 | + limit: 100, |
| 221 | +}); |
| 222 | +``` |
| 223 | + |
| 224 | +The default and maximum limit is 1,000. |
| 225 | + |
| 226 | +Usernames are returned in chronological order according to opt-in time, starting after the specified cursor. If the cursor is not found, results begin from the earliest opt-in time. |
0 commit comments