Skip to main content

SDKs

Four client SDKs, all MIT licensed, all talking to the same /v1 endpoints with the app's pk_live_… public key.

SDKPackagePlatformTransportNotes
iOS (Swift)packages/sdk-ios (Swift Package)iOS 15+APNs directlyNo Firebase. URLSession + UserDefaults, zero dependencies. NSE template included.
Android (Kotlin)com.opennotification:sdk (AAR)minSdk 23FCMFirebase for the token; the SDK draws every notification. HttpURLConnection, no other deps.
React Native@opennotification/react-nativeiOS + AndroidAPNs (native module) / FCM (embedded Kotlin SDK)Native modules ship in the package; no Firebase or Notifee JS packages. Expo config plugin.
Web@opennotification/webBrowsers, PWAsWeb PushCapability detection, iOS install guide, prebuilt service worker.

What they all do

  1. Register the device: token + platform + device facts + the user's language/timezone/country. The API upserts by token, so calling it on every launch is correct and cheap. The returned subscriptionId is persisted locally.
  2. Identity: login(externalId) attaches the device to your user id; logout() detaches it. Rules in Identity.
  3. Tags: setTags merges, removeTags deletes keys. Tags belong to the user and reach every device they own.
  4. Tracking: the SDK reports delivered, opened, clicked and (where the OS allows) dismissed using the signed msgId in the payload. No key needed — the signature is the credential.
  5. Opens: onOpen gives you a normalised message (title, body, url, data, actionId) so you can route. Cold starts are handled — a press that launched the app is replayed once your handler is set.

The normalised message

Whatever the wire format (APNs aps+on, FCM flat data, Web Push JSON), every SDK hands your code the same shape:

FieldTypeNotes
msgIdstring?Signed tracking id. null if the push was not from Open Notification.
campaignIdstring?
title, bodystringAlready in the subscriber's locale, placeholders filled.
imagestring?
urlstring?The deep link. If a button with its own url was pressed, that URL is here.
actions{id,title,url?}[]
actionIdstring?Set when the open came from a button.
dataRecord<string,string>The campaign's data payload.

Errors never throw

Every network-facing call returns a Result ({ ok: true, value } / { ok: false, error } in TypeScript; Result<…> / completion Error? in Swift and Kotlin). Codes are stable strings — permission_denied, no_token, api_error, network_error — so you can branch without parsing messages.

Which key, again

The SDKs take the public key. It can register a device and update that device's own user; it cannot send, read other users or list anything. Shipping it inside an app binary or a web page is the intended use. Never put an sk_ key in a client.