npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

expo-rich-notifications

v0.1.0

Published

Zero-config rich notifications, communication notifications, and action buttons for Expo

Readme

expo-rich-notifications

npm version license platform - ios

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-notifications

Quick 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:ios

That'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": 1 for 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:

  1. The enableCommunicationNotifications plugin option (enabled by default)
  2. senderName in the push payload
  3. The Communication Notifications capability in your provisioning profile (Apple Developer Portal)

Apple Developer Setup

  1. Go to Apple Developer Portal
  2. Select your App ID
  3. Enable Communication Notifications capability
  4. 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 image URL is publicly accessible (HTTPS)
  • Check that the image URL returns a valid image (JPG, PNG, GIF)

Communication style not working

  • Ensure senderName is 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 category in the push payload matches a registered category identifier
  • Verify categories are registered via initRichNotifications() or registerCategories()

Extension not running

  • Run npx expo prebuild --clean to regenerate the iOS project
  • Verify the NotificationServiceExtension target 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