Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.suprsend.com/llms.txt

Use this file to discover all available pages before exploring further.

The SDK provides the data layer only — no built-in UI. Bind to its data and events and render your own.

Prerequisites

Integration of iOS SDK.

Initialize Feed Client

// create feed instance
let feed: Feed = SuprSend.shared.feeds.initialize(options: IFeedOptions?)
Options
ParameterTypeDescription
tenantIdString?Tenant to read from. Defaults to “default” tenant
pageSizeUInt?Notifications per page. Defaults to 20
stores[IStore]?Filtered views inside feed (see Stores)
hostFeedHost?Override API/socket host via FeedHost(socketHost:apiHost:)
If you are passing tenant_id in feed, make sure to pass the scope key while creating userToken passed during identifying user, else a 403 error will be thrown due to scope mismatch.

Feed Client

Get Feed Data Store

Returns the current notification store — the list of notifications plus metadata like page info and badge counts. You can call this anytime to get updated store data.
let feedData: IFeedData = feed.data

feedData.notifications     // [IRemoteNotification] — list of notifications
feedData.store             // IStore — active store
feedData.pageInfo          // IPageInfo — .total, .hasMore, .pageSize
feedData.meta              // "badge" — latest notifs count since last opened, per-store unread counts
feedData.apiStatus         // .initial / .loading / .success / .error / .fetchingMore

Initialize Socket for Realtime Updates

feed.initializeSocketConnection()
Keep exactly one active socket per feed. Multiple live sockets cause duplicated events, doubled badge increments, and inflated counts. Avoid:
  • Recreating the feed without teardown. removeAll() (or removeInstance(_:)) the old feed before calling feeds.initialize(...) again.
  • Owning the feed somewhere short-lived. A feed re-created with its view opens a socket each time; own it in a single, stable place and reuse it.
  • Skipping cleanup on dismiss/logout. An unclosed socket keeps running in the background — tear down in deinit or on logout.

Fetch Notification Data

Gets the first page of notifications from the SuprSend server and sets it in the notification store (it also fetches badge counts on the first call).
await feed.fetch()

Fetch More Notifications

Gets the next page and appends it to the notification store. Call this only when pageInfo.hasMore == true.
await feed.fetchNextPage()

Listening for Updates

Subscribe to feed.emitter to keep your UI in sync. It fires two events:
  • .storeUpdate — the notification store changed (new notification, state update, pagination, mutations, socket events). Listen to this and update your local state so that the UI is refreshed.
  • .newNotification — use this listener to show a toast notification when a new notification is received.
public enum InboxEmitterEvents {
    case storeUpdate(IFeedData)                // store changed — re-render UI
    case newNotification(IRemoteNotification)  // new notification arrived
}
feed.emitter
    .receive(on: RunLoop.main)
    .sink { [weak self] event in
        switch event {
        case .storeUpdate(let data):                self?.render(data)
        case .newNotification(let notification):    self?.showToast(for: notification)
        }
    }
    .store(in: &cancellables)

Removing Feed

Removes the feed client and aborts its socket connection.
SuprSend.shared.feeds.removeInstance(feed)  // one instance
SuprSend.shared.feeds.removeAll()           // all active inbox instances
deinit { SuprSend.shared.feeds.removeAll() }
Reconnecting: In background mode iOS suspends app activity. When the app comes from background to foreground, remove existing feed instances and reconnect the socket and emitters, then refetch data.

Action Methods

// Change active store (when using multi-tab stores)
await feed.changeActiveStore(storeId: String)

// Reset the bell-icon badge count
await feed.resetBadgeCount()

// Mark notifications as seen
await feed.markBulkAsSeen(notificationIds: [String])

// Mark all notifications as read
await feed.markAllAsRead()

// Mark notification as read
await feed.markAsRead(notificationId: String)

// Mark notification as unread
await feed.markAsUnread(notificationId: String)

// Mark notification as interacted
await feed.markAsInteracted(notificationId: String)

// Archive notification
await feed.markAsArchived(notificationId: String)
Read more about seen, read, and interacted. Response returned by the action methods (markAsRead, changeActiveStore, etc.):
public class APIResponse: NSObject, Response {
    public let status: ResponseStatus     // .success or .error
    public let statusCode: StatusCode?    // HTTP status code (Int)
    public let body: ResponseBody?        // [String: String]
    public let error: ResponseError?      // type and message, when status == .error
}

Notification Structure

public class IRemoteNotification: NSObject, Codable {
    public let n_id: String                          // unique notif id
    public let message: IRemoteNotificationMessage   // actual notif message content
    public let created_on: TimeInterval              // notif creation timestamp
    public let seen_on: TimeInterval?                // notif seen timestamp
    public let read_on: TimeInterval?                // notif read timestamp
    public let interacted_on: TimeInterval?          // notif interacted timestamp
    public let archived: Bool?                       // if notif is archived
    public let is_pinned: Bool                       // if notif is pinned
    public let expiry: TimeInterval?                 // milliseconds since epoch to expiry
    public let is_expiry_visible: Bool               // show timer to user till expiry
}

public class IRemoteNotificationMessage: NSObject, Codable {
    public let header: String?                        // title
    public let text: String                           // body
    public let subtext: ISubTextObject?               // subtext
    public let avatar: IAvatarObject?                 // avatar img and click url
    public let url: String?                           // action url
    public let actions: [IActionObject]?              // action buttons
    public let extra_data: String?                    // arbitrary JSON string
}

Notification States

  • Seen: seen_on flag is used to check if the notification has been seen in SuprSend analytics. If it’s null, the notification has not been seen yet — call markBulkAsSeen when the notification enters the viewport and seen_on is null.
  • Read: read_on flag is used to check if the notification has been read. This doesn’t update SuprSend analytics and is only for visual purposes. If read_on is null, show a dot on the notification indicating it’s unread. Call markAsRead when read_on is null, or markAsUnread when read_on has a timestamp. Marking as read will also set seen_on if not already set.
  • Interacted: interacted_on flag is used to set the notification as clicked in SuprSend analytics. If interacted_on is null and the user clicks on the notification, call markAsInteracted. This will also set read_on and seen_on if not already set.