---
title: Triggers
description: Understand how to use triggers to create notifications that fire under specific conditions.
---

Triggers can be used to display notifications in-advance when a specific condition is met such as time.

For example, you may wish to notify your user when they have a meeting at work.

<Vimeo id="445346021" caption="Triggers Example" />

## Handling trigger notifications

### Creating a trigger notification

```js
import React from 'react';
import { View, Button } from 'react-native';
import notifee, { TimestampTrigger, TriggerType } from 'react-native-notify-kit';

function Screen() {
  async function onCreateTriggerNotification() {
    const date = new Date(Date.now());
    date.setHours(11);
    date.setMinutes(10);

    // Create a time-based trigger
    const trigger: TimestampTrigger = {
      type: TriggerType.TIMESTAMP,
      timestamp: date.getTime(), // fire at 11:10am (10 minutes before meeting)
    };

    // Create a trigger notification
    await notifee.createTriggerNotification(
      {
        title: 'Meeting with Jane',
        body: 'Today at 11:20am',
        android: {
          channelId: 'your-channel-id',
        },
      },
      trigger,
    );
  }

  return (
    <View>
      <Button title="Create Trigger Notification" onPress={() => onCreateTriggerNotification()} />
    </View>
  );
}
```

> To see a full list of triggers and their properties, view the [Trigger](/react-native/reference/trigger) reference documentation.

The `createTriggerNotification` method is called passing in a `notification` and a `trigger`. You must ensure the channel is created first as well as other attributes your notification may have such as categories.

Go ahead and press the button! A notification will appear in 10 minutes, giving the user a reminder they have a meeting with Jane!

### Updating a trigger notification

Trigger notifications work in the same way as any other notification. They have a random unique ID assigned to them which can be used to update pending trigger notifications. If there is no trigger with that ID, a new one will be created.

Let's update our trigger we created previously to occur weekly.

```js
import notifee, { TimestampTrigger, TriggerType, RepeatFrequency } from 'react-native-notify-kit';

async function onCreateTriggerNotification() {
  const date = new Date(Date.now());
  date.setHours(11);
  date.setMinutes(10);

  const trigger: TimestampTrigger = {
    type: TriggerType.TIMESTAMP,
    timestamp: date.getTime(),
    repeatFrequency: RepeatFrequency.WEEKLY,
  };

  await notifee.createTriggerNotification(
    {
      id: '123',
      title: 'Meeting with Jane',
      body: 'Today at 11:20am',
      android: {
        channelId: 'your-channel-id',
      },
    },
    trigger,
  );
}
```

> To update any notifications that are already displayed, you can update them using [displayNotification](/react-native/displaying-a-notification)

### Retrieving trigger notifications

To retrieve a list of all your trigger notifications you can call [getTriggerNotificationIds](/react-native/reference/gettriggernotificationids) method and a list of ids will be returned.

```js
notifee.getTriggerNotificationIds().then(ids => console.log('All trigger notifications: ', ids));
```

### Cancelling a trigger notification

There may be situations whereby you may want to cancel the trigger notification and stop any future notifications from displaying.

