> ## 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 Android SDK integration guide.

Complete guide to implementing push notifications with Zixflow using Firebase Cloud Messaging (FCM).

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

### Prerequisites

Before implementing push notifications:

1. **Configure FCM in Zixflow dashboard** - Add your FCM Server Key in the Zixflow dashboard first
2. **Firebase Project Setup** - Create Firebase project and add your Android app
3. **Install the push messaging module** - Add `messagingpush` dependency

**Important:** FCM setup is required before implementing push notifications. This integration serves as the foundation for all push messaging capabilities.

***

### Step 1: Firebase Project Setup

#### 1. Create Firebase Project

1. Go to [https://console.firebase.google.com](https://console.firebase.google.com)
2. Click **Add project** or select existing project
3. Follow the setup wizard

#### 2. Add Android App to Firebase

1. In Firebase console, click **Add app** → Select **Android**
2. Enter your app's package name (e.g., `com.yourcompany.app`)
3. (Optional) Add SHA-1 certificate for debugging
4. Download `google-services.json`

#### 3. Add google-services.json to Project

1. Place `google-services.json` in your `app/` directory
2. Verify the file is at: `app/google-services.json`

***

### Step 2: Add Dependencies

#### 1. Add Google Services Plugin

**Project-level `build.gradle` or `build.gradle.kts`:**

```kotlin theme={null}
// build.gradle.kts (Kotlin DSL)
buildscript {
    dependencies {
        classpath("com.google.gms:google-services:4.4.0")
    }
}
```

```groovy theme={null}
// build.gradle (Groovy DSL)
buildscript {
    dependencies {
        classpath 'com.google.gms:google-services:4.4.0'
    }
}
```

#### 2. Apply Plugin in App Module

**App-level `build.gradle` or `build.gradle.kts`:**

```kotlin theme={null}
// build.gradle.kts (Kotlin DSL)
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
    id("com.google.gms.google-services")  // Add this line
}
```

```groovy theme={null}
// build.gradle (Groovy DSL)
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'com.google.gms.google-services'  // Add this line
}
```

#### 3. Add Zixflow and Firebase Dependencies

**Kotlin DSL:**

```kotlin theme={null}
dependencies {
    // Zixflow core and push module
    implementation("com.zixflow.android:datapipelines:1.0.0")
    implementation("com.zixflow.android:messagingpush:1.0.0")

    // Firebase (if not already included)
    implementation(platform("com.google.firebase:firebase-bom:32.7.0"))
    implementation("com.google.firebase:firebase-messaging")
}
```

**Groovy DSL:**

```groovy theme={null}
dependencies {
    // Zixflow core and push module
    implementation 'com.zixflow.android:datapipelines:1.0.0'
    implementation 'com.zixflow.android:messagingpush:1.0.0'

    // Firebase
    implementation platform('com.google.firebase:firebase-bom:32.7.0')
    implementation 'com.google.firebase:firebase-messaging'
}
```

***

### Step 3: Initialize Zixflow with Push Support

#### Basic Initialization (Kotlin)

```kotlin theme={null}
import android.app.Application
import com.zixflow.sdk.Zixflow
import com.zixflow.sdk.ZixflowConfigBuilder
import com.zixflow.messagingpush.ModuleMessagingPushFCM

class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        // Initialize Zixflow SDK
        val config = ZixflowConfigBuilder(
            applicationContext = this,
            apiKey = "YOUR_API_KEY"
        )
            .autoTrackDeviceAttributes(true)
            .autoTrackActivityScreens(true)
            .trackApplicationLifecycleEvents(true)
            .logLevel(ZixflowLogLevel.DEBUG)

            // Add push notifications module
            .addModule(ModuleMessagingPushFCM())

            .build()

        Zixflow.initialize(config)
    }
}
```

#### Basic Initialization (Java)

```java theme={null}
import android.app.Application;
import com.zixflow.sdk.Zixflow;
import com.zixflow.sdk.ZixflowConfig;
import com.zixflow.sdk.ZixflowConfigBuilder;
import com.zixflow.sdk.ZixflowLogLevel;
import com.zixflow.messagingpush.ModuleMessagingPushFCM;

public class MainApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        // Initialize Zixflow SDK
        ZixflowConfig config = new ZixflowConfigBuilder(this, "YOUR_API_KEY")
            .autoTrackDeviceAttributes(true)
            .autoTrackActivityScreens(true)
            .trackApplicationLifecycleEvents(true)
            .logLevel(ZixflowLogLevel.DEBUG)
            .addModule(new ModuleMessagingPushFCM())
            .build();

        Zixflow.initialize(config);
    }
}
```

**Important:** The SDK automatically:

* Registers a `FirebaseMessagingService` in your manifest
* Fetches and registers FCM device tokens
* Handles push notification display and tracking

***

### Step 4: Register Application in AndroidManifest.xml

Ensure your custom `Application` class is registered:

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

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

    <application
        android:name=".MainApplication"
        android:label="@string/app_name">
        <!-- Your activities -->
    </application>
</manifest>
```

***

### Step 5: Request Push Notification Permission (Android 13+)

Android 13 (API 33) and higher requires runtime permission for notifications.

#### Request Permission in Activity

```kotlin theme={null}
import android.Manifest
import android.os.Build
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import android.content.pm.PackageManager

class MainActivity : AppCompatActivity() {

    private val requestPermissionLauncher = registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { isGranted ->
        if (isGranted) {
            // Permission granted - push notifications enabled
            println("Push notification permission granted")
        } else {
            // Permission denied - explain value to user
            println("Push notification permission denied")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Request permission for Android 13+
        requestNotificationPermission()
    }

    private fun requestNotificationPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            when {
                ContextCompat.checkSelfPermission(
                    this,
                    Manifest.permission.POST_NOTIFICATIONS
                ) == PackageManager.PERMISSION_GRANTED -> {
                    // Permission already granted
                    println("Notification permission already granted")
                }
                shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS) -> {
                    // Show explanation to user why you need this permission
                    showPermissionRationale()
                }
                else -> {
                    // Request permission
                    requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
                }
            }
        }
    }

    private fun showPermissionRationale() {
        // Show dialog explaining why push notifications are valuable
        // Then request permission
        requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
    }
}
```

***

### Step 6: Identify Users

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

```kotlin theme={null}
// Identify user when they log in
Zixflow.instance().identify(
    userId = "user@example.com",
    traits = mapOf(
        "email" to "user@example.com",
        "first_name" to "John",
        "last_name" to "Doe",
        "plan" to "premium"
    )
)
```

**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

***

### Configuration Options

Configure push notification behavior with `MessagingPushModuleConfig`:

```kotlin theme={null}
import com.zixflow.messagingpush.MessagingPushModuleConfig
import com.zixflow.messagingpush.ModuleMessagingPushFCM
import com.zixflow.messagingpush.config.PushClickBehavior

