expo-rich-notifications
v0.1.0
Published
Zero-config rich notifications, communication notifications, and action buttons for Expo
Maintainers
Readme
expo-rich-notifications
Zero-config rich notifications, communication notifications, and action buttons for Expo.
Features
- Rich Image Attachments — Show images when the notification is expanded
- Communication Notifications — Display sender avatar with iOS communication style
- Custom Action Buttons — Add interactive buttons to notifications
- Zero Config — Just add the plugin and it works. No Swift knowledge required
- Automatic NSE Setup — Creates the iOS Notification Service Extension during prebuild
Installation
npx expo install expo-rich-notifications expo-notificationsQuick Start
1. Add plugin to app config
// app.config.ts
export default {
plugins: [
'expo-notifications',
'expo-rich-notifications', // Zero config — just works!
],
};2. Initialize in your app
import { initRichNotifications } from 'expo-rich-notifications';
// Call once during app startup
await initRichNotifications();3. Prebuild and run
npx expo prebuild --clean
npx expo run:iosThat's it. Send a push notification with "mutable-content": 1 and an image URL in the payload, and you'll see a rich notification.
Custom Action Buttons
Plugin config
// app.config.ts
export default {
plugins: [
'expo-notifications',
['expo-rich-notifications', {
enableCommunicationNotifications: true, // default: true
categories: [
{
identifier: 'order_update',
actions: [
{ id: 'track', title: 'Track Order', opensApp: true },
{ id: 'dismiss', title: 'Dismiss', destructive: true },
],
},
{
identifier: 'message',
actions: [
{ id: 'reply', title: 'Reply', opensApp: true },
{ id: 'mark_read', title: 'Mark as Read' },
],
},
],
}],
],
};Handle action taps
import { initRichNotifications, addActionListener } from 'expo-rich-notifications';
await initRichNotifications({
categories: [
{
identifier: 'order_update',
actions: [
{ identifier: 'track', buttonTitle: 'Track Order', options: { opensAppToForeground: true } },
{ identifier: 'dismiss', buttonTitle: 'Dismiss', options: { isDestructive: true } },
],
},
],
});
const unsubscribe = addActionListener((actionId, notification) => {
switch (actionId) {
case 'track':
// Navigate to tracking screen
break;
case 'dismiss':
// Handle dismiss
break;
}
});
// Later: unsubscribe();Push Payload Format
The library reads these keys from the push notification payload (Extra Data / custom data):
| Key | Type | Required | Description |
|-----|------|----------|-------------|
| image | String (URL) | No | Rich notification image (shown when expanded) |
| senderName | String | No* | Sender display name (*required for communication style) |
| senderImage | String (URL) | No | Sender avatar URL (circular image) |
| senderIdentifier | String | No | Unique sender ID |
| conversationIdentifier | String | No | Thread grouping ID |
| category | String | No | Notification category ID (determines which action buttons show) |
Important: The APNs payload must include
"mutable-content": 1for the Notification Service Extension to fire.
Example Payloads
Rich Image Only:
{
"image": "https://cdn.example.com/photo.jpg"
}Communication Style (sender avatar):
{
"senderName": "John Doe",
"senderImage": "https://cdn.example.com/avatar.jpg",
"senderIdentifier": "user-123",
"conversationIdentifier": "chat-456"
}Rich + Communication + Action Buttons:
{
"image": "https://cdn.example.com/photo.jpg",
"senderName": "MyApp",
"senderImage": "https://cdn.example.com/app-icon.jpg",
"category": "order_update"
}Communication Notifications
Communication notifications show a sender avatar and are treated specially by iOS (Focus filters, notification summary). They require:
- The
enableCommunicationNotificationsplugin option (enabled by default) senderNamein the push payload- The Communication Notifications capability in your provisioning profile (Apple Developer Portal)
Apple Developer Setup
- Go to Apple Developer Portal
- Select your App ID
- Enable Communication Notifications capability
- Regenerate your provisioning profile
i18n / Localization
Use registerCategories() to update button titles after a language change:
import { registerCategories } from 'expo-rich-notifications';
await registerCategories([
{
identifier: 'order_update',
actions: [
{ identifier: 'track', buttonTitle: t('notifications.trackOrder') },
{ identifier: 'dismiss', buttonTitle: t('notifications.dismiss') },
],
},
]);Troubleshooting
Notification image not showing
- Ensure your APNs payload includes
"mutable-content": 1 - Verify the
imageURL is publicly accessible (HTTPS) - Check that the image URL returns a valid image (JPG, PNG, GIF)
Communication style not working
- Ensure
senderNameis included in the push payload - Enable Communication Notifications capability in Apple Developer Portal
- Regenerate your provisioning profile after enabling the capability
Action buttons not appearing
- Long-press (or swipe down) on the notification to see action buttons
- Ensure the
categoryin the push payload matches a registered category identifier - Verify categories are registered via
initRichNotifications()orregisterCategories()
Extension not running
- Run
npx expo prebuild --cleanto regenerate the iOS project - Verify the
NotificationServiceExtensiontarget exists in Xcode - Check that the extension target has proper signing (same team as main app)
API Reference
initRichNotifications(config?)
Initialize rich notifications. Call once during app startup.
| Parameter | Type | Description |
|-----------|------|-------------|
| config.categories | RichNotificationCategory[] | Notification categories with action buttons |
| config.onAction | (actionId, notification) => void | Callback for action button taps |
registerCategories(categories)
Register or update notification categories. Can be called multiple times (replaces existing).
addActionListener(callback)
Subscribe to action button taps. Returns an unsubscribe function.
Plugin Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| enableCommunicationNotifications | boolean | true | Enable communication notification entitlements |
| categories | PluginCategory[] | [] | Pre-defined notification categories (optional) |
License
MIT
