Skip to content
tinbo
Blog

Guides6 min read

Deep links without an SDK: a Firebase Dynamic Links alternative

How deep links into your own iOS and Android app work on tinbo, on your own domain and with no SDK, with an honest look at deferred deep linking. Plus a short map for teams still moving off Firebase Dynamic Links.

tinbo team

In this post
  1. What a deep link has to do
  2. How it works on tinbo
  3. Deferred deep links, honestly
  4. Coming from Firebase Dynamic Links?
  5. What it costs

One link that opens your app on the right screen, and sends people without the app to the store. Firebase Dynamic Links used to be the default way to get that, until Google shut it down in August 2025. tinbo does it on your own domain, without an SDK.

This post covers how it works, and what the hard part really is (it's not the part most vendors talk about).

A deep link is a link that opens your app instead of a web page. Both platforms support this natively, as long as the app and the domain vouch for each other:

  • iOS (universal links): the app lists the domain in its Associated Domains, and the domain serves an apple-app-site-association file naming the app.
  • Android (App Links): the app declares the domain in an intent filter, and the domain serves an assetlinks.json file with the app's package name and signing key.

When both sides match, a tap on the link opens the app directly. That part is well understood. The awkward cases are everything around it:

  1. The app isn't installed. The person should get the App Store or Google Play, not a web page that pretends to be your app.
  2. The app gets installed from that link. On first launch it should still open the screen the link pointed to. This is the "deferred" deep link, and it's where the platforms stop helping.
  3. Computers. No app to open, so they get the website.

How it works on tinbo

PersonTaps go.acme.com/order/42
App installed
PhoneOpens your app, not the browser
Your appSends the link to /_/open
tinboAnswers with the destination and counts the click
Order 42 in your app
No app yet
tinboSends it to your App Store or Google Play page
PersonInstalls the app and opens it
Your appFinds the link it came from: a deferred deep link
Order 42 in your app
What a tap on a deep link does

Everything app-specific lives on the domain, once:

  • In Domains → Deep links, you enter the Apple Team ID, bundle ID and App Store link, and the Android package name and signing-key fingerprints. tinbo serves both association files from that, under /.well-known/ on your domain.
  • The same settings become the domain's default device targeting: iPhones without the app go to your App Store page, Android phones to your Google Play page, built from the package name. Links don't carry any of this.

So a link is just a link. Its destination is the page it stands for, say https://acme.com/product/42. The app decides which screen that means, and computers get the page itself. When one link needs to differ, its Device targeting has an Override defaults button: point iPhones at a TestFlight invite and Android phones still go to Google Play.

On the app side there is no SDK. When a link opens the app, the app sends it to the domain and gets the destination back:

curl -X POST https://go.acme.com/_/open \
  -H 'content-type: application/json' \
  -d '{"link": "https://go.acme.com/order/42", "platform": "ios", "deviceType": "mobile"}'
{
  "clickId": "…",
  "link": {
    "id": "…",
    "domain": "go.acme.com",
    "slug": "order",
    "url": "https://acme.com/order/42"
  }
}

That one call also counts the click (marked "opened in app", with the right device), and applies the link's geo targeting and A/B test, so the app gets the same destination a browser would. The deep links guide has the full code for SwiftUI, Kotlin and React Native.

One link can also cover many screens. Turn on prefix link, and go.acme.com/order answers go.acme.com/order/42 too, with /42 added to the destination. One link for every order, and the app routes by path.

This is the hard part, and the platforms treat it very differently.

Android does it properly. Google Play carries an "install referrer" from the store page to the app it installs. tinbo puts the short link into it, and on first launch the app reads it through the Install Referrer API and asks /_/open where to go. Nothing is guessed. The one condition: the store page has to be your own app's, which the domain default always is.

iPhone doesn't. The App Store passes nothing from a web page to the app it installs, and Apple offers no way to do it. Every deep-linking service works around this, and the workarounds have limits. tinbo uses two, in this order:

PersonTaps go.acme.com/order/42, no app yet
tinboShows "Get the app": its button copies the short link
StoreThe App Store installs the app
Your appFirst launch: a URL on the clipboard? iOS asks "Allow Paste?"
Allowed
Your appSends the pasted link to /_/open
Order 42 in your app
Refused, or nothing copied
Your appSends {} to /_/open
tinboLooks for a store visit from the same IP in the last hour
Order 42 if one matched, otherwise the home screen
iPhone: the clipboard first, the IP match when there's nothing to paste
  1. The clipboard gives the exact link, but only if the person allows the paste. If they say no, that's fine: the app starts on its home screen, or tries the IP match.
  2. The IP match is a best guess, and it answers once per store visit. People sharing an IP (an office, a café, a carrier, a VPN) can get each other's link, and it misses anyone who took longer than an hour to install. If you'd rather not guess, don't make that call.

We think it's better to say this plainly than to promise "100% deferred deep linking". On iPhone nobody has that.

Most of what a Firebase link carried as URL parameters now lives on the domain or in the link's own settings:

Firebase Dynamic Linkstinbo
linkThe link's destination
apnAndroid package name, on the domain
ibi, isiBundle ID and App Store link, on the domain
afl, iflOverride defaults: a device rule for that phone
oflThe destination (computers get it anyway), or a desktop rule
st, sd, siCustom social preview
utm_*UTM parameters in the destination
The short link's suffixThe slug

If your old links used your own domain, it's still yours: point it at tinbo with one CNAME record, and links you recreate under their old slugs (in bulk, 100 per request) work again, including ones already printed or sent. page.link addresses belonged to Google, so those are gone for good.

What it costs

Deep links are on the Pro plan, $42 a month billed monthly, on a custom domain. That covers the association files, the store pages, deferred deep links on both platforms, and app opens counted with the rest of your clicks. No per-install or per-click fees.

The deep links guide walks through the setup step by step, from the domain settings to the code in your app.

Keep reading

Your first link is one minute away

Sign up, get you.tnb.li, paste a URL. Free to use, no card, no time limit.