val pushConfig = MessagingPushModuleConfig.Builder()
    .setAutoTrackPushEvents(true)           // Auto-track delivered/opened
    .setPushClickBehavior(                   // Control app navigation
        PushClickBehavior.ACTIVITY_PREVENT_RESTART
    )
    .build()

val config = ZixflowConfigBuilder(this, "YOUR_API_KEY")
    .addModule(ModuleMessagingPushFCM(config = pushConfig))
    .build()
```

#### Configuration Options

| Option                 | Type                            | Default                    | Description                                          |
| ---------------------- | ------------------------------- | -------------------------- | ---------------------------------------------------- |
| `autoTrackPushEvents`  | Boolean                         | `true`                     | Automatically track `delivered` and `opened` metrics |
| `pushClickBehavior`    | PushClickBehavior               | `ACTIVITY_PREVENT_RESTART` | Define behavior when notification is clicked         |
| `notificationCallback` | ZixflowPushNotificationCallback | `null`                     | Override default push behavior                       |

#### Push Click Behaviors

Three strategies control app navigation when notifications are tapped:

**`ACTIVITY_PREVENT_RESTART`** (Default - Recommended)

* Reuses existing activities when possible
* Ideal for apps with sensitive screens (checkout, payment)
* Prevents interrupting user workflows

**`ACTIVITY_NO_FLAGS`**

* Creates new activity instance on every notification tap
* Standard Android behavior

**`RESET_TASK_STACK`**

* Clears entire app state
* Prevents back navigation to previous screens
* Use when you want fresh app start

```kotlin theme={null}
import com.zixflow.messagingpush.config.PushClickBehavior

