# Push notifications

Stream sends push notifications through Firebase Cloud Messaging (FCM), Apple Push Notification service (APN), Huawei Push and Xiaomi Push. Push providers, device registration and push preferences work the same way across products and are managed with the same APIs. Each product decides which events send a push and what the notification contains; those rules and templates are documented with each product.

>
> **Info:** The Stream API doesn't support web push notifications. If you're building a mobile application using JavaScript technologies, you can set up mobile push notifications using the supported providers.
>

## Setting Up Push

Push is available to Stream integrations running in a mobile environment. Setting it up takes three steps:

1. **Configure a push provider** on the [Stream Dashboard](https://getstream.io/signin/)
2. **Add client-side integration** for your chosen provider in your app
3. **Register user devices** with Stream's API

The client-side steps depend on which SDK you are using; follow the push notification guide in your SDK's documentation.

Providers, devices, preferences and troubleshooting each have their own page:

- [Push providers and multi-bundle](https://getstream.io/docs/platform/push-providers/)
- [Registering devices](https://getstream.io/docs/platform/push-devices/)
- [Push preferences](https://getstream.io/docs/platform/push-preferences/)
- [Testing and troubleshooting push](https://getstream.io/docs/platform/push-troubleshooting/)

## Chat Push Delivery

Stream Chat supports push notifications through Firebase Cloud Messaging, Apple Push Notification (APN), Huawei Push and Xiaomi Push.

- Push notifications can be sent for new messages, message edits and reactions. You can use [Webhooks](https://getstream.io/docs/platform/webhooks/) to send push notifications on other types of events.

- Supports customization of push payloads, including the ability to add custom data. But you don't have to configure it as it comes with well-designed default templates.

- Supports enabling/disabling push notifications for each notification type, such as new messages, message edits, reactions. By default, all notification types are disabled.

- A common message payload where SDKs automatically enrich messages and channels in the runtime and call the callback with these data where it's a familiar way of building by programming and any customization is possible.

- Multi bundle support for push providers.

- Multi-tenancy and continuous delivery are covered in a single Stream app.

- Customization in multiple levels; _app, provider, channel type, user._

- **No channel member count limitation**

### Push Delivery Rules

Push message delivery behaves according to these rules:

- Push notifications can be configured for new messages, message edits, message reactions and more.
- Only channel members receive a push notification.
- Members receive push notifications regardless of their online status.
- Replies inside a [thread](https://getstream.io/chat/docs/node/threads/) are only sent to users that are part of that thread:
  - They posted at least one message.
  - They were mentioned.
- Push from muted users are not sent.
- Push [preferences](https://getstream.io/docs/platform/push-preferences/) for a user are respected:
  - Preferences at user level are "all", "none" or "mentions".
  - Preferences at channel level are "all", "none" or "mentions".
- Push for a [private message](https://getstream.io/chat/docs/node/private-messaging/) are sent only to the restricted users of the message.
- Push notification are sent to all registered devices for a user (up to 25) .
- `skip_push` is marked as `false` , as described [here](https://getstream.io/chat/docs/node/send-message/).
- `push_notifications` is enabled (default) on the channel type for message is sent.

>
> **Warning:** Push notifications require membership. Watching a channel isn't enough.
>

### Handling Push Notifications on the Foreground

Both iOS and Android discard push notifications when your application is on the foreground.

You can configure this on your application and decide what to do when a push notification is received while the app is on the foreground.

```ts label="React Native"
// we should an example on how to handle this using `notifee` below
// any other library for handling push notification rendering can be used
notifee.onForegroundEvent(({ detail, type }) => {
  if (type === EventType.PRESS) {
    // the user has pressed the notification
    const channelId = detail.notification?.data?.channel_id;
    // the navigation logic, to navigate to relevant channel screen for example
    if (channelId) {
      navigationContainerRef.current?.navigate("ChannelScreen", { channelId });
    }
  }
});
```

```swift label="Swift"
// you can add this to your `UNUserNotificationCenterDelegate` delegate
// and show a banner notification when a push message is received
func userNotificationCenter(_ center: UNUserNotificationCenter,
     willPresent notification: UNNotification,
     withCompletionHandler completionHandler:
      @escaping (UNNotificationPresentationOptions) -> Void) {
  completionHandler([.banner])
}
```

### Push Notification Payload

Push notifications are delivered as data payloads that the SDK can use to convert into the same data types that are received when working with the APIs.

When a message received by the Chat API, according to the delivery rules, it kicks a job that sends a regular data message (as below) to configured push providers on your app. According to the battery and the online status of the device, push providers deliver this payload to the actual devices. When a device receives the payload, it's passed to the SDK which connects to Chat API to receive regular message and channel records and unmarshals them into in-memory objects and gives control to you by passing these objects. At this point, your application can use these objects to generate any push notification to be shown to the user.

This is the main payload which will be sent to each configured provider:

>
> **Info:** The version field in the data payload is set to **v2**. It is to ensure backward compatibility with the existing SDKs.
>

```json label="JSON"
{
  "sender": "stream.chat",
  "type": "message.new",
  "version": "v2",
  "message_id": "d152f6c1-8c8c-476d-bfd6-59c15c20548a",
  "id": "d152f6c1-8c8c-476d-bfd6-59c15c20548a",
  "channel_type": "messaging",
  "channel_id": "company-chat",
  "cid": "messaging:company-chat"
}
```

On both Android and iOS the SDK will convert the payload in channel and message types and allow you to customize the notification message.

You can find more details, examples and guides on specific use-cases on the specific SDK docs.

## Feeds Push Delivery

Stream Activity Feeds supports push notifications through Firebase Cloud Messaging (FCM) and Apple Push Notification (APN) providers.

Push notifications help keep users engaged by delivering real-time updates about activities, reactions, comments, and other feed events when the application is closed or in the background.

>
> **Info:** The Stream API doesn't support web push notifications. However, if you're building a mobile application using JavaScript technologies, you can set up mobile push notifications using the supported providers: Firebase Cloud Messaging (FCM) and Apple Push Notification (APN).
>

### When Push Notifications Are Sent

Activity Feeds sends push notifications in the following scenarios:

- **New Follower** when a user follows another user
- **Comments** added to activities the user is involved with
- **Reactions** added to the user's activities
- **Comment Reactions** added to the user's comments
- **Mentions** when a user is mentioned in activities or comments
- **Notification feeds** - activities added to the default notification feed automatically trigger push notifications

### Push Delivery Rules

Push notification delivery follows these rules for Activity Feeds:

- Only users with registered devices receive push notifications
- Push notifications are sent to all registered devices for a user (up to 25 devices)
- Users must have proper permissions granted for notifications
- Push notifications are sent for activity updates like new comments and reactions
- Notifications respect the feed's privacy settings and user permissions
- Activities added to the default notification feed automatically trigger push notifications
- You can skip push notifications for individual actions using the `skip_push` parameter on comments, reactions, and follows

### Feed Groups and Push Notifications

Push notifications in Activity Feeds are configured at the feed group level. Each feed group can have its own push notification settings:

- **Built-in feed groups** like `notification` and `user` come with default push configurations
- **Custom feed groups** can be created with specific push notification settings
- **Activity types** can be selectively enabled for push notifications using `push_types`

For detailed configuration options, refer to the Feed Group Push Configuration documentation.

### Implementation Examples

#### Direct Push Notifications

Direct push notifications are sent immediately when events occur. Use `skip_push: false` (default) to enable direct push:

```js label="React"
// Comment with direct push notification (default behavior)
await client.addComment({
  object_id: activity.id,
  object_type: "activity",
  comment: "Great post!",
  // skip_push: false (default) - sends push immediately
});

// Reaction with direct push notification
await client.addReaction({
  activity_id: activity.id,
  type: "like",
  // skip_push: false (default) - sends push immediately
});
```

```js label="React Native"
// Comment with direct push notification (default behavior)
await client.addComment({
  object_id: activity.id,
  object_type: "activity",
  comment: "Great post!",
  // skip_push: false (default) - sends push immediately
});

// Reaction with direct push notification
await client.addReaction({
  activity_id: activity.id,
  type: "like",
  // skip_push: false (default) - sends push immediately
});
```

```js label="JavaScript"
// Comment with direct push notification (default behavior)
await client.addComment({
  object_id: activity.id,
  object_type: "activity",
  comment: "Great post!",
  // skip_push: false (default) - sends push immediately
});

// Reaction with direct push notification
await client.addReaction({
  activity_id: activity.id,
  type: "like",
  // skip_push: false (default) - sends push immediately
});
```

```js label="Node.js"
// Comment with direct push notification (default behavior)
await serverClient.feeds.addComment({
  object_id: activity.id,
  object_type: "activity",
  comment: "Great post!",
  user_id: "user-456",
  // skip_push: false (default) - sends push immediately
});

// Reaction with direct push notification
await serverClient.feeds.addReaction({
  activity_id: activity.id,
  type: "like",
  user_id: "user-456",
  // skip_push: false (default) - sends push immediately
});
```

```php label="PHP"
use GetStream\GeneratedModels;

// Comment with direct push notification (default behavior)
$feedsClient->addComment(new GeneratedModels\AddCommentRequest(
    objectID: $activity->id,
    objectType: "activity",
    comment: "Great post!",
    userID: "user-456",
    // skipPush: false (default) - sends push immediately
));

// Reaction with direct push notification
$feedsClient->addActivityReaction($activity->id, new GeneratedModels\AddReactionRequest(
    type: "like",
    userID: "user-456",
    // skipPush: false (default) - sends push immediately
));
```

```go label="Go"
// Comment with direct push notification (default behavior)
_, err = client.Feeds().AddComment(ctx, &getstream.AddCommentRequest{
  ObjectID: activityID,
  ObjectType: "activity",
  Comment: "Great post!",
  UserID: getstream.PtrTo("user-456"),
  // SkipPush: getstream.PtrTo(false), (default) - sends push immediately
})
if err != nil {
  log.Fatal("Error adding comment:", err)
}

// Reaction with direct push notification
_, err = client.Feeds().AddReaction(ctx, activityID, &getstream.AddReactionRequest{
  Type: "like",
  UserID: getstream.PtrTo("user-456"),
  // SkipPush: getstream.PtrTo(false), (default) - sends push immediately
})
if err != nil {
  log.Fatal("Error adding reaction:", err)
}
```

#### Notification Feed Push Notifications

Use `create_notification_activity: true` with `skip_push: true` to send push via the built-in `notification feeds`:

```js label="React"
// Comment that creates notification activity and sends via notification feed
await client.addComment({
  object_id: activity.id,
  object_type: "activity",
  comment: "Great post!",
  create_notification_activity: true,
  skip_push: true, // Send via notification feed instead of direct push
});
// Reaction that creates notification activity
await client.addReaction({
  activity_id: activity.id,
  type: "like",
  create_notification_activity: true,
  skip_push: true, // Send via notification feed
});
```

```js label="React Native"
// Comment that creates notification activity and sends via notification feed
await client.addComment({
  object_id: activity.id,
  object_type: "activity",
  comment: "Great post!",
  create_notification_activity: true,
  skip_push: true, // Send via notification feed instead of direct push
});
// Reaction that creates notification activity
await client.addReaction({
  activity_id: activity.id,
  type: "like",
  create_notification_activity: true,
  skip_push: true, // Send via notification feed
});
```

```js label="JavaScript"
// Comment that creates notification activity and sends via notification feed
await client.addComment({
  object_id: activity.id,
  object_type: "activity",
  comment: "Great post!",
  create_notification_activity: true,
  skip_push: true, // Send via notification feed instead of direct push
});
// Reaction that creates notification activity
await client.addReaction({
  activity_id: activity.id,
  type: "like",
  create_notification_activity: true,
  skip_push: true, // Send via notification feed
});
```

```js label="Node.js"
// Comment that creates notification activity and sends via notification feed
await serverClient.feeds.addComment({
  object_id: activity.id,
  object_type: 'activity',
  comment: 'Great post!',
  user_id: "user-456",
  create_notification_activity: true,
  skip_push: true // Send via notification feed instead of direct push
});

// Reaction that creates notification activity
await serverClient.feeds.addActivityReaction({
  activity_id: activity.id,
  type: 'like',
  user_id: 'user-456'
  create_notification_activity: true,
  skip_push: true, // Send via notification feed
});
```

```php label="PHP"
use GetStream\GeneratedModels;

// Comment that creates notification activity and sends via notification feed
$feedsClient->addComment(new GeneratedModels\AddCommentRequest(
    objectID: $activity->id,
    objectType: "activity",
    comment: "Great post!",
    userID: "user-456",
    createNotificationActivity: true,
    skipPush: true // Send via notification feed instead of direct push
));

// Reaction that creates notification activity
$feedsClient->addActivityReaction($activity->id, new GeneratedModels\AddReactionRequest(
    type: "like",
    userID: "user-456",
    createNotificationActivity: true,
    skipPush: true // Send via notification feed
));
```

```go label="Go"
_, err = client.Feeds().AddComment(ctx, &getstream.AddCommentRequest{
  ObjectID: activityID,
  ObjectType: "activity",
  Comment: "Great post!",
  UserID: getstream.PtrTo("user-456"),
  CreateNotificationActivity: getstream.PtrTo(true),
  SkipPush: getstream.PtrTo(true),
})
if err != nil {
  log.Fatal("Error adding comment:", err)
}

_, err = client.Feeds().AddReaction(ctx, activityID, &getstream.AddReactionRequest{
  Type: "like",
  UserID: getstream.PtrTo("user-456"),
  CreateNotificationActivity: getstream.PtrTo(true),
  SkipPush: getstream.PtrTo(true),
})
if err != nil {
  log.Fatal("Error adding reaction:", err)
}
```

#### Custom Notification Feeds

Manually add activities to custom notification feeds for complete control (only for server-side SDKs):

```js label="Node.js"
// Add a custom notification directly to a user's notification feed
await serverClient.feeds.addActivity({
  feeds: ["notification:user-123"], // Target user's notification feed
  type: "milestone", // Custom activity type
  text: "You've reached 1000 followers!",
  user_id: "user_id",
  extra_data: {
    milestone_type: "followers",
    count: 1000,
  },
});

// Add activity to custom notification feed group
await serverClient.feeds.addActivity({
  feeds: ["alerts:user-123"], // Custom notification feed group
  type: "system_alert",
  text: "Your subscription expires in 3 days",
  user_id: "user_id",
});
```

```php label="PHP"
use GetStream\GeneratedModels;

// Add a custom notification directly to a user's notification feed
$feedsClient->addActivity(new GeneratedModels\AddActivityRequest(
    feeds: ["notification:john"], // Target user's notification feed
    type: "milestone", // Custom activity type
    text: "You've reached 1000 followers!",
    userID: "<user id>",
    custom: (object)[
        "milestone_type" => "followers",
        "count" => 1000,
    ]
));

// Add activity to custom notification feed group
$feedsClient->addActivity(new GeneratedModels\AddActivityRequest(
    feeds: ["alerts:john"], // Custom notification feed group
    type: "system_alert",
    text: "Your subscription expires in 3 days",
    userID: "<user id>"
));
```

```go label="Go"
ctx := context.Background()

// Add a custom notification directly to a user's notification feed
_, err = client.Feeds().AddActivity(ctx, &getstream.AddActivityRequest{
  Feeds:  []string{"notification:john"}, // Target user's notification feed
  Type:   "milestone",                       // Custom activity type
  Text:   getstream.PtrTo("You've reached 1000 followers!"),
  UserID: getstream.PtrTo("<user id>"),
  Custom: getstream.PtrTo(map[string]any{
    "milestone_type": "followers",
    "count":          1000,
  }),
})
if err != nil {
  log.Fatal("Error adding milestone activity:", err)
}

// Add activity to custom notification feed group
_, err = client.Feeds().AddActivity(ctx, &getstream.AddActivityRequest{
  Feeds:  []string{"alerts:john"}, // Custom notification feed group
  Type:   "system_alert",
  Text:   getstream.PtrTo("Your subscription expires in 3 days"),
  UserID: getstream.PtrTo("<user id>"),
})
if err != nil {
  log.Fatal("Error adding system alert activity:", err)
}
```

## What Each Product Configures

The notification templates are configured per product, because the variables differ:

- Chat: [push templates](https://getstream.io/chat/docs/node/push-template/)
- Activity Feeds: [push templates](https://getstream.io/activity-feeds/docs/node/push-template/) and [feed group push configuration](https://getstream.io/activity-feeds/docs/node/feed-group-push-configuration/)

---

For the most recent version of this documentation, visit [https://getstream.io/docs/platform/push-notifications/](https://getstream.io/docs/platform/push-notifications/).