SDK
Appy SDK
Deep links, deferred deep links, install attribution and in-app events for iOS and Android, in an SDK small enough to read in one sitting, on top of an API you can call without it.
The SDK and install attribution are part of the Enterprise plan. The REST API and the MCP server are part of Business. Smart links themselves need no SDK on any plan: they route to the store, the web or an installed app from the moment you create them.
What you get
| Need | How Appy covers it |
|---|---|
| Open the app on the right screen | Universal Links and App Links on your own link domain, <subdomain>.appy.to, plus a custom scheme for in-app browsers that ignore them. |
| Keep the link through an install | A deferred deep link on the first launch, delivered through the same callback as every other link. |
| Know which link brought an install | Install attribution per link: attributed or organic, the link’s UTM source, medium and campaign, and the store that installed the app. |
| Count re-engagement | App opens through a link are added to that link’s click statistics. |
| Measure what users do | In-app events with properties and revenue, credited to the link that brought the install. |
| Count a purchase once | Pass the store’s transaction id as the event’s deduplication id from the app and from your backend. |
| Events only the backend sees | Server-side events by install id or by your own user id. |
| Decide on rewards safely | A per-install lookup from your backend that says whether Appy verified the install. |
| Share links from the app | Links with parameters built on the device, with no API call and no extra link quota. |
| Respect consent | One switch that stops events and the first-launch lookup, and makes the server store nothing. |
How it works
onDeepLink callback. After an install, the first launch asks Appy once.- 1
Someone taps an Appy link
The link lives on your link domain, for example
https://acme.appy.to/spring?item=42. Every link in your account works on that domain without changes. - 2
The app is installed: it opens directly
iOS or Android hands the URL to your app, you pass it to the SDK, and
onDeepLinkreceivesfoundwith the slug, the parameters and the in-app destination. - 3
The app is not installed: the store opens
The link sends the person to the App Store, Google Play or AppGallery. Appy remembers the tap, and on Android the store carries the link through the install referrer.
- 4
The first launch asks Appy once
Appy matches the install to the link that brought it. The app receives
foundwithisDeferredset,notFoundorfailed, and a separate attribution: attributed with the link and its campaign, or organic. - 5
Events follow the install
Events you
trackare credited to the link that brought the install. Your backend can add server-side events and look up any install with a secret key.
Choose a platform
Every platform needs the same two values from registering your app: the publishable key (appy_pk_…), which is safe to ship in the app, and the link domain (<subdomain>.appy.to). Never put a secret key (appy_sk_…) in an app.
Principles
Verified sources first
Appy looks for the link in sources that cannot be wrong before anything else: the link that opened the app, the click id Appy’s redirect page adds to custom-scheme links, and the Google Play or AppGallery install referrer. Only when none of these exists does Appy look for a recent tap that fits the new install. How attribution works describes the order.
One answer per launch
The first launch gets one of three answers: the link (found), no link (notFound) or an error such as a timeout (failed), plus a separate attribution result. Deciding whether an install belongs to a tap is Appy’s job, not the app’s. A match that does not hold up is never delivered and never uses up the tap, so the phone that really tapped can still claim it.
For decisions that involve money, the install lookup tells your backend whether Appy verified the install, and strict attribution makes Appy count only verified installs and treat everything else as organic.
Nothing to track a person with
- No advertising identifiers (IDFA, GAID), no App Tracking Transparency prompt, and nothing sent to ad networks.
- The matching layer never stores an IP address. A tap is filed under a keyed hash of the network address that changes every day and expires after two hours; the tap record itself lasts 24 hours.
- The install id is random, lives in the app’s own storage and disappears with the app.
- With tracking turned off, the server stores nothing for that device and only resolves links the user explicitly opened.
API first, SDK optional
The SDKs are thin clients over two public endpoints, POST /v1/sdk/open and POST /v1/sdk/events. Any runtime can make the same calls: Using Appy without the SDK has working Swift, Kotlin and JavaScript versions of a few dozen lines each.
Size and footprint
| iOS | Android | |
|---|---|---|
| Source | 7 Swift files, about 940 lines | 9 Kotlin files, about 1,150 lines |
| Third-party dependencies | None | Play Install Referrer (Google) |
| Added to a release app | About 161 KB of code and data (stripped, arm64) | About 75 KB of dex after R8, including about 4 KB for Install Referrer |
| Requests per launch | 1 | 1 |
| Unsent events kept | At most 1,000 | At most 1,000 |
| Public API | configure, handle, onDeepLink, onAttribution, attribution, latestDeepLink, track, setUserId, isTrackingEnabled, link, flush | init, handleIntent, handleUri, setDeepLinkListener, setAttributionListener, attribution, latestDeepLink, track, setUserId, isTrackingEnabled, buildLink, flush |
Both SDKs keep their state on a background queue and make every request off the main thread. The platform guides describe how each number was measured.
Integration at a glance
Appy.configure(AppyConfiguration(publishableKey: "appy_pk_...", linkDomains: ["acme.appy.to"]))
Appy.shared.onDeepLink = { result in
if case .found(let link) = result {
router.open(slug: link.slug, parameters: link.parameters)
}
}Appy.init(this, AppyConfig("appy_pk_...", listOf("acme.appy.to")))
Appy.setDeepLinkListener { result ->
if (result is AppyDeepLinkResult.Found) {
router.open(result.link.slug, result.link.parameters)
} else {
router.openHome()
}
}Add the Associated Domains entitlement (iOS) or an autoVerify intent filter (Android) for your link domain, and pass incoming links to handle(url:) or handleIntent(intent) where the platform delivers them.
Scope
Appy attributes installs and events to your Appy links: campaigns, QR codes, emails, social posts and referrals. It is not an ad-network measurement partner. It does not send postbacks to ad networks, does not handle SKAdNetwork or AdAttributionKit conversion values, and does not attribute installs to ads that never went through an Appy link.