Skip to content

Push Notification Analytics

The MovableInk SDK provides automatic tracking for push notification opens. This allows you to measure engagement and attribute conversions to your push campaigns.

Setup

Call handlePushNotificationOpened(_:) when a user opens a push notification to allow the SDK to check if it is a MovableInk notification and track the open event.

If your app uses the UserNotifications framework, implement the delegate method in your UNUserNotificationCenterDelegate:

import UserNotifications
import MovableInk

class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate {
  func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse,
    withCompletionHandler completionHandler: @escaping () -> Void
  ) {
    // Track the notification open with MovableInk
    MIClient.userNotificationCenter(center, didReceive: response)

    // Your app's notification handling logic here

    completionHandler()
  }
}

UIApplicationDelegate

Alternatively, if you aren't using the UserNotifications framework, you'll need to use the UIApplicationDelegate method:

import MovableInk

func application(
  _ application: UIApplication,
  didReceiveRemoteNotification userInfo: [AnyHashable: Any]
) {
  MIClient.handlePushNotificationOpened(userInfo)

  // Your app's notification handling logic here
}

Manual Tracking | Without SDK

If you're not using the SDK, you can still track this event by manually making a request to the URL in the payload.

Using UserNotifications Framework

If your app uses the UserNotifications framework, you can extract the URL from the notification payload and make a request when the notification is opened.

import UserNotifications

func userNotificationCenter(
  _ center: UNUserNotificationCenter,
  didReceive response: UNNotificationResponse,
  withCompletionHandler completionHandler: @escaping () -> Void
) {
  guard let userInfo = response.notification.request.content.userInfo as? [String: Any] else {
    completionHandler()
    return
  }

  // Try to extract URL from either "mi" or "data" container
  var urlString: String?

  // First, check for the standard "mi" container format
  if let miContainer = userInfo["mi"] as? [String: Any] {
    urlString = miContainer["url"] as? String
  }

  // Also check for "data" container format (mi_url and mi_source)
  if urlString == nil, let dataContainer = userInfo["data"] as? [String: Any] {
    urlString = dataContainer["mi_url"] as? String
  }

  // If we found a URL string, resolve it
  if let urlString = urlString, let url = URL(string: urlString) {
    Task {
      let _ = try await URLSession.shared.data(for: URLRequest(url: url))
    }
  }
}

Without UserNotifications Framework

If you're not using the UserNotifications framework, you can extract the URL from the notification payload in the UIApplicationDelegate method.

func application(
  _ application: UIApplication,
  didReceiveRemoteNotification userInfo: [AnyHashable: Any]
) {
  // Try to extract URL from either "mi" or "data" container
  var urlString: String?

  // First, check for the standard "mi" container format
  if let miContainer = userInfo["mi"] as? [String: Any] {
    urlString = miContainer["url"] as? String
  }

  // Also check for "data" container format (mi_url and mi_source)
  if urlString == nil, let dataContainer = userInfo["data"] as? [String: Any] {
    urlString = dataContainer["mi_url"] as? String
  } 

  // If we found a URL string, resolve it
  if let urlString = urlString, let url = URL(string: urlString) {
    Task {
      let _ = try await URLSession.shared.data(for: URLRequest(url: url))
    }
  }
}