Link handling
The SDK passes links to the application when a user triggers them from stories, games, In-App Messages, or banners.
The link is passed as a target string. The application decides what to do with it: open an in-app screen, handle a deeplink, show an in-app browser, or open the link through the system.
Always set an explicit link handler. If no handler is set, the SDK may try to open the link automatically in some scenarios, but this should not be the main application logic. In newer iOS versions, system deeplink opening through fallback mechanisms may be unstable. In your own code, use UIApplication.shared.open(_:options:completionHandler:).
What to Choose
The handler depends on the type of content shown by the application.
- UIKit
StoryView, single stories, onboardings, games, IAM - use the globalInAppStory.shared.onActionWithhandler. - SwiftUI
StoryListView- use the local.onAction. - SwiftUI
.singleStory(...)and.onboardingStories(...)- use the localonActiondirectly in the modifier. - Banners - use only the banner's local handler:
IASBannersView.onActionWithorIASBannersListView.onAction(...).
InAppStory.shared.onActionWith is not called for banners. If a banner link does not open, first check that the banner's local handler is set. See banner link handling for details.
The declarative SwiftUI API has local .onAction handlers. For StoryListView, .singleStory(...), and .onboardingStories(...), use those handlers. This is clearer and more reliable than relying on the global InAppStory.shared.onActionWith.
Quick Start
In most cases, link handling consists of three steps:
- receive
targetin a callback; - close the current SDK content with
closeReader(...); - open an application screen or a system link.
func handleSDKLink(_ target: String) {
InAppStory.shared.closeReader {
openTarget(target)
}
}
In all examples below, handleSDKLink(target) is the function from this section.
func openTarget(_ target: String) {
// First, you can check the application's own deeplink routes.
// For example: if router.open(target) { return }
guard let url = URL(string: target) else {
return
}
UIApplication.shared.open(url, options: [:]) { success in
if !success {
// Here you can show an error or handle the link another way.
}
}
}
closeReader(complete:) closes:
- onboarding reader;
- single story reader;
- story reader opened from a
StoryViewlist; - stack reader;
- IAM reader;
- standalone game, if there are no other readers currently open.
If there is nothing to close, complete is still called. Therefore, basic link navigation does not need to be split by type.
- UIKit
- SwiftUI
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// SDK initialization.
InAppStory.shared.initWith(serviceKey: <String>)
InAppStory.shared.settings = Settings(userID: <String>, tags: <Array<String>>)
// Global link handler for UIKit stories, single stories,
// onboardings, games, and IAM.
InAppStory.shared.onActionWith = { target, type, storyType in
// handleSDKLink(target) is described above in the "Quick Start" section.
handleSDKLink(target)
}
return true
}
StoriesScreenView.swift
struct StoriesScreenView: View {
var body: some View {
StoryListView()
.onAction { target, type, storyType in
// handleSDKLink(target) is described above in the "Quick Start" section.
handleSDKLink(target)
}
.frame(height: 150.0)
}
}
App.swift
@main
struct DemoApp: App {
init() {
// SDK initialization.
InAppStory.shared.initWith(serviceKey: <String>)
InAppStory.shared.settings = Settings(userID: <String>, tags: <Array<String>>)
// The global handler is still needed for IAM and standalone games.
InAppStory.shared.onActionWith = { target, type, storyType in
// handleSDKLink(target) is described above in the "Quick Start" section.
handleSDKLink(target)
}
}
var body: some Scene {
WindowGroup {
StoriesScreenView()
}
}
}
Global Handler InAppStory.shared.onActionWith
Use the global handler when links should be handled in one place in the application.
It works for:
- UIKit
StoryView, if the specificStoryViewdoes not have a localonActionWith; single stories, opened withInAppStory.shared.showStory(...);onboardings, opened withInAppStory.shared.showOnboardings(...);games, opened withInAppStory.shared.openGame(...);In-App Messages.
It does not work for banners.
Signature
InAppStory.shared.onActionWith = { target, type, storyType in
// target: String
// type: ActionType
// storyType: StoriesType?
}
target: String- the link or deeplink received from the SDK;type: ActionType- the action type that triggered the link. SeeActionType;storyType: StoriesType?- the story source, if any. SeeStoriesType.
type is useful for analytics, logging, or rare business logic. But for basic navigation, you usually do not need to write switch type: wrap the transition in closeReader(...) and handle target in complete.
Callback Parameters
.button- the user tapped a button inside a story, IAM, or other content;.swipe- the SwipeUp widget was triggered;.game- the link came from a game;.deeplink- the link came from a story list cell when the story has a deeplink configured in the dashboard.
.list(feed: String?)- the link came from a story opened from aStoryViewlist;.single- the link came from a single story;.onboarding(feed: String)- the link came from an onboarding;nil- the action has no story source.
storyType == nil as an errorstoryType == nil is a normal value. For example, it comes from IAM and standalone games. Do not use nil as an error indicator.
Content Examples
- UIKit
- SwiftUI
Stories from StoryView
StoryView shows a list of stories. If the specific StoryView does not have a local onActionWith, links from its reader will be sent to the global handler set in AppDelegate at the beginning of this document.
final class ViewController: UIViewController {
private let storyView = StoryView(frame: .zero)
override func viewDidLoad() {
super.viewDidLoad()
// The global InAppStory.shared.onActionWith is set in AppDelegate at the beginning of this document.
// Local storyView.onActionWith is not set here.
view.addSubview(storyView)
// StoryView size and layout setup.
// ...
storyView.create()
}
}
Single story
A single story is opened by ID or slug. A link from it will be sent to the global InAppStory.shared.onActionWith with storyType == .single.
InAppStory.shared.showStory(with: <String>, from: self, with: <PanelSettings?>) { shown in
// shown == true if the single story was opened.
}
Onboarding
Onboarding opens a separate onboarding feed. A link from it will be sent to the global InAppStory.shared.onActionWith with storyType == .onboarding(feed: ...).
InAppStory.shared.showOnboardings(from: self) { shown in
// shown == true if the onboarding was opened.
}
Standalone game
A standalone game is opened without a story reader. A link from such a game will be sent to the global InAppStory.shared.onActionWith with type == .game and storyType == nil.
InAppStory.shared.openGame(with: Game(id: <String>), from: self) { opened in
// opened == true if the game was opened.
}
IAM
IAM is not a story, so a link from IAM will be sent to the global InAppStory.shared.onActionWith with storyType == nil.
InAppStory.shared.showInAppMessageWith(id: <String>, targetView: view) { shown in
// shown == true if the IAM was shown.
}
Single story
In SwiftUI, it is more convenient to handle a single story locally through onAction in the modifier. This handler belongs only to this specific single story presentation.
.singleStory(
storyID: <String>,
isPresented: $isSinglePresented,
onAction: { target, type in
// handleSDKLink(target) is described above in the "Quick Start" section.
handleSDKLink(target)
}
)
Onboarding
For SwiftUI onboarding, use the local onAction in .onboardingStories(...). This keeps the handler tied to this specific declarative onboarding presentation.
.onboardingStories(
isPresented: $isOnboardingPresented,
onAction: { target, type in
// handleSDKLink(target) is described above in the "Quick Start" section.
handleSDKLink(target)
}
)
Standalone game
A standalone game in SwiftUI is opened with the same InAppStory.shared.openGame(...) method. Links from the game are handled by the global InAppStory.shared.onActionWith set in App.swift at the beginning of this document.
Button("Show game") {
InAppStory.shared.openGame(with: Game(id: <String>)) { opened in
// opened == true if the game was opened.
}
}
IAM
For IAM in SwiftUI, register a container and show the message with showIAMWith(...). Links from IAM are handled by the global InAppStory.shared.onActionWith set in App.swift at the beginning of this document.
content
.inAppMessageContainer()
.onAppear {
InAppStory.shared.showIAMWith(id: <String>) { shown in
// shown == true if the IAM was shown.
}
}
Local Story Handlers
Use a local handler when a specific story list should handle links differently from the rest of the application.
Priorities
If StoryView has a local onActionWith, the global InAppStory.shared.onActionWith will not be called for that action.
The call order is:
- the SDK checks local
StoryView.onActionWith; - if the local handler is set, only that handler is called;
- if the local handler is not set,
InAppStory.shared.onActionWithis called; - if neither handler is set, the SDK may try to open the link automatically.
UIKit StoryView
let storyView = StoryView(frame: .zero)
storyView.onActionWith = { target, type, storyType in
// handleSDKLink(target) is described above in the "Quick Start" section.
handleSDKLink(target)
}
storyView.create()
Local handler signature:
storyView.onActionWith = { target, type, storyType in
// target: String
// type: ActionType
// storyType: StoriesType
}
In local StoryView.onActionWith, storyType is not optional because the link always comes from a specific story list.
SwiftUI StoryListView
StoryListView(feed: "main")
.onAction { target, type, storyType in
// handleSDKLink(target) is described above in the "Quick Start" section.
handleSDKLink(target)
}
.frame(height: 150.0)
SwiftUI single story and onboarding
For declarative SwiftUI modifiers, use the local onAction directly in the modifier:
.singleStory(
storyID: <String>,
isPresented: $isSinglePresented,
onAction: { target, type in
// handleSDKLink(target) is described above in the "Quick Start" section.
handleSDKLink(target)
}
)
.onboardingStories(
isPresented: $isOnboardingPresented,
onAction: { target, type in
// handleSDKLink(target) is described above in the "Quick Start" section.
handleSDKLink(target)
}
)
SwiftUI modifiers .singleStory(...) and .onboardingStories(...) use InAppStory.shared.onActionWith inside the SDK. If the global InAppStory.shared.onActionWith is set beforehand, the modifier may replace it with its own handler when presenting. Therefore, for the declarative SwiftUI API, set onAction directly in the modifier.
Banner Link Handling
Banners handle links separately from stories, games, and IAM. The global InAppStory.shared.onActionWith is not called for banners.
For banners, use:
- UIKit:
IASBannersView.onActionWith; - SwiftUI:
IASBannersListView.onAction(...).
If the banner's local handler is not set, the application will not receive the link and will not open it. The SDK will send an internal banner click event, but it will not call InAppStory.shared.onActionWith and will not open target automatically.
Signature
public typealias BannerOnActionType = ((_ target: String) -> Void)
target: String- the link received from the banner.
- UIKit
- SwiftUI
ViewController.swift
final class ViewController: UIViewController {
private var bannersView: IASBannersView!
override func viewDidLoad() {
super.viewDidLoad()
bannersView = IASBannersView(
placeID: <String>,
appearance: IASBannersAppearance(),
frame: .zero
)
bannersView.onActionWith = { target in
// handleSDKLink(target) is described above in the "Quick Start" section.
handleSDKLink(target)
}
view.addSubview(bannersView)
// Banner size and layout setup.
// ...
bannersView.create()
}
}
BannersScreenView.swift
struct BannersScreenView: View {
var body: some View {
IASBannersListView(
id: <String>,
appearance: IASBannersAppearance()
)
.onAction { target in
// handleSDKLink(target) is described above in the "Quick Start" section.
handleSDKLink(target)
}
.frame(height: 120.0)
.frame(maxWidth: .infinity)
}
}
For more information about banner setup and configuration, see Banners place.
If the Link Does Not Arrive
Check that the handler matches the content type:
- For UIKit
StoryView, check that there is no localstoryView.onActionWithoverriding the globalInAppStory.shared.onActionWith. - For SwiftUI
StoryListView, set a local.onAction. - For SwiftUI
.singleStory(...)and.onboardingStories(...), setonActiondirectly in the modifier. - For banners, set
IASBannersView.onActionWithorIASBannersListView.onAction(...). - Check that the handler does not split actions with
switch typeorActionTypein a way that leaves some types without handling. For basic link opening, it is usually enough to callcloseReader(...)and handletargetincomplete. - Check that the SDK is initialized and that
create()has been called for widgets that require internal logic to start. - Check that
targetcan be parsed as aURLif you open it withUIApplication.shared.open(...).