Skip to content

Certainty at the one boundary the platforms don't cover.

Initialise once, listen to one stream, and get told how the answer was reached. There is very little surface area here — the complexity belongs on our side of the boundary.

What you are actually integrating against

Universal Links and App Links are already solved for you when the app is installed. Everything difficult lives in the minutes where it isn't — the user is in the App Store, your process does not exist, and there is nowhere on the device the destination is allowed to live. Every deep-linking SDK claims to close that gap. The question worth asking a vendor is what happens when it can't close it cleanly.

No payload survives the store
iOS and Android hand off to the store with no channel back into a process that has not launched yet.
The click and the open are separate events
Minutes apart, different network, sometimes a different OS version. Nothing links them by default.
Silence is indistinguishable from success
A user landing on your home screen looks exactly like a user who wanted your home screen.

Four beats, start to finish

  1. Click

    The redirect records the click on your domain with whatever the device offers, then hands off.

  2. Install

    The store round-trip. Minutes may pass. Nothing of yours is running.

  3. Launch

    OptoLink.initialize() runs before runApp() and the chain resolves the pending journey.

  4. Route

    One event on onLink carries path, params, method and confidence. You navigate.

What you get told, and how sure it is

The chain stops at the first method that answers. The result carries which one it was, so you can treat a deterministic match differently from a network-level guess — gate a discount on exact, and merely navigate on low.

  • A token the phone carriesexact
  • The store's own receipthigh
  • The device, exactly as it washigh
  • The device, mostly as it wasmedium
  • The last thing we knowlow
  • OptoLink.initialize(config) before runApp() — apiKey and orgKey both required.
  • One Stream<OptoLinkData> delivers direct and deferred links to the same handler.
  • Every event carries path, params, matchType, confidence, isDeferred and linkId.
  • getInitialLink() for cold starts; resolveDeferredLink() to run the chain explicitly.
  • clipboardEnabled: false skips the iOS 16+ paste banner without disabling the rest.
  • A logger hook forwards diagnostics to Crashlytics, Sentry, or your own sink.
main.dartflutter sdk
// main.dart — before runApp()
await OptoLink.initialize(
  OptoLinkConfig(
    apiKey: 'ol_live_…',
    orgKey: 'acme',
    clipboardEnabled: true, // false skips the iOS 16+ paste banner
  ),
);

// One stream. Direct opens and deferred installs arrive the same way.
OptoLink.instance.onLink.listen((OptoLinkData link) {
  if (link.confidence == 'exact') {
    grantReferralCredit(link.params['ref']);
  }
  router.go(link.path, extra: link.params);
});

Branching on confidence is the reason it is in the payload. A referral credit should require a deterministic match; navigation does not.

Where it runs

  • iOS

    13+, via the Flutter SDK

  • Android

    API 21+, Kotlin plugin for the store referrer

  • Flutter

    v1.0.0 — the shipping SDK

  • React Native

    Roadmap — not shipped

  • Web

    Redirect and resolution endpoints

Every link finds its exact destination.

Bring us the journey that keeps breaking — the campaign that can't prove its installs, the printed code that lands on a home screen, the checkout link that only works for people who already have the app.

Optolink is built and operated by Optomatica