capacitor-notification-reader
v1.2.0
Published
Capacitor plugin to read and persist Android notifications with RoomDB storage
Maintainers
Readme
capacitor-notification-reader
Capacitor plugin to read active notifications on Android with persistent storage.
Features
- Read Active Notifications: Access all currently active notifications from the notification drawer
- Persistent Storage: Notifications are automatically stored in a RoomDB database when posted
- Background Collection: Notifications are captured even when your app isn't running
- Pagination Support: Efficiently retrieve stored notifications with pagination
- Comprehensive Type Safety: Full TypeScript support with discriminated unions
- Rich Notification Data: Access notification styles, actions, icons, and metadata
Install
npm install capacitor-notification-reader
npx cap syncHow It Works
Persistent Notification Storage
This plugin uses Android's NotificationListenerService combined with RoomDB to provide robust notification tracking:
Notification Listener Service: Once you grant notification access, the Android NotificationListenerService runs in the background and receives all notifications system-wide.
Automatic Storage: When a notification is posted, the service automatically:
- Parses all notification data (title, text, style, actions, icons, etc.)
- Stores it in a local RoomDB database
- Notifies your app via the
notificationPostedevent listener (if the app is running)
Background Operation: The listener service operates independently of your app:
- Notifications are captured even when your app is closed
- Data persists across app restarts
- No battery-intensive polling required
Dual Access Methods:
getActiveNotifications(): Returns currently visible notifications from the notification drawergetNotifications(): Retrieves stored notifications from the database with pagination support
Database Schema
The RoomDB database stores comprehensive notification data including:
- Primary key: UUID (automatically generated for each notification)
- Basic fields: app name (human-readable), package name, title, text, timestamp
- Icons: small icon, large icon, app icon (all as base64)
- Metadata: category, style, channel ID, group info, priority
- Style-specific data: big text, big picture, inbox lines, messaging conversations
- Action buttons with inline reply support
- Progress information for download/upload notifications
- Call-style specific data (caller name)
Note: When the NotificationListenerService first connects (e.g., when your app is installed or after device reboot), it automatically loads all currently active notifications into the database. This ensures you have a complete history from the moment the service starts.
Usage Examples
Listen for Real-time Notifications
import { NotificationReader } from 'capacitor-notification-reader';
// Listen for notifications as they are posted
await NotificationReader.addListener('notificationPosted', (notification) => {
console.log('New notification:', notification.title);
console.log('Stored in DB with ID:', notification.id);
// The notification is automatically saved to the database
});Retrieve Stored Notifications with Pagination
import { NotificationReader } from 'capacitor-notification-reader';
// Get first batch (most recent notifications)
const { notifications } = await NotificationReader.getNotifications({
limit: 20
});
// Get next batch using cursor (timestamp-based pagination)
if (notifications.length > 0) {
const lastTimestamp = notifications[notifications.length - 1].timestamp;
const { notifications: nextBatch } = await NotificationReader.getNotifications({
cursor: lastTimestamp,
limit: 20
});
}Type-Safe Notification Handling
import { NotificationStyle, NotificationCategory } from 'capacitor-notification-reader';
notifications.forEach((notification) => {
// TypeScript automatically narrows the type
switch (notification.style) {
case NotificationStyle.MESSAGING:
// notification is MessagingNotification
console.log('Messages:', notification.messages);
break;
case NotificationStyle.BIG_PICTURE:
// notification is BigPictureNotification
console.log('Picture:', notification.bigPicture);
break;
}
});Clear Notification History
import { NotificationReader } from 'capacitor-notification-reader';
// Delete all stored notifications from the database
await NotificationReader.deleteAllNotifications();
console.log('All notification history cleared');
// Note: This only clears the database, not the system notification drawerImport Notifications
import { NotificationReader, NotificationStyle } from 'capacitor-notification-reader';
// Prepare notifications to import (e.g., from a backup or migration)
const notificationsToImport = [
{
id: 'notification-1',
appName: 'WhatsApp',
packageName: 'com.whatsapp',
title: 'John Doe',
text: 'Hey, how are you?',
timestamp: Date.now() - 3600000, // 1 hour ago
style: NotificationStyle.MESSAGING,
category: 'msg',
actions: [],
isGroupSummary: false,
isOngoing: false,
autoCancel: true,
isLocalOnly: false,
priority: 0,
number: 1,
messages: [
{
text: 'Hey, how are you?',
timestamp: Date.now() - 3600000,
sender: 'John Doe'
}
],
conversationTitle: 'John Doe',
isGroupConversation: false
}
];
// Import notifications into the database
await NotificationReader.importNotifications({
notifications: notificationsToImport
});
console.log('Notifications imported successfully');
// Verify import
const { notifications } = await NotificationReader.getNotifications({ limit: 10 });
console.log('Imported notifications:', notifications);For more detailed examples, see TYPE_USAGE_EXAMPLES.md.
API
getActiveNotifications()openAccessSettings()isAccessEnabled()getNotifications(...)deleteAllNotifications()getTotalCount()getDatabaseSize()importNotifications(...)getInstalledApps()getConfig()setConfig(...)addListener('notificationPosted', ...)- Interfaces
- Type Aliases
- Enums
getActiveNotifications()
getActiveNotifications() => Promise<GetActiveNotificationsResult>Gets all active notifications from the notification listener service.
Returns: Promise<GetActiveNotificationsResult>
Since: 1.0.0
openAccessSettings()
openAccessSettings() => Promise<{ enabled: boolean; }>Opens the system settings page to allow the user to grant notification access to the app. The promise resolves when the user returns from settings with the current permission status.
Returns: Promise<{ enabled: boolean; }>
Since: 1.0.0
isAccessEnabled()
isAccessEnabled() => Promise<{ enabled: boolean; }>Checks if the app has notification access enabled.
Returns: Promise<{ enabled: boolean; }>
Since: 1.0.0
getNotifications(...)
getNotifications(options?: GetNotificationsOptions | undefined) => Promise<GetNotificationsResult>Retrieves notifications from the persistent Room database with optional filtering and cursor-based pagination. Notifications are cached when they are posted and can be queried later even after dismissal from the notification drawer.
| Param | Type | Description |
| ------------- | --------------------------------------------------------------------------- | -------------------------------------- |
| options | GetNotificationsOptions | - Cursor, limit, and filtering options |
Returns: Promise<GetNotificationsResult>
Since: 1.0.0
deleteAllNotifications()
deleteAllNotifications() => Promise<void>Deletes all notifications from the database. This does not affect notifications in the system notification drawer.
Since: 1.0.0
getTotalCount()
getTotalCount() => Promise<{ count: number; }>Gets the total count of notifications stored in the database. This count includes all notifications regardless of their status or type.
Returns: Promise<{ count: number; }>
Since: 1.0.0
getDatabaseSize()
getDatabaseSize() => Promise<{ sizeBytes: number; sizeMB: number; }>Gets the current database size in bytes consumed by stored notifications. This can be used to monitor storage usage and determine if you're approaching your configured storage limit.
Returns: Promise<{ sizeBytes: number; sizeMB: number; }>
Since: 1.0.0
importNotifications(...)
importNotifications(options: ImportNotificationsOptions) => Promise<void>Imports an array of notifications into the database. This method is useful for restoring previously exported notifications, migrating data from another source, or bulk-importing notification data.
Each notification will be inserted using REPLACE strategy, meaning if a notification with the same ID already exists, it will be updated.
| Param | Type | Description |
| ------------- | --------------------------------------------------------------------------------- | -------------------------------------------------------- |
| options | ImportNotificationsOptions | - Object containing the array of notifications to import |
Since: 1.0.0
getInstalledApps()
getInstalledApps() => Promise<GetInstalledAppsResult>Retrieves a list of all installed applications on the device. Returns app name, package name, app icon, and whether it's a system app.
Returns: Promise<GetInstalledAppsResult>
Since: 1.0.0
getConfig()
getConfig() => Promise<NotificationReaderConfig>Gets the current configuration for the notification reader plugin.
Returns: Promise<NotificationReaderConfig>
Since: 1.0.0
setConfig(...)
setConfig(config: NotificationReaderConfig) => Promise<void>Sets the configuration for the notification reader plugin. Changes take effect immediately for new notifications.
| Param | Type | Description |
| ------------ | ----------------------------------------------------------------------------- | ------------------------------ |
| config | NotificationReaderConfig | - Configuration options to set |
Since: 1.0.0
addListener('notificationPosted', ...)
addListener(eventName: 'notificationPosted', listenerFunc: (notification: NotificationItem) => void) => Promise<PluginListenerHandle>Listen for notifications that are posted while the listener service is running. Fires with the freshly-captured notification payload.
| Param | Type |
| ------------------ | ---------------------------------------------------------------------------------------- |
| eventName | 'notificationPosted' |
| listenerFunc | (notification: NotificationItem) => void |
Returns: Promise<PluginListenerHandle>
Interfaces
GetActiveNotificationsResult
Result returned by getActiveNotifications.
| Prop | Type | Description |
| ------------------- | ------------------------------- | -------------------------------------------------------- |
| notifications | NotificationItem[] | Array of active notifications with type-specific shapes. |
BigTextNotification
Big text style notification with expanded text content
| Prop | Type | Description |
| ------------- | ------------------------------------------------------------------------ | -------------------------------- |
| style | NotificationStyle.BIG_TEXT | Notification style template used |
| bigText | string | The full expanded text content |
BigPictureNotification
Big picture style notification with an image
| Prop | Type | Description |
| ------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------- |
| style | NotificationStyle.BIG_PICTURE | Notification style template used |
| bigPicture | string | Base64-encoded picture shown in expanded view |
| pictureContentDescription | string | Content description for the picture |
InboxNotification
Inbox style notification with multiple lines
| Prop | Type | Description |
| ---------------- | --------------------------------------------------------------------- | -------------------------------- |
| style | NotificationStyle.INBOX | Notification style template used |
| inboxLines | string[] | Array of text lines in the inbox |
MessagingNotification
Messaging style notification for chat/messaging apps
| Prop | Type | Description |
| ------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------- |
| style | NotificationStyle.MESSAGING | Notification style template used |
| category | NotificationCategory.MESSAGE | Notification category (call, message, email, etc.) |
| conversationTitle | string | Conversation title for group chats |
| isGroupConversation | boolean | Whether this is a group conversation |
| messages | NotificationMessage[] | Array of messages in the conversation |
NotificationMessage
Message in a messaging-style notification
| Prop | Type | Description |
| --------------- | ------------------- | ------------------------ |
| text | string | Message text |
| timestamp | number | Timestamp of the message |
| sender | string | Sender name |
ProgressNotification
Progress style notification for downloads, uploads, etc.
| Prop | Type | Description |
| -------------- | ------------------------------------------------------------------------------ | -------------------------------------------------- |
| style | NotificationStyle.DEFAULT | Notification style template used |
| category | NotificationCategory.PROGRESS | Notification category (call, message, email, etc.) |
| progress | NotificationProgress | Progress information |
NotificationProgress
Progress information for notifications with progress bars
| Prop | Type | Description |
| ------------------- | -------------------- | ------------------------------------- |
| current | number | Current progress value |
| max | number | Maximum progress value |
| indeterminate | boolean | Whether the progress is indeterminate |
CallNotification
Call notification
| Prop | Type | Description |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| style | NotificationStyle.CALL | NotificationStyle.DEFAULT | Notification style template used |
| category | NotificationCategory.CALL | NotificationCategory.MISSED_CALL | Notification category (call, message, email, etc.) |
| callerName | string | Caller name |
MediaNotification
Media playback notification
| Prop | Type | Description |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| style | NotificationStyle.MEDIA | NotificationStyle.DECORATED_MEDIA | Notification style template used |
| category | NotificationCategory.TRANSPORT | Notification category (call, message, email, etc.) |
GenericNotification
Generic notification that doesn't fit specific patterns
| Prop | Type | Description |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
| style | NotificationStyle.DECORATED_CUSTOM | NotificationStyle.DEFAULT | Notification style template used |
GetNotificationsResult
Result returned by getNotifications.
| Prop | Type | Description |
| ------------------- | ------------------------------- | ----------------------------------------- |
| notifications | NotificationItem[] | Array of notifications from the database. |
GetNotificationsOptions
Options for getNotifications.
| Prop | Type | Description | Default |
| ------------ | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- |
| cursor | number | Return notifications whose timestamp is strictly less than this value (in ms). Use the timestamp from the last item of the previous page when paginating. | |
| limit | number | Maximum number of notifications to retrieve. | 10 |
| filter | NotificationFilter | Optional filter criteria applied on the stored notifications. | |
NotificationFilter
Advanced filters for querying stored notifications. Each filter is optional and multiple filters are combined with AND logic.
| Prop | Type | Description |
| ------------------------------ | --------------------- | -------------------------------------------------------------------------------------------------------------------- |
| textContains | string | Match notifications whose text contains the provided value (case-sensitive). |
| titleContains | string | Match notifications whose title contains the provided value (case-sensitive). |
| textContainsInsensitive | string | Match notifications whose text contains the provided value (case-insensitive). |
| titleContainsInsensitive | string | Match notifications whose title contains the provided value (case-insensitive). |
| appNames | string[] | Only return notifications whose appName exactly matches one of the supplied names. |
| packageName | string | Filter by package name of the posting application. |
| category | string | Filter by notification category. |
| style | string | Filter by notification style template. |
| isOngoing | boolean | Filter for ongoing (non-dismissible) notifications only. |
| isGroupSummary | boolean | Filter for group summary notifications only. |
| channelId | string | Filter by notification channel ID (Android 8+). |
| afterTimestamp | number | Only return notifications posted after this timestamp (in milliseconds). Creates a lower bound for the time range. |
| beforeTimestamp | number | Only return notifications posted before this timestamp (in milliseconds). Creates an upper bound for the time range. |
ImportNotificationsOptions
Options for importNotifications.
| Prop | Type | Description |
| ------------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| notifications | NotificationItem[] | Array of notification items to import into the database. Each notification should conform to the NotificationItem type structure. |
GetInstalledAppsResult
Result returned by getInstalledApps.
| Prop | Type | Description |
| ---------- | --------------------------- | ---------------------------------------------------- |
| apps | InstalledApp[] | Array of installed applications with their metadata. |
InstalledApp
Information about an installed application.
| Prop | Type | Description |
| ----------------- | -------------------- | ---------------------------------------------- |
| packageName | string | The package name of the app. |
| appName | string | The human-readable name of the app. |
| appIcon | string | Base64-encoded PNG of the app's launcher icon. |
| isSystemApp | boolean | Whether the app is a system app. |
NotificationReaderConfig
Configuration options for the notification reader plugin.
| Prop | Type | Description | Default |
| --------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
| filterOngoing | boolean | Whether to filter out ongoing (non-dismissible) notifications. When true, ongoing notifications will be filtered out and not stored. | true |
| filterTransport | boolean | Whether to filter out transport category notifications. When true, notifications with category 'transport' will be filtered out and not stored. | true |
| storageLimit | number | Storage limit for notifications in megabytes (MB). When the database exceeds this limit, older notifications will be removed using FIFO. Set to undefined for unlimited storage. | 500 |
PluginListenerHandle
| Prop | Type |
| ------------ | ----------------------------------------- |
| remove | () => Promise<void> |
Type Aliases
NotificationItem
Union type of all specific notification types. Use discriminated union on 'style' and 'category' for type narrowing.
Type narrowing examples:
- For BigTextNotification: check
notification.style === <a href="#notificationstyle">NotificationStyle</a>.BIG_TEXT - For BigPictureNotification: check
notification.style === <a href="#notificationstyle">NotificationStyle</a>.BIG_PICTURE - For InboxNotification: check
notification.style === <a href="#notificationstyle">NotificationStyle</a>.INBOX - For MessagingNotification: check
notification.style === <a href="#notificationstyle">NotificationStyle</a>.MESSAGING - For ProgressNotification: check
notification.category === <a href="#notificationcategory">NotificationCategory</a>.PROGRESS - For CallNotification: check category is CALL or MISSED_CALL
- For MediaNotification: check style is MEDIA or DECORATED_MEDIA
BigTextNotification | BigPictureNotification | InboxNotification | MessagingNotification | ProgressNotification | CallNotification | MediaNotification | GenericNotification
Enums
NotificationStyle
| Members | Value |
| ---------------------- | -------------------------------------------- |
| BIG_TEXT | 'BigTextStyle' |
| BIG_PICTURE | 'BigPictureStyle' |
| INBOX | 'InboxStyle' |
| MESSAGING | 'MessagingStyle' |
| MEDIA | 'MediaStyle' |
| CALL | 'CallStyle' |
| DECORATED_CUSTOM | 'DecoratedCustomViewStyle' |
| DECORATED_MEDIA | 'DecoratedMediaCustomViewStyle' |
| DEFAULT | 'default' |
NotificationCategory
| Members | Value |
| ---------------------- | ------------------------------- |
| ALARM | 'alarm' |
| CALL | 'call' |
| EMAIL | 'email' |
| ERROR | 'err' |
| EVENT | 'event' |
| LOCATION_SHARING | 'location_sharing' |
| MESSAGE | 'msg' |
| MISSED_CALL | 'missed_call' |
| NAVIGATION | 'navigation' |
| PROGRESS | 'progress' |
| PROMO | 'promo' |
| RECOMMENDATION | 'recommendation' |
| REMINDER | 'reminder' |
| SERVICE | 'service' |
| SOCIAL | 'social' |
| STATUS | 'status' |
| STOPWATCH | 'stopwatch' |
| SYSTEM | 'sys' |
| TRANSPORT | 'transport' |
| VOICEMAIL | 'voicemail' |
| WORKOUT | 'workout' |
| UNKNOWN | 'unknown' |
Contributing
See CONTRIBUTING.md for details on how to contribute to this project.
Release Process
This package uses npm Trusted Publishers with OIDC for secure, automated releases. Releases are triggered automatically when commits are pushed to the main branch.
Setup (One-time)
Configure the trusted publisher on npm:
- Go to your package settings on npmjs.com
- Navigate to "Publishing access" → "Trusted Publisher"
- Select "GitHub Actions"
- Configure:
- Organization/User:
WhyAsh5114 - Repository:
capacitor-notification-reader - Workflow filename:
release.yml
- Organization/User:
No npm tokens needed! The workflow uses OpenID Connect (OIDC) for authentication.
Commit Convention
Follow Conventional Commits for your commit messages:
feat:- New features (triggers minor version bump)fix:- Bug fixes (triggers patch version bump)docs:- Documentation changeschore:- Maintenance tasksBREAKING CHANGE:- Breaking changes (triggers major version bump)
Example:
git commit -m "feat: add support for notification icons"
git commit -m "fix: resolve crash when notification has no title"The CI pipeline will automatically:
- Build the package
- Determine version bump based on commits
- Create a GitHub release with changelog
- Publish to npm with provenance attestation
