> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zixflow.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Push Notifications

> Push Notifications — Zixflow React Native SDK integration guide.

Complete guide to implementing push notifications in React Native with Zixflow using Apple Push Notifications (APNs) or Firebase Cloud Messaging (FCM).

> \*\* Track your campaigns:\*\* The SDK automatically tracks delivery, opens, and clicks. For advanced tracking customization and implementation details, see [Push Notification Tracking](/documentation/sdk/react-native/push-notification-tracking).

### Prerequisites

Before implementing push notifications:

1. **Configure push credentials in Zixflow dashboard** - Add APNs certificates or FCM Server Key
2. **Complete iOS/Android native setup** - Ensure native dependencies are installed
3. **Device tokens must be associated with users** - Call `identify()` before sending notifications

**Important Limitation**: The Zixflow React Native SDK currently supports deep links and images in push notifications. Custom action buttons require additional native code.

***

### Platform-Specific Requirements

#### iOS Requirements

* **APNs or FCM**: Choose either Apple Push Notification service or Firebase Cloud Messaging
* **Xcode Capabilities**: Push Notifications and Background Modes
* **Notification Service Extension**: Required for rich push (images, videos)
* **Physical Device**: iOS Simulator cannot receive push notifications

#### Android Requirements

* **Firebase Project**: Required for FCM integration
* **google-services.json**: Must be in `android/app/` directory
* **Minimum API Level 24**: Android 7.0 or higher
* **POST\_NOTIFICATIONS Permission**: Required for Android 13+ (API 33+)

***

### iOS Setup

You can use either **APNs (Apple Push Notification service)** or **FCM (Firebase Cloud Messaging)** on iOS.

#### Step 1: Enable Push Capabilities in Xcode

1. Open your project's `.xcworkspace` file in Xcode
2. Select your app target
3. Go to **Signing & Capabilities** tab
4. Click **+ Capability** → Add **Push Notifications**
5. Click **+ Capability** → Add **Background Modes**
6. Enable **Remote notifications** under Background Modes

#### Step 2: Choose APNs or FCM

**Option A: APNs (Recommended for iOS-only apps)**

Update your `ios/Podfile`:

```ruby theme={null}
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

platform :ios, '13.0'

target 'YourApp' do
  config = use_native_modules!

  use_react_native!(:path => config[:reactNativePath])

  # Add Zixflow with APNs support
  pod 'zixflow-reactnative/apn', :path => '../node_modules/zixflow-reactnative'

  # Your other dependencies...
end
```

**Option B: FCM (For cross-platform Firebase apps)**

Update your `ios/Podfile` with static linkage:

```ruby theme={null}
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

platform :ios, '13.0'

# Required for FCM
use_frameworks! :linkage => :static

target 'YourApp' do
  config = use_native_modules!

  use_react_native!(:path => config[:reactNativePath])

  # Add Zixflow with FCM support
  pod 'zixflow-reactnative/fcm', :path => '../node_modules/zixflow-reactnative'

  # Your other dependencies...
end
```

**Install dependencies:**

```bash theme={null}
cd ios
pod install
cd ..
```

#### Step 3: Configure AppDelegate (Swift - Recommended)

For modern Swift-based React Native apps with APNs:

**AppDelegate.swift:**

```swift theme={null}
import UIKit
import ZixflowMessagingPushAPN

@main
class AppDelegateWithZixflowIntegration: ZixflowAppDelegateWrapper<AppDelegate> {}

class AppDelegate: NSObject, UIApplicationDelegate {

  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    // Set notification delegate
    UNUserNotificationCenter.current().delegate = self

    // Initialize Zixflow push messaging (APNs)
    MessagingPushAPN.initialize(
      withConfig: MessagingPushConfigBuilder()
        .build()
    )

    return true
  }
}

extension AppDelegate: UNUserNotificationCenterDelegate {
  // Show notifications when app is in foreground
  func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    willPresent notification: UNNotification,
    withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
  ) {
    completionHandler([.banner, .list, .badge, .sound])
  }
}
```

**For FCM**, import `ZixflowMessagingPushFCM` instead:

```swift theme={null}
import ZixflowMessagingPushFCM

// Initialize with FCM
MessagingPushFCM.initialize(
  withConfig: MessagingPushConfigBuilder()
    .build()
)
```

#### Step 4: Configure AppDelegate (Objective-C)

If your React Native app uses Objective-C, create a Swift bridge:

**Create `MyAppPushNotificationsHandler.swift`:**

```swift theme={null}
import Foundation
import ZixflowMessagingPushAPN

@objc
public class MyAppPushNotificationsHandler: NSObject {

  @objc(setupZixflowClickHandling)
  public func setupZixflowClickHandling() {
    MessagingPushAPN.initialize(
      withConfig: MessagingPushConfigBuilder().build()
    )
  }

  @objc(application:deviceToken:)
  public func application(
    _ application: UIApplication,
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
  ) {
    MessagingPush.shared.application(
      application,
      didRegisterForRemoteNotificationsWithDeviceToken: deviceToken
    )
  }

  @objc(application:error:)
  public func application(
    _ application: UIApplication,
    didFailToRegisterForRemoteNotificationsWithError error: Error
  ) {
    MessagingPush.shared.application(
      application,
      didFailToRegisterForRemoteNotificationsWithError: error
    )
  }
}
```

**Update `AppDelegate.mm`:**

```objc theme={null}
#import "YourApp-Swift.h"

@implementation AppDelegate

MyAppPushNotificationsHandler* pnHandlerObj;

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // ... existing initialization code ...

  // Register for remote notifications
  [application registerForRemoteNotifications];

  // Initialize push handling
  pnHandlerObj = [[MyAppPushNotificationsHandler alloc] init];
  [pnHandlerObj setupZixflowClickHandling];

  return YES;
}

- (void)application:(UIApplication *)application
    didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  [pnHandlerObj application:application deviceToken:deviceToken];
}

- (void)application:(UIApplication *)application
    didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  [pnHandlerObj application:application error:error];
}

@end
```

#### Step 5: Rich Push with Notification Service Extension

To support rich push notifications (images, videos, GIFs), add a Notification Service Extension:

**1. Create Notification Service Extension:**

1. In Xcode: **File** → **New** → **Target**
2. Select **Notification Service Extension**
3. Name it `NotificationServiceExtension`
4. Click **Finish** (activate scheme when prompted)

**2. Add Zixflow to Extension:**

Update your `ios/Podfile` to include the extension:

```ruby theme={null}
# Main app target
target 'YourApp' do
  # ... existing configuration ...
  pod 'zixflow-reactnative/apn', :path => '../node_modules/zixflow-reactnative'
end

# Notification Service Extension target
target 'NotificationServiceExtension' do
  pod 'zixflow-reactnative-richpush/apn', :path => '../node_modules/zixflow-reactnative'
end
```

For FCM:

```ruby theme={null}
target 'NotificationServiceExtension' do
  pod 'zixflow-reactnative-richpush/fcm', :path => '../node_modules/zixflow-reactnative'
end
```

**3. Install dependencies:**

```bash theme={null}
cd ios
pod install
cd ..
```

**4. Update `NotificationService.swift`:**

```swift theme={null}
import UserNotifications
import ZixflowMessagingPushAPN

class NotificationService: UNNotificationServiceExtension {
  var contentHandler: ((UNNotificationContent) -> Void)?
  var bestAttemptContent: UNMutableNotificationContent?

  override func didReceive(
    _ request: UNNotificationRequest,
    withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
  ) {
    self.contentHandler = contentHandler
    bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

    // Initialize SDK for extension
    MessagingPushAPN.initializeForExtension(
      withConfig: MessagingPushConfigBuilder(apiKey: "YOUR_API_KEY")
                .build()
    )

    if let bestAttemptContent = bestAttemptContent {
      // Let Zixflow handle rich push and track delivery
      MessagingPush.shared.didReceive(request, withContentHandler: contentHandler)
    }
  }

  override func serviceExtensionTimeWillExpire() {
    // Called when extension is about to be terminated
    MessagingPush.shared.serviceExtensionTimeWillExpire()

    if let contentHandler = contentHandler,
       let bestAttemptContent = bestAttemptContent {
      contentHandler(bestAttemptContent)
    }
  }
}
```

