Smler Logo
SMLER

Deferred Deep Links on Android: Full Smler Integration Guide (2026)

Learn how to integrate deferred deep links in your Android app using Smler and the Install Referrer API, with code, testing steps, and common fixes.


Deferred Deep Links on Android: Full Smler Integration Guide (2026)

Deferred deep links let you send a user straight to a specific screen inside your app — a product page, an offer, a referral reward — even if the app isn't installed yet when they click the link. Once the app installs and opens for the first time, the user lands on the exact screen the link pointed to, instead of a generic home screen.

What changed: this guide has been refreshed for 2026 with updated Install Referrer library guidance, clearer handling of edge cases (null referrers, cold vs warm start), a dedicated testing section, and a troubleshooting checklist. The core integration steps and Smler API call remain the same.

In this guide, we'll walk you through:

  • Setting up the Install Referrer API

  • Handling the deep link after app install

  • Sending install data back to Smler

  • Routing users to the right screen using the link

  • Testing the flow and fixing the issues that most often break it

When a user clicks a Smler deferred link and then installs your app from the Play Store, four things happen in sequence:

  1. The Install Referrer string attached to the Play Store install contains the link metadata (query parameters like page or a full path).

  2. Your app reads this referrer string on first launch.

  3. The app extracts the deep link from the referrer URL and tracks the deep link open by hitting the Smler endpoint.

  4. The app redirects the user to the appropriate screen using the destination URL returned by the /api/v1/short endpoint.

If you haven't generated a deferred link yet, see the step-by-step guide to generating deferred deep links in Smler before wiring up the Android side below.

Step 1: Add the Install Referrer Dependency

Google's Install Referrer library is what gives you access to the referrer string. Add it to your module-level build.gradle:

dependencies { 
  implementation 'com.android.installreferrer:installreferrer:2.2' 
}

This is the same library Google Play Services uses to expose install attribution data, and it's still the current, supported way to read the referrer — there's no newer replacement API as of this update.

Step 2: Build the Referrer Client Manager

This class does the actual work: it connects to the Install Referrer service, reads the referrer string once, stores a flag so it never runs twice, and forwards the data to Smler.

package `in`.smler.deferredlink import android.content.Context 
import android.util.Log 
import com.android.installreferrer.api.InstallReferrerClient 
import com.android.installreferrer.api.InstallReferrerStateListener 
import com.android.installreferrer.api.ReferrerDetails 
import androidx.core.content.edit 
import kotlinx.coroutines.CoroutineScope 
import kotlinx.coroutines.Dispatchers 
import kotlinx.coroutines.launch 
import java.net.URLEncoder 
import java.net.HttpURLConnection 
import java.net.URL 

class InstallReferrerClientManager(private val context: Context) { 
  fun fetchReferrer() { 
    val prefs = context.getSharedPreferences("smler_preference", Context.MODE_PRIVATE) 
    val isFirstInstall = prefs.getBoolean("is_first_install", true) 
    if (!isFirstInstall) { 
      Log.d("ReferrerClient", "Not first install. Skipping referrer fetch.") 
      return 
    } 
    val referrerClient = InstallReferrerClient.newBuilder(context).build() 
    Log.d("ReferrerClient", "Starting connection...") 
    referrerClient.startConnection(object : InstallReferrerStateListener { 
      override fun onInstallReferrerSetupFinished(responseCode: Int) { 
        when (responseCode) { I
          nstallReferrerClient.InstallReferrerResponse.OK -> { 
            val response: ReferrerDetails = referrerClient.installReferrer 
            val referrerUrl = response.installReferrer 
            Log.d("ReferrerClient", "Referrer URL: $referrerUrl") 
            // Save flag 
            prefs.edit { putBoolean("is_first_install", false) } 
            // Notify Smler 
            notifySmlerInstall(referrerUrl) 
          } 
          InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED -> Log.w("ReferrerClient", "Install Referrer not supported") 
          InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE -> Log.w("ReferrerClient", "Install Referrer service unavailable") 
        } 
        referrerClient.endConnection() 
      } 
      override fun onInstallReferrerServiceDisconnected() { Log.d("ReferrerClient", "Referrer service disconnected") } 
    }) 
  } 
  private fun notifySmlerInstall(referrer: String) { 
    CoroutineScope(Dispatchers.IO).launch { 
      try { 
        val encoded = URLEncoder.encode(referrer, "UTF-8") 
        val url = URL("https://smler.in/api/v1/deferred-link/install?details=$encoded") 
        val conn = url.openConnection() as HttpURLConnection 
        conn.requestMethod = "GET" 
        val responseCode = conn.responseCode 
        Log.d("ReferrerClient", "Install ping response: $responseCode") 
        conn.disconnect() 
      } catch (e: Exception) { 
        Log.e("ReferrerClient", "Error notifying Smler", e) 
      } 
    } 
  } 

Call fetchReferrer() once, from either your Application class or the first activity's onCreate(). The is_first_install flag in SharedPreferences is what stops it from firing on every app open — without it, you'd re-notify Smler on every cold start, which pollutes your attribution data.

Once the app opens, the referrer tells you that a deferred link was clicked. The intent data tells you where to send the user. Add this to the activity that receives the launch intent:

private fun handleIntentDeepLink() { 
  val page = intent?.data?.getQueryParameter("page") 
  val fullUrl = intent?.data.toString() 
  Log.i("MainActivity", "Intent URL: $fullUrl") 
  Log.i("MainActivity", "Page Param: $page") 
  // Navigate to specific screen based on query param 
  when (page) { 
    "123" -> openOfferPage() 
    "home" -> openHome() 
    else -> handleUriFallback(fullUrl) 
  } 
} 

override fun onNewIntent(intent: Intent?) { 
  super.onNewIntent(intent) 
  setIntent(intent) 
  handleIntentDeepLink() 
}

You can configure page=xyz in the Smler dashboard while creating the deferred link, or use the entire URI path to route users (e.g. /product/9876 → open the product page).

A few edge cases worth handling explicitly:

  • Cold start vs warm start: onNewIntent() only fires if the activity is already running. On a true cold start (first launch after install), read the deep link data from getIntent() inside onCreate() as well.

  • Null or empty referrer: if the user installed the app organically, the referrer will be empty or generic. Always fall back to your normal home screen rather than crashing on a null page parameter.

  • Delayed referrer availability: on some devices the referrer isn't available for a few seconds after first launch. Don't block your splash screen indefinitely waiting for it — set a short timeout and fall back gracefully.

Step 4: Enable Deep Linking in AndroidManifest.xml

Your manifest needs to declare which links your app is allowed to open. This is required regardless of whether the link is deferred or a standard deep link:

<activity android:name=".MainActivity">   
<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="smler.in" android:pathPrefix="/your/custom/path" />
  </intent-filter> <!--
  Custom scheme like smler:// awesomeapp:// --> <intent-filter>
    <data android:scheme="smler" />
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
  </intent-filter>
</activity>

Match the exact path structure you're using in Smler, and set android:autoVerify="true" if you want the link to open your app directly instead of showing a disambiguation dialog.

A regular deep link only works if the app is already installed — the intent-filter in Step 4 handles those cases on its own, no referrer needed. A deferred deep link is the version that survives an app install in between: the click happens before the app exists on the device, and the destination is recovered afterwards using the Install Referrer data described above. If you're deciding which one your feature actually needs, the deferred vs regular deep linking comparison guide breaks down when each applies.

Test the full install-to-navigation flow before shipping, not just the link click. Three ways to do it:

  1. Play Install Referrer Test Tool: Google's official Play Install Referrer Test Tool lets you simulate a referrer string without going through an actual Play Store install — the fastest way to check your parsing logic.

  2. Fresh install on a real device: uninstall the app completely, click your Smler deferred link, install from the Play Store, and confirm you land on the correct screen on first open.

  3. ADB intent simulation: once the app is installed, you can fire a test intent directly with adb shell am start -a android.intent.action.VIEW -d "https://smler.in/your/custom/path?page=123" to test navigation logic in isolation from the referrer flow.

For a broader testing checklist that covers regular deep links as well, see how to test deep links on Android.

  • Referrer comes back empty: usually means the app was tested via a direct APK install (sideloaded) rather than through the Play Store, which is the only path that populates the referrer.

  • Navigation fires more than once: check that the is_first_install flag is being written correctly and that fetchReferrer() is only called from one place in your app.

  • Wrong screen opens: double-check the query parameter names configured in the Smler dashboard match exactly what your when block expects — a mismatched key silently falls through to your fallback case.

  • Works on some devices, not others: a handful of OEM Android builds delay or restrict Install Referrer callbacks; always test on at least one non-Pixel device before launch.

Wrap-Up

By integrating Smler's deferred deep linking with the Google Install Referrer API, you ensure users land on the exact screen they expect — even after installing your app for the first time. It's simple, lightweight, and requires no third-party SDK. Configure it once, and track installs and navigation automatically from then on.

Building the iOS side of the same feature? Check the companion guide to integrating deferred deep links in your iOS app with Smler. And if you want the full conceptual background before you touch code, the Ultimate Guide to Deferred Deep Linking is a good place to start.

Start creating your deferred links here:

https://app.smler.in/app/deferred-link

Do I need a third-party SDK to implement deferred deep links on Android?
No. Google's Install Referrer library plus Smler's API call is enough to build the full flow described in this guide. Third-party attribution SDKs add extra cost and data collection that most apps don't need for this use case.

Why is my Install Referrer returning null or empty?
This almost always happens when the app was installed by sideloading an APK instead of through the Play Store, since the referrer is only populated on Play Store installs. It can also happen briefly right after install if you read it before the connection finishes.

Can deferred deep links work with a custom URL scheme instead of a domain?
Yes. The manifest example in Step 4 shows both an HTTPS domain-based intent-filter and a custom scheme (like smler://). Custom schemes are simpler to set up but don't support Android App Links verification, so the OS may prompt the user to choose an app.

How long after install does the referrer data stay valid?
Referrer data remains available for up to 90 days after installation. That's why this guide stores an is_first_install flag — to manage the user experience effectively during the initial onboarding process.

Published with LeafPad