A Tauri v2 plugin for sending notifications on desktop and mobile platforms. Send toast notifications (brief auto-expiring OS window elements) with support for rich content, scheduling, actions, channels, and push delivery via FCM and APNs.
- Send simple and rich notifications
- Schedule notifications for specific dates or recurring intervals
- Interactive notifications with custom actions
- Notification channels (Android) for organized notifications
- Manage pending and active notifications
- Support for attachments, icons, and custom sounds
- Inbox and large text notification styles
- Group notifications with summary support
- Permission management
- Real-time notification events
- macOS: Native notification center integration
- Windows: Windows notification system
- Linux: notify-rust with desktop notification support
- iOS: User Notifications framework
- Android: Android notification system with channels
Install the JavaScript package:
npm install @choochmeque/tauri-plugin-notifications-api
# or
yarn add @choochmeque/tauri-plugin-notifications-api
# or
pnpm add @choochmeque/tauri-plugin-notifications-apiAdd the plugin to your Tauri project's Cargo.toml:
[dependencies]
tauri-plugin-notifications = "0.4"The push-notifications feature is disabled by default. To enable push notifications support:
[dependencies]
tauri-plugin-notifications = { version = "0.4", features = ["push-notifications"] }This enables:
- Firebase Cloud Messaging support on Android
- APNs (Apple Push Notification service) support on iOS
Note: Push notifications are currently supported on mobile platforms (iOS and Android) only. macOS and Windows support is not yet available.
Without this feature enabled:
- Firebase dependencies are not included in Android builds
- Push notification registration code is disabled
- The
registerForPushNotifications()function will return an error if called
The unified-push feature is disabled by default. UnifiedPush is a decentralized push notification protocol that allows apps to receive push notifications through various distributors (like NextPush, ntfy, etc.) instead of being locked into FCM or APNs.
To enable UnifiedPush support on Android:
[dependencies]
tauri-plugin-notifications = { version = "0.4", features = ["unified-push"] }Note: UnifiedPush is currently only supported on Android. It can be used alongside FCM or as a standalone push notification solution.
To enable both FCM and UnifiedPush:
[dependencies]
tauri-plugin-notifications = { version = "0.4", features = ["push-notifications", "unified-push"] }What is UnifiedPush?
UnifiedPush is an open standard for push notifications that gives users control over their notification delivery. Instead of relying solely on Google's FCM or Apple's APNs, apps can receive notifications through user-chosen distributors:
- NextPush - A UnifiedPush distributor with server-side support
- ntfy - Simple, self-hostable push notification service
- Other distributors - Any app implementing the UnifiedPush protocol
Benefits:
- User privacy - users choose their notification provider
- No Google Services dependency required
- Works with self-hosted solutions
- Open protocol that any distributor can implement
The notify-rust feature is enabled by default and provides cross-platform desktop notifications using the notify-rust crate.
When to use notify-rust (default):
- Simple notifications on Linux, macOS, and Windows
- Cross-platform consistency
- Basic notification features (title, body, icon)
When to disable notify-rust:
- You need native Windows toast notifications with advanced features (actions, hero images, scheduling)
- You want platform-specific notification features on macOS/Windows
To disable notify-rust and use native platform implementations:
[dependencies]
tauri-plugin-notifications = { version = "0.4", default-features = false }To disable notify-rust and enable push notifications:
[dependencies]
tauri-plugin-notifications = { version = "0.4", default-features = false, features = ["push-notifications"] }Configure the plugin permissions in your capabilities/default.json:
{
"permissions": [
"notifications:default"
]
}If you enabled the unified-push feature, also add the UnifiedPush permission set:
{
"permissions": [
"notifications:default",
"notifications:allow-unified-push"
]
}Register the plugin in your Tauri app:
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_notifications::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}An example app is available in examples/notifications-demo demonstrating all plugin features:
- Permission management and push notifications (mobile)
- Basic, scheduled, and styled notifications
- Interactive notifications with action buttons
- Notification channels (Android)
- Pending and active notification management
- Event listeners with logging
Run it:
cd examples/notifications-demo
pnpm install
pnpm tauri devimport {
isPermissionGranted,
requestPermission,
sendNotification
} from '@choochmeque/tauri-plugin-notifications-api';
// Check and request permission
let permissionGranted = await isPermissionGranted();
if (!permissionGranted) {
const permission = await requestPermission();
permissionGranted = permission === 'granted';
}
// Send simple notification
if (permissionGranted) {
sendNotification('Hello from Tauri!');
// Or with more details
sendNotification({
title: 'TAURI',
body: 'Tauri is awesome!'
});
}import { sendNotification } from '@choochmeque/tauri-plugin-notifications-api';
// Notification with icon and sound
await sendNotification({
id: 1,
title: 'New Message',
body: 'You have a new message from John',
icon: 'message_icon',
sound: 'notification_sound',
autoCancel: true
});
// Large text notification
await sendNotification({
id: 2,
title: 'Article',
body: 'New article available',
largeBody: 'This is a much longer text that will be displayed when the user expands the notification...',
summary: 'Read more'
});
// Inbox style notification
await sendNotification({
id: 3,
title: 'Email',
body: '3 new emails',
inboxLines: [
'Alice: Meeting at 3pm',
'Bob: Project update',
'Charlie: Lunch tomorrow?'
]
});import { sendNotification, Schedule } from '@choochmeque/tauri-plugin-notifications-api';
// Schedule notification for specific date
await sendNotification({
title: 'Reminder',
body: 'Time for your meeting!',
schedule: Schedule.at(new Date(2024, 0, 15, 14, 30))
});
// Repeating notification
await sendNotification({
title: 'Daily Reminder',
body: 'Don\'t forget to exercise!',
schedule: Schedule.at(new Date(2024, 0, 15, 9, 0), true)
});
// Schedule with interval
await sendNotification({
title: 'Break Time',
body: 'Time to take a break!',
schedule: Schedule.interval({
hour: 1
})
});
// Schedule every X units
import { ScheduleEvery } from '@choochmeque/tauri-plugin-notifications-api';
await sendNotification({
title: 'Hourly Update',
body: 'Checking in every hour',
schedule: Schedule.every(ScheduleEvery.Hour, 1)
});import {
sendNotification,
registerActionTypes,
onAction
} from '@choochmeque/tauri-plugin-notifications-api';
// Register action types
await registerActionTypes([{
id: 'message-actions',
actions: [
{
id: 'reply',
title: 'Reply',
input: true,
inputPlaceholder: 'Type your reply...',
inputButtonTitle: 'Send'
},
{
id: 'mark-read',
title: 'Mark as Read'
},
{
id: 'delete',
title: 'Delete',
destructive: true
}
]
}]);
// Send notification with actions
await sendNotification({
title: 'New Message',
body: 'You have a new message',
actionTypeId: 'message-actions'
});
// Listen for action events
const unlisten = await onAction((notification) => {
console.log('Action performed on notification:', notification);
});
// Stop listening
unlisten();import {
createChannel,
channels,
removeChannel,
Importance,
Visibility
} from '@choochmeque/tauri-plugin-notifications-api';
// Create a notification channel
await createChannel({
id: 'messages',
name: 'Messages',
description: 'Notifications for new messages',
importance: Importance.High,
visibility: Visibility.Private,
sound: 'message_sound',
vibration: true,
lights: true,
lightColor: '#FF0000'
});
// Send notification to specific channel
await sendNotification({
channelId: 'messages',
title: 'New Message',
body: 'You have a new message'
});
// List all channels
const channelList = await channels();
// Remove a channel
await removeChannel('messages');import {
pending,
active,
cancel,
cancelAll,
removeActive,
removeAllActive
} from '@choochmeque/tauri-plugin-notifications-api';
// Get pending notifications
const pendingNotifications = await pending();
// Cancel specific pending notifications
await cancel([1, 2, 3]);
// Cancel all pending notifications
await cancelAll();
// Get active notifications
const activeNotifications = await active();
// Remove specific active notifications
await removeActive([
{ id: 1 },
{ id: 2, tag: 'message' }
]);
// Remove all active notifications
await removeAllActive();import { onNotificationReceived } from '@choochmeque/tauri-plugin-notifications-api';
// Listen for notifications received
const unlisten = await onNotificationReceived((notification) => {
console.log('Notification received:', notification);
});
// Stop listening
unlisten();import { registerForPushNotifications } from '@choochmeque/tauri-plugin-notifications-api';
// Register for push notifications and get device token
try {
const token = await registerForPushNotifications();
console.log('Push token:', token);
// Send this token to your server to send push notifications
} catch (error) {
console.error('Failed to register for push notifications:', error);
}UnifiedPush provides a decentralized alternative to FCM, giving users control over their push notification delivery.
import {
registerForUnifiedPush,
getUnifiedPushDistributors,
saveUnifiedPushDistributor,
onUnifiedPushMessage,
onUnifiedPushEndpoint
} from '@choochmeque/tauri-plugin-notifications-api';
// Check available UnifiedPush distributors
const { distributors } = await getUnifiedPushDistributors();
console.log('Available distributors:', distributors);
// If no distributor is selected, prompt user to choose one
if (distributors.length === 0) {
console.error('No UnifiedPush distributor installed. Please install NextPush or ntfy.');
} else {
// Save the selected distributor (e.g., NextPush)
await saveUnifiedPushDistributor(distributors[0]);
// Listen for new endpoints
const unlistenEndpoint = await onUnifiedPushEndpoint((data) => {
console.log('UnifiedPush endpoint:', data.endpoint);
// Send this endpoint to your server to send push notifications
});
// Listen for incoming messages
const unlistenMessage = await onUnifiedPushMessage((data) => {
console.log('UnifiedPush message received:', data);
});
// Register for UnifiedPush
const { endpoint, instance } = await registerForUnifiedPush();
console.log('Registered with UnifiedPush:', endpoint);
}Sending UnifiedPush notifications:
Once you have the endpoint URL, your server can send notifications by making an HTTP POST request to the endpoint:
curl -X POST "https://your-distributor-url/endpoint" \
-H "Content-Type: application/json" \
-d '{
"title": "Hello",
"body": "This is a UnifiedPush notification",
"data": {
"custom": "data"
}
}'use tauri_plugin_notifications::{NotificationsExt, Schedule, ScheduleEvery};
// Send simple notification
app.notifications()
.builder()
.title("Hello")
.body("This is a notification from Rust!")
.show()?;
// Send rich notification
app.notifications()
.builder()
.id(1)
.title("New Message")
.body("You have a new message")
.icon("message_icon")
.sound("notification_sound")
.auto_cancel()
.show()?;
// Scheduled notification
app.notifications()
.builder()
.title("Reminder")
.body("Time for your meeting!")
.schedule(Schedule::at(date_time, false, false))
.show()?;
// Notification with attachments
use tauri_plugin_notifications::Attachment;
app.notifications()
.builder()
.title("Photo Shared")
.body("Check out this image!")
.attachment(Attachment {
id: "image1".to_string(),
url: "file:///path/to/image.jpg".to_string(),
})
.show()?;Checks if the permission to send notifications is granted.
Returns: Promise<boolean>
Requests the permission to send notifications.
Returns: Promise<'granted' | 'denied' | 'default'>
Registers the app for push notifications (mobile only). On Android, this retrieves the FCM device token. On iOS, this requests permissions and registers for remote notifications.
Returns: Promise<string> - The device push token
Unregisters the app from push notifications (mobile only). Deletes the FCM token on Android.
Returns: Promise<void>
Breaking change:
unregisterForPushNotifications()previously returnedPromise<string>. It now returnsPromise<void>since the native side no longer resolves with a value.
Registers the app for UnifiedPush notifications (Android only). UnifiedPush is a decentralized push notification protocol that allows receiving notifications through various distributors.
Returns: Promise<UnifiedPushEndpoint> - An object containing:
endpoint: The URL where push messages should be sentinstance: The instance identifier for this registrationpubKeySet(optional): VAPID public-key set for encrypted push (containspubKeyandauthfields)
Unregisters the app from UnifiedPush notifications (Android only).
Returns: Promise<void>
Gets the list of available UnifiedPush distributors installed on the device (Android only). Distributors are apps that handle push notification delivery (e.g., NextPush, ntfy).
Returns: Promise<{ distributors: string[] }>
Saves the selected UnifiedPush distributor (Android only). This sets which distributor app should be used for handling push notifications.
Parameters:
distributor: The package name of the distributor to use
Returns: Promise<void>
Gets the currently selected UnifiedPush distributor (Android only).
Returns: Promise<{ distributor: string }>
Listens for new UnifiedPush endpoint events. This event is triggered when a new UnifiedPush endpoint is registered or updated.
Returns: Promise<PluginListener> with unlisten() method
Listens for UnifiedPush message events. This event is triggered when a push message is received through UnifiedPush.
Returns: Promise<PluginListener> with unlisten() method
Listens for UnifiedPush unregistration events. This event is triggered when the app is unregistered from UnifiedPush.
Returns: Promise<PluginListener> with unlisten() method
Listens for UnifiedPush error events. This event is triggered when there's an error with UnifiedPush registration or delivery.
Returns: Promise<PluginListener> with unlisten() method
Listens for UnifiedPush temporary-unavailability events. Fired when the distributor app is temporarily unavailable (e.g. being updated). The existing registration remains valid; wait for an onUnifiedPushEndpoint callback before sending push messages again.
Returns: Promise<PluginListener> with unlisten() method
Sends a notification to the user. Can be called with a simple string for the title or with a detailed options object.
Parameters:
options: Notification options or title stringid: Notification identifier (32-bit integer)channelId: Channel identifier (Android)title: Notification titlebody: Notification bodyschedule: Schedule for delayed or recurring notificationslargeBody: Multiline text contentsummary: Detail text for large notificationsactionTypeId: Action type identifiergroup: Group identifiergroupSummary: Mark as group summary (Android)sound: Sound resource nameinboxLines: Array of lines for inbox style (max 5)icon: Notification iconlargeIcon: Large icon (Android)iconColor: Icon color (Android)attachments: Array of attachmentsextra: Extra payload dataongoing: Non-dismissible notification (Android)autoCancel: Auto-cancel on clicksilent: Silent notification (iOS)visibility: Notification visibilitynumber: Number of items (Android)
Register actions that are performed when the user clicks on the notification.
Parameters:
types: Array of action type objects with:id: Action type identifieractions: Array of action objectsid: Action identifiertitle: Action titlerequiresAuthentication: Requires device unlockforeground: Opens app in foregrounddestructive: Destructive action styleinput: Enable text inputinputButtonTitle: Input button labelinputPlaceholder: Input placeholder text
Retrieves the list of pending notifications.
Returns: Promise<PendingNotification[]>
Cancels the pending notifications with the given list of identifiers.
Cancels all pending notifications.
Retrieves the list of active notifications.
Returns: Promise<ActiveNotification[]>
Removes the active notifications with the given list of identifiers.
Removes all active notifications.
Creates a notification channel (Android).
Parameters:
channel: Channel configurationid: Channel identifiername: Channel namedescription: Channel descriptionsound: Sound resource namelights: Enable notification lightlightColor: Light colorvibration: Enable vibrationimportance: Importance level (None, Min, Low, Default, High)visibility: Visibility level (Secret, Private, Public)
Removes the channel with the given identifier.
Retrieves the list of notification channels.
Returns: Promise<Channel[]>
Listens for notification received events.
Returns: Promise<PluginListener> with unlisten() method
Listens for notification action performed events.
Returns: Promise<PluginListener> with unlisten() method
- Uses native notification systems
- Actions support varies by platform
- Limited scheduling capabilities on some platforms
- Channels not applicable (Android-specific)
- Requires permission request
- Rich notifications with attachments
- Action support with input options
- Silent notifications available
- Group notifications (thread identifiers)
- Notification channels required for Android 8.0+
- Full scheduling support
- Rich notification styles (inbox, large text)
- Ongoing notifications for background tasks
- Detailed importance and visibility controls
- Custom sounds, vibration, and lights
- The plugin automatically configures notification capabilities
- Add notification sounds to your Xcode project if needed:
- Add sound files to your iOS project
- Place in app bundle
- Reference by filename (without extension)
- The plugin automatically includes required permissions
- For custom sounds:
- Place sound files in
res/raw/folder - Reference by filename (without extension)
- Place sound files in
- For custom icons:
- Place icons in
res/drawable/folder - Reference by filename (without extension)
- Place icons in
- For push notifications (FCM) - These steps must be done in your Tauri app project:
- Create a Firebase project at Firebase Console
- Download the
google-services.jsonfile from Firebase Console - Place
google-services.jsonin your Tauri app'sgen/android/app/directory - Add the Google Services classpath to your app's
gen/android/build.gradle.kts:buildscript { repositories { google() mavenCentral() } dependencies { classpath("com.google.gms:google-services:4.4.2") } } - Apply the plugin at the bottom of
gen/android/app/build.gradle.kts:apply(plugin = "com.google.gms.google-services")
- The notification plugin already includes the Firebase Cloud Messaging dependency when the
push-notificationsfeature is enabled
- Notifications appear in the system notification center
- Test different notification types and interactions
- Verify notification persistence and dismissal
- Test on physical devices (simulator support is limited)
- Request permissions before sending notifications
- Test scheduled notifications with different intervals
- Verify action handling and notification grouping
- Create and test notification channels
- Test different importance levels and visibility settings
- Verify scheduled notifications work with device sleep
- Test ongoing notifications for background tasks
- Verify notification styles (inbox, large text, etc.)
- Verify permissions are granted
- On Android, ensure notification channel exists
- Check system notification settings
- Verify notification ID is unique
- Check device power settings (battery optimization)
- On Android, use
allowWhileIdlefor critical notifications - Verify schedule time is in the future
- Ensure action types are registered before sending notification
- Verify action IDs match between registration and handling
- Check platform-specific action support