Skip to main content
A notification created in the dashboard or sent through POST /v1/messages can carry a deepLink, a named action, up to four actions buttons, or all three. The SDK parses them into a PushPayload and routes them when the notification is opened, so what a notification does is decided on the server and never needs an app release. Register one closure at launch, after BuzzKit.configure.
The closure runs on every notification whose payload has a deepLink that parses as a URL. When you need more than the URL, implement BuzzKitDelegate instead and return true to say you consumed it.
BuzzKit tries three routes in order and stops at the first that takes the URL. Every routed link is tracked as $deeplink.opened with the url, the messageId, and via set to delegate, handler or system, so you can see in the event stream which links fell through to the system.

Registering named actions

Actions are the half you configure remotely. The app registers handlers by name once, and any message or workflow step can name one with data chosen on the server.
action.name is the name the message used and action.data is a [String: JSONValue] dictionary, so read values by pattern matching the case you expect, or take anyValue for a Foundation object. BuzzKit.actions.unregister("show_offer") removes a handler. Both the handler and the deep link run when a payload carries both: the action first, then the link. Every action is tracked as $action.triggered with name and handled, so a message naming an action no build has a handler for is visible in the event stream rather than silent. On the device it logs a warning and does nothing else.
Ship a small set of capable handlers, such as opening a paywall, a screen or a purchase flow, then decide in the dashboard which notification calls which with what data. That is what lets you change a campaign’s destination without shipping an app update.

Action buttons

Buttons come from the message’s actions array, each with id, title, destructive, foreground, input and placeholder. The notification service extension turns them into a UNNotificationCategory before the notification is displayed, using the message’s category or a category id derived from the buttons themselves. Buttons therefore need the extension in your app: without it the notification still arrives, with no buttons on it. A button with input: true becomes a UNTextInputNotificationAction whose placeholder is the field’s placeholder text. The tapped button reaches your app through the delegate.
actionIdentifier is the button’s id, and nil when the person tapped the notification body rather than a button. payload.data holds the message’s custom data exactly as sent.
Text a person types into an input button is reported to BuzzKit as the input field of the $notification.opened event, and is not passed to the delegate. Read it from the subscriber’s event stream, or branch on it in a workflow.

Delivered and opened receipts

Three events tell you what happened to each notification, all carrying the messageId of the send that produced them. Opened and dismissed receipts work with no setup beyond BuzzKit.configure. Delivered receipts need a notification service extension, because that is the only code Apple runs for a notification the person has not touched. It is the same extension that registers action buttons, so adding it once turns on both.
BuzzKit sets mutable-content on every message carrying an image or buttons, which is what makes iOS launch the extension in the first place.
The extension gets only a few seconds of runtime. With an app group shared between the app and the extension, a receipt that cannot reach the API in that window is written to the shared container and delivered on the app’s next launch. Without one, receipts are best effort.

Receipts and the delivery ledger

The two records answer different questions and both are worth reading. The delivery ledger is the server’s view: one delivery per device with every attempt, the exact payload sent, the provider’s response and a latency. It reaches sent when APNs accepted the notification, which is the most a push provider ever confirms. Receipts are the device’s view, and they arrive as events on the subscriber rather than as changes to delivery rows. $notification.delivered is the proof the notification actually landed on a phone, and $notification.opened is what open rates are computed from. Workflows read the same events: an opened or delivered condition on an earlier send step branches on exactly these receipts.

Next

Sending messages

The deepLink, action and actions fields that produce all of this.

Delivery and retries

Deliveries, attempts and what the provider said.

Events

Tracking your own events, and the reserved ones the SDK sends.

Local notifications

Notifications a workflow hands the device to schedule itself.