Skip to main content

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.

tip

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 global InAppStory.shared.onActionWith handler.
  • SwiftUI StoryListView - use the local .onAction.
  • SwiftUI .singleStory(...) and .onboardingStories(...) - use the local onAction directly in the modifier.
  • Banners - use only the banner's local handler: IASBannersView.onActionWith or IASBannersListView.onAction(...).
Main exception

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.

SwiftUI

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:

  1. receive target in a callback;
  2. close the current SDK content with closeReader(...);
  3. 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 StoryView list;
  • 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.

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
}

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 specific StoryView does not have a local onActionWith;
  • single stories, opened with InAppStory.shared.showStory(...);
  • onboardings, opened with InAppStory.shared.showOnboardings(...);
  • games, opened with InAppStory.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. See ActionType;
  • storyType: StoriesType? - the story source, if any. See StoriesType.
tip

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

ActionType:

  • .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.

StoriesType:

  • .list(feed: String?) - the link came from a story opened from a StoryView list;
  • .single - the link came from a single story;
  • .onboarding(feed: String) - the link came from an onboarding;
  • nil - the action has no story source.
Do not treat storyType == nil as an error

storyType == nil is a normal value. For example, it comes from IAM and standalone games. Do not use nil as an error indicator.

Content Examples

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.
}

Local Story Handlers

Use a local handler when a specific story list should handle links differently from the rest of the application.

Priorities

Pitfall

If StoryView has a local onActionWith, the global InAppStory.shared.onActionWith will not be called for that action.

The call order is:

  1. the SDK checks local StoryView.onActionWith;
  2. if the local handler is set, only that handler is called;
  3. if the local handler is not set, InAppStory.shared.onActionWith is called;
  4. 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)
}
)
Pitfall

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.

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(...).
Why a banner link does not open

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.

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()
}
}

For more information about banner setup and configuration, see Banners place.

Check that the handler matches the content type:

  • For UIKit StoryView, check that there is no local storyView.onActionWith overriding the global InAppStory.shared.onActionWith.
  • For SwiftUI StoryListView, set a local .onAction.
  • For SwiftUI .singleStory(...) and .onboardingStories(...), set onAction directly in the modifier.
  • For banners, set IASBannersView.onActionWith or IASBannersListView.onAction(...).
  • Check that the handler does not split actions with switch type or ActionType in a way that leaves some types without handling. For basic link opening, it is usually enough to call closeReader(...) and handle target in complete.
  • Check that the SDK is initialized and that create() has been called for widgets that require internal logic to start.
  • Check that target can be parsed as a URL if you open it with UIApplication.shared.open(...).