val pushConfig = MessagingPushModuleConfig.Builder()
    .setPushClickBehavior(PushClickBehavior.ACTIVITY_PREVENT_RESTART)
    .build()
```

***

### Advanced Features

#### Customize Notification Appearance

Override notification appearance using `ZixflowPushNotificationCallback`:

```kotlin theme={null}
import com.zixflow.messagingpush.data.communication.ZixflowPushNotificationCallback
import com.zixflow.messagingpush.data.model.ZixflowParsedPushPayload
import androidx.core.app.NotificationCompat

val pushConfig = MessagingPushModuleConfig.Builder()
    .setNotificationCallback(object : ZixflowPushNotificationCallback {
        override fun onNotificationComposed(
            payload: ZixflowParsedPushPayload,
            builder: NotificationCompat.Builder
        ): NotificationCompat.Builder {
            // Customize notification appearance
            return builder
                .setColor(getColor(R.color.notification_accent))
                .setSound(Uri.parse("android.resource://${packageName}/${R.raw.notification_sound}"))
                .setPriority(NotificationCompat.PRIORITY_HIGH)
        }
    })
    .build()
```

#### Configure Default Icon and Color

Add metadata to `AndroidManifest.xml`:

```xml theme={null}
<application>
    <!-- Default notification icon (should be 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>
```

#### Rich Push Notifications

Rich push (images, videos, GIFs) is **automatically supported** by the SDK. No additional configuration needed.

Send rich media from Zixflow dashboard:

1. Create push notification campaign
2. Add image URL or video URL
3. SDK automatically downloads and displays media

***

### Handle Existing FirebaseMessagingService

If your app already implements `FirebaseMessagingService`, delegate to Zixflow SDK:

```kotlin theme={null}
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.zixflow.messagingpush.ZixflowFirebaseMessagingService

class MyFirebaseMessagingService : FirebaseMessagingService() {

    override fun onMessageReceived(message: RemoteMessage) {
        // Let Zixflow SDK handle push notifications
        val handled = ZixflowFirebaseMessagingService.onMessageReceived(
            context = this,
            remoteMessage = message
        )

        if (!handled) {
            // Handle non-Zixflow push notifications
            handleCustomPush(message)
        }
    }

    override fun onNewToken(token: String) {
        super.onNewToken(token)

        // Register new token with Zixflow
        ZixflowFirebaseMessagingService.onNewToken(
            context = this,
            token = token
        )

        // Handle token for other services
        handleCustomToken(token)
    }

    private fun handleCustomPush(message: RemoteMessage) {
        // Your custom push handling logic
    }

    private fun handleCustomToken(token: String) {
        // Your custom token handling logic
    }
}
```

Register your service in `AndroidManifest.xml`:

```xml theme={null}
<service
    android:name=".MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>
```

***

### Tracking Push Metrics

The SDK automatically tracks push notification delivery, opens, and action clicks to provide campaign analytics in your Zixflow dashboard.

**Automatic tracking includes:**

* **Delivered** - When notification arrives on device
* **Opened** - When user taps notification
* **Action Clicked** - When user taps an action button

> **For advanced tracking customization**, including handling custom `FirebaseMessagingService` implementations, action button clicks, and non-Zixflow push notifications, see the [Push Notification Tracking](/documentation/sdk/android/push-notification-tracking) section below.

**Manual tracking (for custom implementations):**

```kotlin theme={null}
import com.zixflow.messagingpush.data.model.MetricEvent

// Track delivered event
Zixflow.instance().trackMetric(
    deliveryID = "delivery-id-from-payload",
    event = MetricEvent.delivered,
    deviceToken = "device-token"
)

// Track opened event
Zixflow.instance().trackMetric(
    deliveryID = "delivery-id-from-payload",
    event = MetricEvent.opened,
    deviceToken = "device-token"
)
```

***

### Deep Links and Custom Actions

Handle deep links from push notifications:

#### 1. Add Intent Filter to Activity

```xml theme={null}
<activity android:name=".MainActivity">
    <!-- Handle deep links -->
    <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>
```

#### 2. Handle Deep Link in Activity

```kotlin theme={null}
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Handle deep link
        handleDeepLink(intent)
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        intent?.let { handleDeepLink(it) }
    }

    private fun handleDeepLink(intent: Intent) {
        val data = intent.data ?: return

        // Parse and navigate based on deep link
        when (data.path) {
            "/product" -> {
                val productId = data.getQueryParameter("id")
                navigateToProduct(productId)
            }
            "/profile" -> navigateToProfile()
            else -> {
                // Handle unknown deep link
            }
        }
    }
}
```

***

### Testing Push Notifications

#### 1. Verify Device Token Registration

Check if device token is registered:

```kotlin theme={null}
val deviceToken = Zixflow.instance().registeredDeviceToken
if (deviceToken != null) {
    println("Device token registered: $deviceToken")
} else {
    println("Device token not yet registered")
}
```

#### 2. Enable Debug Logging

Use debug logging to troubleshoot:

```kotlin theme={null}
val config = ZixflowConfigBuilder(this, "YOUR_API_KEY")
    .logLevel(ZixflowLogLevel.DEBUG)  // Enable verbose logging
    .build()
