Skip to main content

Quickstart

One link, two journeys: tap it with the app installed (direct Universal Link), then install the app from a tap (deferred match). This picks up after install & initialize; the app config, associated-domains entitlement, and SDK initialization are in place.

In the OptoLink portal, create a link with the path /promo/flash-24h. Its canonical URL is https://links.yourdomain.com/acme/<shortCode>; share that URL to a device.

Direct open (app installed)​

With the app already installed, tap the link in Safari. iOS verifies the associated-domains entitlement, opens your app, and hands it the URL through one of the ingestion surfaces you wired. Collect links:

Task {
for await link in OptoLink.instance().links {
print("\(link.path) \(link.matchMethod.rawValue) deferred=\(link.isDeferred)")
}
}

The tap prints:

/promo/flash-24h DIRECT deferred=false

Behind the scenes the SDK resolved the short code via the backend and emitted an OptoLinkData with linkId, path, params, and matchMethod = .direct. handle(url:) is safe to call before initialize finishes; an early URL parks and is processed once initialization completes.

Deferred match (install from a tap)​

On a device without the app:

  1. Tap the link in Safari. The OptoLink redirect page opens and, in the same tap, copies the link URL with a one-time attribution token (?opl_click=…) to the clipboard, then shows the Download on the App Store button.
  2. Install and open the app.
  3. On first launch, initialize detects the URL on the pasteboard. iOS shows the system paste dialog — tap Allow — and the SDK matches the token server-side, emitting the link on links:
/promo/flash-24h CLIPBOARD deferred=true
note

The paste dialog (tap Allow) is the expected output of this test: it confirms the deferred match read the clipboard. Installs that didn't come from a tap never see it; the SDK probes the pasteboard silently first.

The match runs once per install. If the first launch had no network, the opportunity isn't lost: call resolveDeferredLink() later to re-run the match manually; it returns an OptoLinkData? (nil = no match) and throws on network failure.

What you have​

Both journeys end in the same place: an OptoLinkData on the links stream, with matchMethod telling you how it arrived. From here:

  • Every method and shape: API reference
  • What throws, what retries: Errors & retries
  • Bind the device to a user or report events with setIdentity / trackEvent — same reference.