Insider • Documentation • MIT License
This project demonstrates how to integrate the Insider iOS SDK into a Swift application using Swift Package Manager, CocoaPods, or Carthage. It includes a fully working example with push notification extensions and all major SDK features.
| Requirement | Minimum |
|---|---|
| iOS | 12.0 (SPM) / 13.0 (CocoaPods) |
| Swift | 5.3+ |
| Xcode | 14.0+ |
The project ships two flavors of the example app — one for the classic native SDK (InsiderMobile + InsiderGeofence), and one for the InsiderWebView SDK — each provided as three schemes (SPM, CocoaPods, Carthage). Shared code is split into per-flavor directories that are wired into every target via Xcode's file-system synchronized groups.
Shared/ # Used by every app target
├── Sources/
│ ├── AppDelegate.swift # SDK initialization & callbacks
│ ├── SceneDelegate.swift # Deep link handling
│ ├── NotificationService.swift # Rich push (Service Extension)
│ └── NotificationViewController.swift # Interactive push (Content Extension)
└── Resources/
├── Assets.xcassets
└── Base.lproj/LaunchScreen.storyboard
Native/ # Used by Example{SPM,Pods,Carthage}
├── Sources/
│ ├── Actions/ # SDK feature implementations
│ ├── ViewControllers/ # UI
│ ├── Views/, Utilities/, Design/, Additions/
└── Resources/
├── Colors.xcassets, Images.xcassets
└── Fonts/{Figtree,RedHatDisplay}
WebView/ # Used by ExampleWebView{SPM,Pods,Carthage}
├── Sources/MainViewController.swift
└── Resources/{index.html, WebView.storyboard}
Example{SPM,Pods,Carthage}/ # Per-target Info.plist + entitlements
ExampleWebView{SPM,Pods,Carthage}/ # Per-target Info.plist + entitlements
InsiderNotificationService{SPM,Pods,Carthage}/
InsiderNotificationContent{SPM,Pods,Carthage}/
| Scheme | Dependency Manager | Flavor | SDKs |
|---|---|---|---|
ExampleSPM |
Swift Package Manager | Native | InsiderMobile, InsiderGeofence, InsiderMobileAdvancedNotification |
ExamplePods |
CocoaPods | Native | InsiderMobile, InsiderGeofence, InsiderMobileAdvancedNotification |
ExampleCarthage |
Carthage | Native | InsiderMobile, InsiderGeofence, InsiderMobileAdvancedNotification |
ExampleWebViewSPM |
Swift Package Manager | WebView | InsiderMobile, InsiderWebView |
ExampleWebViewPods |
CocoaPods | WebView | InsiderMobile, InsiderWebView |
ExampleWebViewCarthage |
Carthage | WebView | InsiderMobile, InsiderWebView |
All targets live in Example.xcworkspace. Each native scheme has its own Notification Service and Notification Content extension targets.
git clone git@github.com:useinsider/SwiftDemo.git
cd SwiftDemoChoose one of the following methods:
Swift Package Manager
No extra steps required. Open Example.xcworkspace and select the ExampleSPM scheme. Xcode resolves packages automatically.
If you are integrating the SDK into your own project, add the package in Xcode as follows:
-
Go to File → Add Package Dependencies...
-
Enter the repository URL:
https://github.com/useinsider/Insider-iOS-SDK -
Select your project under Add to Project and click Add Package.
Important: When adding the Insider-iOS-SDK package, you must add all SDKs (including
InsiderMobileAdvancedNotification) to the main app target (e.g.ExampleSPM), not to the service or content extension targets.![]()
CocoaPods
pod installOpen Example.xcworkspace and select the ExamplePods scheme.
The Podfile includes:
platform :ios, '13.0'
use_frameworks!
target 'ExamplePods' do
pod 'InsiderMobile'
pod 'InsiderGeofence'
end
target 'ExampleWebViewPods' do
pod 'InsiderMobile'
pod 'InsiderWebView'
end
target 'InsiderNotificationServicePods' do
pod 'InsiderMobileAdvancedNotification'
end
target 'InsiderNotificationContentPods' do
pod 'InsiderMobileAdvancedNotification'
endCarthage
carthage update --use-xcframeworks --platform iOSOpen Example.xcworkspace and select the ExampleCarthage scheme.
The Cartfile includes:
binary "https://mobilesdk.useinsider.com/carthage/InsiderWebView/1.0.0/InsiderWebView.json"
binary "https://mobilesdk.useinsider.com/carthage/InsiderGeofence/1.2.4/InsiderGeofence.json"
binary "https://mobilesdk.useinsider.com/carthage/InsiderMobile/15.0.3/InsiderMobile.json"
binary "InsiderMobileAdvancedNotification.json"
After building, link the frameworks from Carthage/Build/ in your target's Frameworks, Libraries, and Embedded Content section.
Before running, update the following values with your own:
- Partner Name in
Shared/Sources/AppDelegate.swift:
Insider.initWithLaunchOptions(
nil,
partnerName: "YOUR_PARTNER_NAME",
appGroup: "YOUR_APP_GROUP"
)-
App Group identifier in all three files:
Shared/Sources/AppDelegate.swiftShared/Sources/NotificationService.swiftShared/Sources/NotificationViewController.swift
-
Signing & Capabilities for every target (app + both extensions):
- Set your development team
- Enable Push Notifications
- Add an App Groups capability with the same identifier used above
- Enable Background Modes: Remote notifications, Location updates, Background processing
Important: The App Group identifier must be identical across the main app target and both notification extension targets.
Verify that the
com.apple.security.application-groupsvalue in each target's.entitlementsfile matches theappGroupparameter passed toInsider.initWithLaunchOptions.A mismatch will prevent the SDK from sharing data between the app and its extensions.
- URL Scheme: In target's Info tab under URL Types, set the scheme to match your partner name (e.g.,
insideryourpartnername).
The SDK is initialized in AppDelegate.swift:
import InsiderMobile
import UIKit
@main
public final class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
public func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
UNUserNotificationCenter.current().delegate = self
// Register callback handler for SDK events
Insider.registerCallback(with: #selector(insiderCallback(_:)), sender: self)
// Initialize with your partner name and app group
Insider.initWithLaunchOptions(nil, partnerName: "YOUR_PARTNER_NAME", appGroup: "YOUR_APP_GROUP")
// Show push notifications while app is in foreground
Insider.setActiveForegroundPushView()
return true
}
}Deep links are handled in SceneDelegate.swift:
import InsiderMobile
import UIKit
public final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
public var window: UIWindow?
public func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
for urlContext in connectionOptions.urlContexts {
Insider.handle(urlContext.url)
}
}
}@objc public func insiderCallback(_ dict: [String: Any]) {
if let typeAsInt = dict["type"] as? Int,
let type = InsiderCallbackType(rawValue: typeAsInt) {
switch type {
case .notificationOpen:
// Handle push notification tap
break
case .inAppSeen:
// Handle in-app message impression
break
case .inappButtonClick:
// Handle in-app button interaction
break
case .sessionStarted:
// Handle session start
break
case .tempStoreAddedToCart, .tempStorePurchase, .tempStoreCustomAction:
// Handle e-commerce events
break
}
}
}The SDK requires two notification extensions for full push notification support:
- Notification Service Extension — Intercepts incoming push notifications to download rich media (images, videos) before display. See
Shared/Sources/NotificationService.swift. - Notification Content Extension — Provides an interactive carousel UI for expanded push notifications. See
Shared/Sources/NotificationViewController.swift.
Both extensions must share the same App Group identifier as the main app target. Refer to the source files for the complete implementation.
The Notification Content Extension's Info.plist must include the following entries:
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>UNNotificationExtensionCategory</key>
<string>insider_int_push</string>
<key>UNNotificationExtensionDefaultContentHidden</key>
<false/>
<key>UNNotificationExtensionInitialContentSizeRatio</key>
<real>0.5</real>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>InsiderInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.usernotifications.content-extension</string>
</dict>CocoaPods copies InsiderInterface.storyboard from the SDK into your build automatically. However, the storyboard's view controller does not have a Module set by default, which means the NotificationViewController class will not be resolved at runtime.
After running pod install, you need to configure it manually:
-
Open
Pods/InsiderMobileAdvancedNotification/Resources/InsiderInterface.storyboardin Xcode:
-
Select the Notification View Controller scene.
-
In the Identity Inspector, set:
- Class:
NotificationViewController - Module: Your Notification Content Extension target name (e.g.
InsiderNotificationContentPods) - Keep Inherit Module From Target unchecked
- Class:
Important: Running
pod installmay reset the storyboard to its original state. You may need to re-apply this change after eachpod install.
Unlike CocoaPods, SPM and Carthage do not automatically provide the InsiderInterface.storyboard file. You need to create it manually in your Notification Content Extension target.
Copy the InsiderInterface.storyboard from this project (e.g. InsiderNotificationContentSPM/InsiderInterface.storyboard) into your Notification Content Extension target, then open it in Xcode and check the Inherit Module From Target box field in the Identity Inspector to match your target name.
The ExampleWebView{SPM,Pods,Carthage} schemes demonstrate the InsiderWebView SDK. The whole demo lives in WebView/:
WebView/
├── Sources/MainViewController.swift # Hosts a WKWebView and wires up the SDK
└── Resources/
├── WebView.storyboard # @IBOutlet for the WKWebView
└── index.html # Demo page that talks to the SDK
MainViewController hands the WKWebView to the SDK via a single call, then loads the demo page:
import InsiderMobile
import InsiderWebView
import UIKit
import WebKit
public final class MainViewController: UIViewController {
@IBOutlet private weak var webView: WKWebView!
public override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 16.4, *) {
webView.isInspectable = true
}
Insider.setupWebViewSDK(on: webView)
// ...load the page (see below)
}
}The demo ships two ways of feeding index.html to the web view — pick whichever fits your workflow.
The WebView/Resources folder is copied into the app bundle at build time, so index.html is available via Bundle.main:
if let htmlPath = Bundle.main.path(forResource: "index", ofType: "html") {
let url = URL(fileURLWithPath: htmlPath)
webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
}This is the default in MainViewController.viewDidLoad(). Use it when you want the page to ship with the app and work offline.
While iterating on index.html, it is faster to serve the file over HTTP so you can edit and refresh without rebuilding the app. From the repository root, run:
python3 -m http.server 8080 --directory WebView/ResourcesThen replace the bundle-loading block in MainViewController.viewDidLoad() with:
if let url = URL(string: "http://localhost:8080/index.html") {
webView.load(URLRequest(url: url))
}Note: iOS blocks plaintext HTTP traffic by default. To load
http://localhost:...you must either setNSAllowsLocalNetworking(orNSAllowsArbitraryLoads) underNSAppTransportSecurityin the target'sInfo.plist, or serveindex.htmlover HTTPS. When testing on a physical device, replacelocalhostwith the host machine's LAN IP and make sure both devices are on the same network.
When the page loaded in the WebView is part of a TypeScript codebase, you can get full type-safety and autocompletion for the JavaScript bridge that Insider.setupWebViewSDK(on:) injects. The WebView/Resources/InsiderWebViewScript.d.ts file in this repository ships the ambient type declarations for that bridge — there is no runtime code in it; it only describes the API that the native SDK exposes at runtime as window.insider.
It declares:
- A global
window.insiderof typeInsider(the bridge entry point). - Classes / enums you can construct in TypeScript:
InsiderEvent,InsiderProduct,InsiderIdentifiers,InsiderUser,CloseButtonPosition. - Supporting types:
Insider,InsiderIDListener,InsiderListenerRegistration,MessageCenterMessage,ParameterMap.
Copy InsiderWebViewScript.d.ts into your web app's source tree (e.g. src/types/) and reference it in tsconfig.json:
{
"include": ["src/**/*", "src/types/InsiderWebViewScript.d.ts"]
}Alternatively, put a triple-slash reference at the top of your entry file:
/// <reference path="./types/InsiderWebViewScript.d.ts" />That is enough to make window.insider strongly typed everywhere — no import needed because the file augments the global Window interface.
All calls are checked at compile time — wrong parameter shapes or types will fail tsc before they ever reach the device. Note that event and parameter keys are typed as plain string, so they are not constrained at compile time; follow the SDK's naming rules (lowercase, starts with a letter, only a–z, 0–9, _).
async function onPurchase() {
const product = window.insider
.createNewProduct(
'prod-123',
'Headphones',
['Audio', 'Headphones'],
'https://cdn.example.com/p/123.jpg',
199.99,
'USD'
)
.setBrand('Acme')
.setSalePrice(149.99)
.setStock(42);
await window.insider.itemPurchased('sale-789', product, { campaign: 'spring_sale' });
}This project is licensed under the MIT License. See the LICENSE file for details.