```

View logs in Android Studio Logcat (filter by "Zixflow").

#### 3. Test on Physical Device or Emulator

**Physical Device:** Always works with valid `google-services.json`

**Emulator:** Requires:

* Google Play Services installed
* Signed in with Google account
* Internet connectivity

#### 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

#### google-services.json Not Found

**Error:** `File google-services.json is missing`

**Solution:**

1. Verify `google-services.json` is in `app/` directory
2. Sync Gradle: **File** → **Sync Project with Gradle Files**
3. Clean and rebuild: **Build** → **Clean Project** → **Rebuild Project**

#### Push Notifications Not Received

**Symptoms:** Notifications sent but not delivered

**Solutions:**

1. Verify FCM Server Key configured in Zixflow dashboard
2. Ensure user is identified: `Zixflow.instance().identify(userId = ...)`
3. Check POST\_NOTIFICATIONS permission granted (Android 13+)
4. Verify device token registered: `Zixflow.instance().registeredDeviceToken`
5. Test on physical device or emulator with Google Play Services
6. Check Firebase console for delivery status

#### Device Token Not Registering

**Symptoms:** `registeredDeviceToken` returns `null`

**Solutions:**

1. Verify `google-services.json` is correct and in `app/` directory
2. Ensure `google-services` plugin is applied
3. Check Google Play Services available on device
4. Verify app package name matches Firebase configuration
5. Check logs for FCM token generation errors

#### Notification Not Displayed

**Symptoms:** Push delivered but not shown

**Solutions:**

1. Check notification channels (Android 8.0+)
2. Verify notification permission granted
3. Ensure app not in "Do Not Disturb" mode
4. Check notification settings for your app
5. Verify custom notification callback isn't blocking display

#### Rich Media Not Loading

**Symptoms:** Images/videos not appearing in notifications

**Solutions:**

1. Verify media URL is accessible from device
2. Check internet connectivity
3. Ensure media format is supported (JPEG, PNG, GIF for images)
4. Check file size (large files may timeout)

***

### Best Practices

1. **Always identify users** before sending push notifications
2. **Request permission thoughtfully** - explain value before requesting
3. **Use ACTIVITY\_PREVENT\_RESTART** for better user experience
4. **Test on multiple devices** and Android versions
5. **Enable debug logging** during development
6. **Monitor metrics** in Zixflow dashboard
7. **Handle permission denial gracefully**
8. **Test deep links thoroughly**
9. **Customize notification appearance** to match app branding
10. **Keep google-services.json secure** - don't commit to version control

***