**Important:** Replace `"YOUR_API_KEY"` with your actual API key.

***

### Android Setup

Android push notifications use Firebase Cloud Messaging (FCM).

#### Step 1: Add Firebase to Your Project

1. Go to [Firebase Console](https://console.firebase.google.com/)
2. Add your Android app to Firebase project
3. Download `google-services.json`
4. Place `google-services.json` in `android/app/` directory

#### Step 2: Configure Gradle

**Project-level `android/build.gradle`:**

```gradle theme={null}
buildscript {
    ext {
        minSdkVersion = 24
        compileSdkVersion = 34
        targetSdkVersion = 34
    }

    dependencies {
        classpath 'com.google.gms:google-services:4.4.2'
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}
```

**App-level `android/app/build.gradle`:**

```gradle theme={null}
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'  // Add this line

android {
    // ... existing configuration ...
}

dependencies {
    // React Native auto-linking handles Zixflow dependencies
    // ... your other dependencies ...
}
```

#### Step 3: Add Permissions

Add to `android/app/src/main/AndroidManifest.xml`:

```xml theme={null}
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Required for push notifications -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- Required for Android 13+ (API 33+) -->
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    <application>
        <!-- Your app configuration -->
    </application>
</manifest>
```

#### Step 4: Configure Notification Icon and Color (Optional)

Add to `android/app/src/main/AndroidManifest.xml` inside `<application>` tag:

```xml theme={null}
<application>
    <!-- Default notification icon (white, transparent background) -->
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/ic_notification" />

    <!-- Default notification color (accent color) -->
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/notification_color" />
</application>
```

***

### React Native Integration

#### Step 1: Initialize SDK

Initialize the Zixflow SDK in your `App.tsx`:

```typescript theme={null}
import React, { useEffect } from 'react';
import { Zixflow, ZixflowConfig, ZixflowLogLevel } from 'zixflow-reactnative';

export default function App() {
  useEffect(() => {
    // Configure the SDK
    const config: ZixflowConfig = {
      apiKey: 'YOUR_API_KEY',
      logLevel: ZixflowLogLevel.debug,
      inApp: {
              },
      autoTrackDeviceAttributes: true,
      trackApplicationLifecycleEvents: true,
    };

    // Initialize the SDK
    Zixflow.initialize(config);

    console.log('Zixflow SDK initialized');
  }, []);

  return (
    // Your app UI
  );
}
```

#### Step 2: Request Push Permission

Request permission to send push notifications:

```typescript theme={null}
import React, { useState } from 'react';
import { Button, Alert } from 'react-native';
import { Zixflow, ZixflowPushPermissionStatus } from 'zixflow-reactnative';

export default function PushPermissionButton() {
  const [permissionStatus, setPermissionStatus] = useState<ZixflowPushPermissionStatus | null>(null);

  const requestPushPermission = async () => {
    try {
      const permission = await Zixflow.pushMessaging.showPromptForPushNotifications({
        ios: {
          sound: true,
          badge: true,
          alert: true,
        },
      });

      setPermissionStatus(permission);

      switch (permission) {
        case ZixflowPushPermissionStatus.Granted:
          Alert.alert('Success', 'Push notifications enabled!');
          console.log('Push notifications enabled');
          break;

        case ZixflowPushPermissionStatus.Denied:
          Alert.alert('Denied', 'Push notification permission was denied');
          console.log('Push notifications denied');
          break;

        case ZixflowPushPermissionStatus.NotDetermined:
          // iOS only: permission not yet asked
          console.log('Push notification permission not determined');
          break;
      }
    } catch (error) {
      console.error('Failed to request push permission:', error);
    }
  };

  return (
    <Button
      title="Enable Push Notifications"
      onPress={requestPushPermission}
    />
  );
}
```

**Permission Options (iOS)**:

| Option  | Type    | Description                |
| ------- | ------- | -------------------------- |
| `sound` | boolean | Enable notification sounds |
| `badge` | boolean | Enable app badge updates   |
| `alert` | boolean | Show notification alerts   |

#### Step 3: Check Permission Status

Check current push permission status:

```typescript theme={null}
import { Zixflow, ZixflowPushPermissionStatus } from 'zixflow-reactnative';

const checkPushPermission = async () => {
  try {
    const status = await Zixflow.pushMessaging.getPushPermissionStatus();

    console.log('Push permission status:', status);

    if (status === ZixflowPushPermissionStatus.Granted) {
      console.log('Push notifications are enabled');
    } else if (status === ZixflowPushPermissionStatus.Denied) {
      console.log('Push notifications are disabled');
    } else {
      console.log('Push permission not determined');
    }
  } catch (error) {
    console.error('Failed to get push permission status:', error);
  }
};
```

#### Step 4: Identify Users

**Critical**: Device tokens must be associated with a user before push notifications can be delivered.

```typescript theme={null}
import { Zixflow } from 'zixflow-reactnative';

// Identify user when they log in
const handleLogin = async (userId: string, userEmail: string) => {
  try {
    // Identify user with Zixflow
    Zixflow.identify({
      userId: userId,
      traits: {
        email: userEmail,
        firstName: 'John',
        lastName: 'Doe',
        plan: 'premium',
      },
    });

    console.log('User identified:', userId);
  } catch (error) {
    console.error('Failed to identify user:', error);
  }
};
```

**Important Notes:**

* When users start the app, they automatically generate a device token
* This token links to their Zixflow profile when you call `identify()`
* This ensures notifications are delivered to the correct user

#### Step 5: Get Device Token

Retrieve the registered device token:

```typescript theme={null}
import { Zixflow } from 'zixflow-reactnative';

const getDeviceToken = async () => {
  try {
    const token = await Zixflow.pushMessaging.getRegisteredDeviceToken();
    console.log('Device token:', token);
    return token;
  } catch (error) {
    console.error('Failed to get device token:', error);
    return null;
  }
};
```

***

### Deep Links and Navigation

Handle deep links from push notifications:

#### Setup Deep Linking

**1. Configure Deep Links (iOS):**

Add to `ios/YourApp/Info.plist`:

```xml theme={null}
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>yourapp</string>
    </array>
  </dict>
</array>
```

**2. Configure Deep Links (Android):**

Add to `android/app/src/main/AndroidManifest.xml`:

```xml theme={null}
<activity android:name=".MainActivity">
  <!-- Existing intent filter -->

  <!-- Deep link intent filter -->
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />

    <data
      android:scheme="yourapp"
      android:host="*" />
  </intent-filter>

  <!-- Universal Links (optional) -->
  <intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />

    <data
      android:scheme="https"
      android:host="yourapp.com" />
  </intent-filter>
</activity>
```

#### Handle Deep Links in React Native

Use React Navigation's linking configuration:

```typescript theme={null}
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Linking } from 'react-native';

const Stack = createNativeStackNavigator();

const linking = {
  prefixes: ['yourapp://', 'https://yourapp.com'],
  config: {
    screens: {
      Home: 'home',
      Product: 'product/:id',
      Profile: 'profile',
    },
  },
};

export default function App() {
  return (
    <NavigationContainer linking={linking}>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Product" component={ProductScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}
```

***

### Rich Push Notification Payloads

The Zixflow SDK automatically handles rich push notifications. Here's how to structure payloads:

#### iOS APNs Payload

```json theme={null}
{
  "aps": {
    "mutable-content": 1,
    "alert": {
      "title": "New Product Available",
      "body": "Check out our latest premium features"
    },
    "badge": 1,
    "sound": "default"
  },
  "Zixflow": {
    "push": {
      "link": "yourapp://product/123",
      "image": "https://example.com/product-image.jpg"
    }
  }
}
```

#### iOS FCM Payload

```json theme={null}
{
  "message": {
    "apns": {
      "payload": {
        "aps": {
          "mutable-content": 1,
          "alert": {
            "title": "Special Offer",
            "body": "Limited time discount!"
          }
        },
        "Zixflow": {
          "push": {
            "link": "https://yourapp.com/offers",
            "image": "https://example.com/offer.png"
          }
        }
      },
      "headers": {
        "apns-priority": 10
      }
    }
  }
}
```

#### Android FCM Payload

```json theme={null}
{
  "message": {
    "data": {
      "title": "Order Shipped",
      "body": "Your order is on the way!",
      "image": "https://example.com/shipping.jpg",
      "link": "yourapp://orders/456"
    }
  }
}
```

***

### Testing Push Notifications

#### 1. Verify Device Token Registration

Check if device token is registered:

```typescript theme={null}
const verifyPushSetup = async () => {
  try {
    const token = await Zixflow.pushMessaging.getRegisteredDeviceToken();
    const status = await Zixflow.pushMessaging.getPushPermissionStatus();

    console.log('Device token:', token);
    console.log('Permission status:', status);

    if (token && status === ZixflowPushPermissionStatus.Granted) {
      console.log('✓ Push notifications ready');
    } else {
      console.log('✗ Push setup incomplete');
    }
  } catch (error) {
    console.error('Push verification failed:', error);
  }
};
```

#### 2. Enable Debug Logging

Set log level to debug during development:

```typescript theme={null}
const config: ZixflowConfig = {
  apiKey: 'YOUR_API_KEY',
  logLevel: ZixflowLogLevel.debug,  // Verbose logging
};

Zixflow.initialize(config);
```

#### 3. Test on Physical Devices

**iOS:**

* Push notifications **do not work** on iOS Simulator
* Must use physical iOS device
* Ensure APNs certificate is configured in Zixflow dashboard

**Android:**

* Emulator works if Google Play Services installed
* Physical device always recommended
* Ensure FCM Server Key is configured in Zixflow dashboard

#### 4. Send Test Push from Zixflow

1. Log into Zixflow dashboard
2. Navigate to **Messaging** → **Push Notifications**
3. Create test push notification
4. Send to specific user (using `userId` from `identify()`)

***

### Troubleshooting

#### iOS Push Not Received

**Symptoms:** Push sent but not delivered on iOS

**Solutions:**

1. Verify Push Notifications capability enabled in Xcode
2. Check APNs certificate uploaded to Zixflow dashboard
3. Ensure testing on physical device (not simulator)
4. Verify user identified: `Zixflow.identify({ userId: ... })`
5. Check permission granted: `getPushPermissionStatus()`
6. Review logs for errors

#### Android Push Not Received

**Symptoms:** Push sent but not delivered on Android

**Solutions:**

1. Verify `google-services.json` in `android/app/` directory
2. Check FCM Server Key in Zixflow dashboard
3. Ensure POST\_NOTIFICATIONS permission granted (Android 13+)
4. Verify Google Services plugin applied
5. Check device token registered
6. Review logs for errors

#### Rich Push Not Working (Images)

**Symptoms:** Images not loading in notifications

**iOS Solutions:**

1. Ensure Notification Service Extension properly configured
2. Verify extension has correct dependencies in Podfile
3. Check App Groups configuration (if using)
4. Verify image URL is accessible
5. Check extension logs for errors

**Android Solutions:**

1. Verify image URL is accessible from device
2. Check internet connectivity
3. Ensure image format is supported (JPEG, PNG, GIF)

#### Permission Denied

**Symptoms:** User denied push permission

**Solutions:**

1. Explain value before requesting permission
2. Guide users to Settings to enable manually
3. Show in-app message explaining benefits
4. Request permission at appropriate time (after user engagement)

#### Device Token Not Registered

**Symptoms:** `getRegisteredDeviceToken()` returns empty or fails

**Solutions:**

1. Verify SDK initialized before calling
2. Check permission granted
3. Ensure identify() called to associate token
4. Review native logs for errors
5. Rebuild app and retry

***

### Best Practices

1. **Request permission thoughtfully** - Explain value before asking
2. **Identify users immediately** after authentication
3. **Test on physical devices** - Simulators have limitations
4. **Use rich push** - Images increase engagement
5. **Handle deep links** - Provide seamless navigation
6. **Monitor metrics** - Track delivery and open rates
7. **Enable debug logging** - During development only
8. **Test both platforms** - iOS and Android behave differently
9. **Clear identity on logout** - Call `clearIdentify()`
10. **Keep credentials secure** - Never commit API keys to git

***

***
