Overview
Implement deep linking and deferred deep linking for Singular tracking links so users move seamlessly from a campaign to a specific screen in your app.
A deep link is a clickable link that opens specific content inside an app. There are two scenarios to support:
- Deep link (direct): the user already has the app installed. They tap a Singular Link and the app opens directly on the right content.
- Deferred deep link (DDL): the user does not have the app yet. They tap the link, install from the store, and on first open the app still routes them to the intended content.
With an SDK integration, Singular handles most of this automatically. In a server-to-server (S2S) integration there is no SDK on the device, so your team is responsible for two extra jobs: passing the deep link your app received up to Singular, and reading the deferred deep link Singular returns and routing the user. Both flow through the SESSION endpoint:
GET https://s2s.singular.net/api/v1/launch
Where this fits:
This guide is part of the S2S documentation suite. For endpoint fundamentals, authentication, and common parameters, see the
S2S Fundamentals hub
. The deep-link parameters used below (
openuri
,
ddl_enabled
, and the response fields) are defined in the
SESSION Endpoint API Reference
.
Resources: Deep Linking FAQ | Singular Links FAQ
The three configurations at a glance
| Step | What it does | Where it happens |
|---|---|---|
| 1. App level | Makes Singular Links open your app (iOS Universal Links / Android App Links) and defines the deep link destinations. | Apple/Google config + Singular dashboard (Apps & Manage Links) |
| 2. SESSION (inbound) |
Singular receives the deep link result. Your app passes the opened link up via the
openuri
parameter.
|
SESSION request → Singular |
| 3. SESSION (outbound) | The app receives the DDL result. Singular returns the deferred deep link in the response, and your server relays it to the app. | SESSION response → your server → app |
Step 1: App-level configuration
Before any deep link can work, Singular Links must be recognized by the OS as iOS Universal Links and Android App Links so that tapping a link opens your app instead of a browser. Traditional URI app schemes are supported as a fallback.
Follow the canonical setup guides for the detailed platform steps, then confirm each item below is complete. The detailed steps live in Singular Links Prerequisites and How to Configure Deep Links . The checklist here gives you the required order and the points teams most often miss.
Configuration checklist:
-
Add a link sub-domain
in
Attribution > Manage Links > Manage Link Domains
(for example
yourbrand.sng.link). This is the host your Singular Links use. -
iOS — Universal Links:
enable the Associated Domains capability for
applinks:yourbrand.sng.link, then copy your App Prefix / Team ID from the Apple Developer Portal into Settings > Apps > [iOS app] > Show Advanced Settings . Optionally register an app-scheme fallback as a URL Type in Xcode. -
Android — App Links:
generate your SHA-256 signing fingerprints (Play Console for production,
keytoolfor debug), add anautoVerifyintent filter for your Singular domain toAndroidManifest.xml, then paste the fingerprint into Settings > Apps > [Android app] > Show Advanced Settings > App Links SHA256 fingerprints . - Define the deep links in Attribution > Manage Links > Create Link (see the field mapping below).
Important: On iOS, if the Team ID step is skipped, every Singular Link redirects to the App Store and deep links will not work. This is the most common reason a correctly built link fails to open the app.
Mapping the Manage Links redirect fields
When you create the link, three redirect fields map directly to the three deep link concepts used later in the API:
| Field in Manage Links | Meaning |
|---|---|
| If the app is not installed , go to | Fallback redirect, usually your App Store / Play Store page. |
| If the app is already installed , go to | The deep link , the in-app destination for existing users (Step 2). |
| After installation , go directly to | The deferred deep link , the destination for new users after install (Step 3). Usually the same value as the deep link. |
Developer handoff:
engineering should provide the deep link scheme(s) per platform and the list of destination URLs (for example
myapp://autumnfashion
).
Step 2: SESSION (inbound) — send the deep link to Singular
When the app opens from a Singular Link, capture the full opening URL and send it to Singular on the SESSION request in the
openuri
parameter (URL-encoded). This is how Singular attributes the session to the link and reports the deep link result. Required when using Singular Links.
Always send SESSION on a deep-link open.
Whenever the app is opened via a deep link, Universal Link, or App Link, send a SESSION request with
openuri
populated, even if the session would normally be considered still active (that is, regardless of the timeout window).
Singular Link parameters carried on the URL
| Parameter | Meaning |
|---|---|
_dl
|
Deep link value (same destination for iOS and Android). |
_ios_dl
/
_android_dl
|
Platform-specific deep link values, when they differ per platform. |
_p
|
Passthrough parameter, a URL-encoded JSON or plain string for custom routing. |
Capture the opening URL in the app
The app needs handler code that receives the opening URL and forwards it to your server for inclusion on the SESSION request.
iOS (Swift):
// Custom scheme / direct opens
func scene(_ scene: UIScene,
openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else { return }
SessionReporter.report(openURL: url.absoluteString)
}
// Universal Links arrive via:
func scene(_ scene: UIScene,
continue userActivity: NSUserActivity) {
if let url = userActivity.webpageURL {
SessionReporter.report(openURL: url.absoluteString)
}
}
Android (Kotlin):
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
intent?.data?.let { uri ->
SessionReporter.report(uri.toString())
}
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
intent?.data?.let { SessionReporter.report(it.toString()) }
}
Send the SESSION request with openuri
From your server, include the captured URL (URL-encoded) as
openuri
:
curl -G https://s2s.singular.net/api/v1/launch \
--data-urlencode "a=<SDK key>" \
--data-urlencode "p=Android" \
--data-urlencode "i=com.yourcompany.app" \
--data-urlencode "aifa=<GAID>" \
--data-urlencode "n=YourAppName" \
--data-urlencode "openuri=myapp://home/page?queryparam1=value1"
Short link resolution
If the user opened a shortened Singular Link, also send
singular_link_resolve_required=true
. Singular returns the expanded long link so you can parse the deep link and passthrough values.
Sample response:
{
"status": "ok",
"resolved_singular_link": "https://myapp.sng.link/A59c0/nha7?_dl=myapp%3A%2F%2Fdeeplink&_ddl=myapp%3A%2F%2Fdeferred-deeplink&_p=passthroughvalue"
}
Dynamic passthrough parameters
If your organization configured dynamic passthrough for a link, the deep link URL includes the
_p
parameter with a URL-encoded JSON string or unstructured string for content routing. See
Dynamic Passthrough Parameters
.
Reference: SESSION Endpoint API Reference (Deep Linking Parameters).
Step 3: SESSION (outbound) — relay the deferred deep link to the app
For a user who installs the app after tapping the link, the deferred deep link is returned by Singular in the SESSION response on the first session after install. Your server must relay that value back to the app so it can route the user.
Request the DDL on the first session
On the first SESSION request after an install, add these two parameters:
| Parameter | Purpose |
|---|---|
install=true
|
Marks this as the first session after a fresh install. |
ddl_enabled=true
|
Tells Singular the app expects a deferred deep link in the response. |
Sample SESSION request (install + DDL enabled):
curl -G https://s2s.singular.net/api/v1/launch \
--data-urlencode "a=<SDK key>" \
--data-urlencode "p=Android" \
--data-urlencode "i=com.yourcompany.app" \
--data-urlencode "aifa=<GAID>" \
--data-urlencode "n=YourAppName" \
--data-urlencode "install=true" \
--data-urlencode "ddl_enabled=true"
Read the response and relay it to the app
If the install came from a tracking link carrying a deferred deep link, Singular returns:
| Response field | What to do with it |
|---|---|
deferred_deeplink
|
The deep link address. Relay to the app and route the user to the matching content. |
deferred_passthrough
|
Any passthrough parameters attached to the link. Use for personalization. |
Sample SESSION response:
{
"deferred_deeplink": "myapp://deferred-deeplink",
"status": "ok",
"deferred_passthrough": "passthroughvalue"
}
Response handling is required.
In a pure S2S setup Singular cannot talk to the device directly. Your backend must parse the SESSION response and forward
deferred_deeplink
(and
deferred_passthrough
) back to the client app, where your routing code sends the user to the right screen. If the response is not relayed, deferred deep linking will silently fail.
Testing & validation
- Deferred deep link: on a device without the app, tap the link and confirm you land on the store. Install and open, and the app should show the intended content.
- Direct deep link: with the app installed, tap the link and confirm the app opens directly on the intended content.
- SESSION ordering: confirm a single SESSION is received before any events, and that the SESSION response is parsed and passed to the client (critical for deferred deep links).
-
openuri populated:
verify deep-link opens send a SESSION with
openuriset, regardless of the timeout window.
Testing guides: Test Your Integration | Test a Tracking Link