OneSignal Push Notifications Integration
The typical scenario: app already in production, backend team sends notifications directly through APNs/FCM, and it becomes a zoo — separate code for iOS, separate for Android, no analytics for opens, no segments, retries written manually. OneSignal solves this entire stack with a unified API and SDK.
What Actually Happens When SDK is Integrated
OneSignal SDK initializes once at the app's entry point. On Android — in Application.onCreate(), on iOS — in AppDelegate.didFinishLaunchingWithOptions.
// iOS — AppDelegate.swift
OneSignal.initialize("YOUR_APP_ID", withLaunchOptions: launchOptions)
OneSignal.Notifications.requestPermission({ accepted in
print("Permission granted: \(accepted)")
}, fallbackToSettings: true)
// Android — Application.kt
OneSignal.initWithContext(this, "YOUR_APP_ID")
OneSignal.Notifications.requestPermission({ accepted ->
Log.d("OneSignal", "Permission: $accepted")
}, this, true)
OneSignal SDK version 5.x (current at time of writing) transitioned to a modular architecture: OneSignal.User, OneSignal.Notifications, OneSignal.InAppMessages — separate namespaces. This matters when upgrading from version 3.x, where everything was a flat API. Migration isn't trivial: sendTag was replaced with OneSignal.User.addTag, setExternalUserId — with OneSignal.login.
Push Permission on iOS — a separate topic. Apple doesn't allow requesting permission again after refusal. If the user tapped "Don't Allow" — the only way out is to open Settings. So the timing of the request is critical: not on first app launch, but on a screen where the value of notifications is obvious (for example, after creating the first order or enabling tracking).
User Identification and Tags
By default, OneSignal creates an anonymous Player ID (device-level identifier). For business logic, we need binding to the system user:
// After user login
OneSignal.login("user_internal_id_12345")
// Attributes for segmentation
OneSignal.User.addTag("plan", "premium")
OneSignal.User.addTag("city", "kyiv")
OneSignal.User.addTag("last_purchase_days", "3")
Tags are the foundation for segmentation later. They should be designed in advance, otherwise you'll have to force app updates just to add a new tag.
Sending via REST API
Server-side is HTTP REST. Minimal request to send by external_id:
POST https://onesignal.com/api/v1/notifications
{
"app_id": "YOUR_APP_ID",
"include_aliases": { "external_id": ["user_12345"] },
"target_channel": "push",
"contents": { "en": "Your order is ready", "ru": "Ваш заказ готов" },
"data": { "order_id": "98765", "screen": "order_detail" }
}
The data field is a payload for deep link. On the mobile client, it's processed by OSNotificationOpenedHandler:
// iOS
OneSignal.Notifications.addClickListener { event in
if let orderId = event.notification.additionalData?["order_id"] as? String {
AppRouter.navigate(to: .orderDetail(id: orderId))
}
}
Delivery and Analytics
OneSignal provides delivery rate, click rate, influenced opens (user opened the app within 60 seconds after receiving notification, without clicking it). For e-commerce this is an important metric — the notification worked, but the user opened the app differently.
For deeper analytics — OneSignal integrates with Mixpanel, Amplitude through outcome events:
OneSignal.Session.addOutcome("purchase_completed")
OneSignal.Session.addOutcomeWithValue("purchase_amount", 149.99f)
Timeframe
Basic OneSignal SDK integration (iOS + Android or Flutter/RN), configuring APNs/FCM certificates, binding external user ID, implementing open handler — 3–5 working days. If adding server-side send logic, setting up segments and templates in OneSignal Dashboard — another 2–3 days.