To cancel a trigger notification, the [`cancelNotification`](/react-native/displaying-a-notification#cancelling-a-notification) method can be called with the unique notification ID.

It's also possible to cancel all of your trigger notifications, by calling [cancelTriggerNotifications](/react-native/reference/canceltriggernotifications) or [cancelAllNotifications](/react-native/reference/cancelallnotifications).

## Trigger Types

### Timestamp Trigger

The [`TimestampTrigger`](/react-native/reference/timestamptrigger) allows you to create a trigger that displays a notification at a specific time and date, using the property `timestamp` (milliseconds since epoch) and optional `repeatFrequency` and `repeatInterval` properties:

```js
import notifee, {
  TimestampTrigger,
  TriggerType,
  RepeatFrequency,
  TimeUnit,
  AlarmType,
} from 'react-native-notify-kit';

const trigger: TimestampTrigger = {
  type: TriggerType.TIMESTAMP,
  timestamp: Date.now() + 1000 * 60 * 60 * 3, // fire in 3 hours
  repeatFrequency: RepeatFrequency.WEEKLY, // repeat once a week
};
```

### Custom repeat intervals

Timestamp triggers now support custom repeat intervals. Use `repeatFrequency` to choose the calendar unit and `repeatInterval` as a positive integer multiplier for that unit.

`repeatInterval` defaults to `1` when `repeatFrequency` is set. `repeatInterval` is only valid with a repeating `repeatFrequency`; it is not valid without `repeatFrequency` or with `RepeatFrequency.NONE`. Supported timestamp repeat frequencies are `HOURLY`, `DAILY`, `WEEKLY`, and `MONTHLY`; `YEARLY` is not supported.

| `repeatFrequency`         | `repeatInterval` | Result         |
| ------------------------- | ---------------- | -------------- |
| `RepeatFrequency.DAILY`   | `2`              | every 2 days   |
| `RepeatFrequency.WEEKLY`  | `2`              | every 2 weeks  |
| `RepeatFrequency.MONTHLY` | `3`              | every 3 months |

```ts
const firstOccurrence = new Date();
firstOccurrence.setHours(10, 0, 0, 0);

await notifee.createTriggerNotification(
  {
    title: 'Reminder',
    body: 'This reminder repeats every 2 days.',
    android: { channelId: 'reminders' },
  },
  {
    type: TriggerType.TIMESTAMP,
    timestamp: firstOccurrence.getTime(),
    repeatFrequency: RepeatFrequency.DAILY,
    repeatInterval: 2,
  },
);
```

```ts
const firstOccurrence = new Date();
firstOccurrence.setHours(12, 45, 0, 0);

await notifee.createTriggerNotification(
  {
    title: 'Quarterly reminder',
    body: 'This reminder repeats every 3 months.',
    android: { channelId: 'reminders' },
  },
  {
    type: TriggerType.TIMESTAMP,
    timestamp: firstOccurrence.getTime(),
    repeatFrequency: RepeatFrequency.MONTHLY,
    repeatInterval: 3,
  },
);
```

#### Android behavior

On Android, `repeatInterval` is used together with `repeatFrequency` to advance the next timestamp with calendar-aware scheduling. For example, `RepeatFrequency.DAILY` with `repeatInterval: 2` advances by two calendar days, and `RepeatFrequency.MONTHLY` with `repeatInterval: 3` advances by three calendar months.

AlarmManager is the default and recommended backend for timestamp triggers. `RepeatFrequency.MONTHLY` is supported with AlarmManager. `RepeatFrequency.MONTHLY` is not supported with `alarmManager: false`, because WorkManager uses duration-based intervals and does not provide calendar-month semantics.

For reminders where the timing is important, consider `AlarmType.SET_ALARM_CLOCK`. It is not required for every timestamp trigger, but it uses Android's highest-priority scheduled alarm primitive.

```ts
const firstOccurrence = new Date();
firstOccurrence.setHours(10, 0, 0, 0);

await notifee.createTriggerNotification(
  {
    title: 'Reminder',
    body: 'Your scheduled reminder is due.',
    android: {
      channelId: 'reminders',
    },
  },
  {
    type: TriggerType.TIMESTAMP,
    timestamp: firstOccurrence.getTime(),
    repeatFrequency: RepeatFrequency.DAILY,
    repeatInterval: 2,
    alarmManager: {
      type: AlarmType.SET_ALARM_CLOCK,
    },
  },
);
```

#### iOS behavior change for repeating timestamp triggers

On iOS, repeating timestamp triggers use a bounded rolling schedule of one-shot local notifications. This replaces the previous native repeating `UNCalendarNotificationTrigger` path for repeating timestamp triggers.

This behavior change applies only to repeating `TimestampTrigger` notifications on iOS. Android scheduling and one-shot timestamp triggers keep their existing paths.

This is intentional: native repeating calendar triggers cannot express custom intervals such as every 2 days or every 3 months from a selected start timestamp, and they can match the next wall-clock time even when the intended start date is in the future.

The rolling schedule keeps upcoming occurrences pending and tops them up when the app becomes active, when the user interacts with a notification, or when a rolling notification is delivered while the app is in the foreground. Because iOS does not wake the app merely because a local notification was delivered while the app is killed or suspended, the rolling window cannot be extended indefinitely unless the app runs again.

When multiple rolling timestamp triggers are active, the library rebalances the bounded rolling window across active rolling series. Earlier triggers do not consume the entire pending-notification budget and block later triggers. If the number of active rolling series exceeds the available rolling budget, scheduling fails with a clear error instead of silently dropping existing series. Non-rolling pending notifications created by the app still count against iOS' global pending-notification limits, so they reduce the space available for rolling timestamp triggers.

This rolling schedule respects the selected start date. It does not use a native repeating `UNCalendarNotificationTrigger` for custom repeat intervals. Internal rolling notification IDs are not exposed through the JavaScript APIs; APIs such as `getTriggerNotificationIds()` and `getDisplayedNotifications()` use the public notification IDs.

#### Monthly repeats and month-end dates

Monthly repeats use native calendar semantics. Dates that do not exist in a target month are adjusted by the platform calendar. For example, a trigger starting on January 31 and repeating monthly may move to the last valid day of February, depending on platform calendar behavior.

### Android backend: AlarmManager (default) vs WorkManager

Since **v9.1.12**, Android trigger notifications are scheduled with **AlarmManager by default** — this gives reliable delivery even when the app is killed, which WorkManager cannot guarantee on aggressive OEM ROMs. The default `AlarmType` is `SET_EXACT_AND_ALLOW_WHILE_IDLE`, which also fires during Doze mode.

You can opt out and fall back to WorkManager with `alarmManager: false`, or customise the AlarmManager configuration with an object:

```js
const trigger: TimestampTrigger = {
  type: TriggerType.TIMESTAMP,
  timestamp: Date.now() + 1000 * 60 * 60 * 3,
  // opt out — use WorkManager (less reliable when app is killed)
  alarmManager: false,
};

const customTrigger: TimestampTrigger = {
  type: TriggerType.TIMESTAMP,
  timestamp: Date.now() + 1000 * 60 * 60 * 3,
  alarmManager: {
    // Explicit AlarmType — if omitted defaults to SET_EXACT_AND_ALLOW_WHILE_IDLE.
    type: AlarmType.SET_EXACT_AND_ALLOW_WHILE_IDLE,
    allowWhileIdle: true,
  },
};
```

#### `AlarmType.SET_ALARM_CLOCK` (strongest reliability)

For time-sensitive reminders, recovery timers, or any notification where a miss is user-visible damage, consider `AlarmType.SET_ALARM_CLOCK`. It is the strongest reliability guarantee Android exposes — it uses the same primitive as the stock Clock app, renders an alarm-clock icon in the status bar, and is the least susceptible to OEM aggressive-kill power management (Xiaomi MIUI, Oppo ColorOS, Huawei EMUI, Vivo FuntouchOS).

```js
const reminderTrigger: TimestampTrigger = {
  type: TriggerType.TIMESTAMP,
  timestamp: Date.now() + 1000 * 60 * 60 * 8, // 8 hours from now
  alarmManager: {
    type: AlarmType.SET_ALARM_CLOCK,
  },
};
```

### Error handling on Android

Since **v9.5.0**, `createTriggerNotification()` and `cancelTriggerNotifications()` resolve their Promises only after the underlying Room write has completed. Two implications:

- **Latency**: ~5–15 ms added on a warm database (measured on a Pixel 9 Pro XL). Tight loops scheduling many triggers may see cumulative latency increases.
- **Rejections**: Room write errors — `SQLiteFullException` on a disk-full device, SQLite corruption, schema migration failures — now **propagate** as JS Promise rejections. Previously these were silently swallowed and the Promise resolved even when the write failed. Wrap trigger scheduling in `try/catch` if you need to react to persistence failures:

```js
try {
  await notifee.createTriggerNotification(notification, trigger);
} catch (error) {
  console.warn('Failed to schedule trigger:', error);
}
```

### DST and reboot recovery

Repeating triggers (`HOURLY` / `DAILY` / `WEEKLY` / `MONTHLY`) honor wall-clock time across DST transitions on Android by using calendar-aware scheduling. Scheduled alarms also self-heal after reboot: since v9.6.0 the library detects boot deltas via `Settings.Global.BOOT_COUNT` and reschedules persisted alarms on OEM devices that suppress `BOOT_COMPLETED` (Xiaomi MIUI, Oppo ColorOS, Huawei EMUI, Vivo FuntouchOS). Stale non-repeating triggers (timestamp already in the past at recovery time) fire once within a 24-hour grace period and are then deleted; beyond the grace period they're deleted silently.

#### Maximum TimestampTrigger Count

Android has a system limit of 50 timestamp triggers active at one time.
iOS appears to have a limit of [64 timestamp triggers active at one time](https://developer.apple.com/forums/thread/23288), but it is not in [the official documentation](https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649508-add).

#### iOS rolling schedule limitations

On iOS, repeating timestamp triggers for `HOURLY`, `DAILY`, `WEEKLY`, and `MONTHLY` are scheduled through the bounded rolling one-shot model described in [Custom repeat intervals](#custom-repeat-intervals). This preserves the selected start timestamp, including the first occurrence.

The rolling window is finite because iOS limits how many local notifications can be pending at one time. The library tops up future occurrences when it gets an app lifecycle, interaction, or foreground-delivery opportunity, but it cannot keep extending the schedule while the app remains killed/suspended and the user never interacts with notifications.

#### Android 12 Limitations

Starting from Android 12, timestamp triggers cannot be created unless user specfically allow the [exact alarm permission](https://developer.android.com/reference/android/Manifest.permission#SCHEDULE_EXACT_ALARM). Before you create a timestamp trigger, check whether `SCHEDULE_EXACT_ALARM` permission is allowed by making a call to `getNotificationSettings`. If ` alarm` is `DISABLED`, you should educate the user on this permission and ask to enable scheduling alarms. You can then use `openAlarmPermissionSettings` function to display the Alarms & Reminder settings of your app.

```js
const settings = await notifee.getNotificationSettings();
if (settings.android.alarm == AndroidNotificationSetting.ENABLED) {
  //Create timestamp trigger
} else {
  // Show some user information to educate them on what exact alarm permission is,
  // and why it is necessary for your app functionality, then send them to system preferences:
  await notifee.openAlarmPermissionSettings();
}
```

Please note that if the user revokes the permission via system preferences, all of the timestamp triggers will be deleted by the system. However, if you check for the permission, notice it is missing, educate the user and they grant permission again, Notify Kit will automatically reschedule the triggers when the user allows the alarm permission again with no need for additional code.

### Interval Trigger

The [`IntervalTrigger`](/react-native/reference/intervaltrigger) allows you to create a trigger that repeats at a specific interval. The trigger accepts two properties, an `interval` and an optional `timeUnit`.

This trigger can be used to implement timers.

For example, to set a trigger to repeat every 30 minutes from now:

```js
import notifee, { IntervalTrigger, TriggerType, TimeUnit } from 'react-native-notify-kit';

const trigger: IntervalTrigger = {
  type: TriggerType.INTERVAL,
  interval: 30,
  timeUnit: TimeUnit.MINUTES
};
```
