Short links that open your app on the right screen, or send people to the App Store, Google Play or a web page, and hand the link to the app after the install.
| Limit | Free | Pro | Scale | Enterprise |
|---|---|---|---|---|
| Short links per project | 100 | 10,000 | 100,000 | 1,000,000 |
| Link click history | 30 days | 90 days | 365 days | 365 days |
A short link like https://<project-ref>.p.stitchdb.com/l/summer (or on your own domain) opens your app on the right screen when it is installed, using iOS Universal Links and Android App Links. Without the app, people go to the App Store or Google Play, and on a computer to a web page. After the install, the app can ask which link brought the person in (a deferred deep link), so an invite or a promo still lands on the right screen. Every link counts clicks, opens in the app and installs, per day, platform, country and referrer.
The links are served by your project’s own server and stored in your project’s database (schema _stitch_links).
#Set it up
- Open Studio › Links and click Turn on links.
- Under Apps and domain, add your iOS app (Team ID, bundle ID and App Store ID) and your Android app (package name and the SHA-256 fingerprint of the app signing certificate from Play Console › Test and release › App signing; add the upload key’s fingerprint too for debug builds). Choose the domain the links use and a default web page.
- Tell the apps about the domain (below), install the app on a phone and open a link from Notes, Messages or an e-mail.
iOS reads https://<domain>/.well-known/apple-app-site-association and Android https://<domain>/.well-known/assetlinks.json when the app is installed; StitchDB serves both from your settings. Only paths under /l/ open the app, so your API on the same domain is not affected.
#iOS
In Xcode, open the app target’s Signing & Capabilities, add Associated Domains and the entry below. Apple caches the association file, so a change can take a while to reach phones.
applinks:<project-ref>.p.stitchdb.com#Android
Add an intent filter with autoVerify to the activity that handles links:
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="<project-ref>.p.stitchdb.com" android:pathPrefix="/l/" />
</intent-filter>#Open the right screen
When the app opens with a link, pass the URL to links.resolve: it returns the link’s path (the screen, as your router knows it) and the data you stored with it, and counts the open. A URL that is not a short link gives null without a request; an expired or turned-off link is an error with status 410.
// React Native: Linking.getInitialURL() and Linking.addEventListener('url', …)
const { data: link, error } = await stitchdb.links.resolve(url, { platform: 'ios' })
if (link) navigation.navigate(link.path, link.data)// the Uri from your deep link package (for example app_links)
final link = await stitchdb.links.resolve(uri.toString());
if (link != null) router.go(link.path ?? '/', extra: link.data);// in the activity's onCreate / onNewIntent
val link = stitchdb.links.resolve(intent)
if (link != null) navController.navigate(link.path ?: "/")// SwiftUI
.onOpenURL { url in
Task {
if let link = try await stitchdb.links.resolve(url.absoluteString) { router.open(link.path, data: link.data) }
}
}#After an install
On the first launch, call links.deferred. The mobile SDKs remember that they asked, so later launches return null without a request. On Android, pass the Play install referrer (read it with the Play Install Referrer library: ReferrerDetails.installReferrer); store links carry the link’s code in it, which is an exact match. Otherwise the click is matched to the install by network address and platform within 2 hours of the click: that is a best guess, it can miss (a phone that switched from Wi-Fi to mobile data) and, on a shared network, rarely pick another person’s click — use it for convenience (a promo code, the invite screen), never for anything that needs proof. Each click is handed out once, and the network addresses are stored only as a keyed hash for a day.
const { data: first } = await stitchdb.links.deferred({ platform: 'android', referrer: installReferrer })
if (first) navigation.navigate(first.path, first.data)final first = await stitchdb.links.deferred();
if (first != null) router.go(first.path ?? '/', extra: first.data);val first = stitchdb.links.deferred(referrer = referrerDetails.installReferrer)
if (first != null) navController.navigate(first.path ?: "/")if let first = try await stitchdb.links.deferred() { router.open(first.path, data: first.data) }#Make links
Make links in Studio, from your server with the service key, or — if you allow it under Apps and domain — from the app by signed-in users (invites, sharing; at most 100 an hour per user, and they cannot choose the code). A link has a path and up to 4 KB of data for the app, an optional web page, iPhone and Android pages for people without the app (instead of the stores), a title, description and image for previews in chats and social posts, and an optional expiry.
const { data: link } = await stitchdb.links.create({
path: '/invite/7',
data: { from: 'ana' },
title: 'Ana invited you',
image_url: 'https://example.com/invite.png',
expires_at: new Date(Date.now() + 7 * 86400e3),
})
share(link.url) // https://<project-ref>.p.stitchdb.com/l/aB3kP9xWith the service key you can also choose the code, list and search links, read one link’s numbers, change and delete links:
curl -X POST https://<project-ref>.p.stitchdb.com/links/v1/links \
-H "apikey: $STITCHDB_SERVICE_KEY" -H "Authorization: Bearer $STITCHDB_SERVICE_KEY" \
-H "Content-Type: application/json" -d '{"code": "summer", "path": "/sale", "web_url": "https://example.com/sale"}'
curl "https://<project-ref>.p.stitchdb.com/links/v1/links/summer?days=30" \
-H "apikey: $STITCHDB_SERVICE_KEY" -H "Authorization: Bearer $STITCHDB_SERVICE_KEY"#Where people go
- App installed: the phone opens the app directly; the click never reaches the server, so it counts when the app calls
resolve(opened in the app). - iPhone without the app: the link’s iPhone page if set, else the App Store, else the web page.
- Android without the app: the link’s Android page if set, else Google Play (with the link in the install referrer), else the web page.
- Computer: the link’s web page, else the project’s default web page, else a small page that says to open the link on a phone.
- Link previews (chat apps, social networks): a page with the link’s title, description and image; previews are not counted as clicks.
- Turned off, expired or unknown: the project’s default web page, else a “link not found” page.
Click history is kept for your plan’s number of days; the totals per link are kept as long as the link. Turning links off makes every link answer 404 and stops the association files, so apps stop opening links until you turn it on again; links and numbers are kept.