Skip to main content

Overview

Deep linking allows you to open a specific page within your app from an external source such as a website, email, or SMS. If the app is not installed, users are redirected to the appropriate app store. If on an unsupported platform, users are redirected to a fallback website. This guide covers setup and usage of deep linking across:
  • Android (App Links)
  • iOS (Universal Links)
  • Push notifications
  • Emails
  • In-app messages
To function correctly, deep links must:

Android setup

Use Android Studio’s App Links Assistant to simplify setup.

Steps

  1. Open Android Studio → ToolsApp Links Assistant
  2. Follow steps to set up links to your site
  3. Android Studio auto-generates the required code and assetlinks.json file

Manifest example

<activity android:name=".SecondActivity" android:exported="true">
  <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" />
    <data android:host="yoursite.com" />
  </intent-filter>
</activity>

Activity handler example

Intent appLinkIntent = getIntent();
String appLinkAction = appLinkIntent.getAction();
Uri appLinkData = appLinkIntent.getData();
The generated assetlinks.json file must be hosted at:
https://yoursite.com/.well-known/assetlinks.json

iOS setup

Apple supports Universal Links for opening your app from external sources like email and SMS. For simpler use cases, URL Schemes can be used when the app is already installed. This guide covers Universal Links setup.
  1. In Xcode → select target → Signing & Capabilities → add Associated Domains
  2. Add your domain as applinks:yourdomain.com

AppDelegate logic

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
  if userActivity.activityType == NSUserActivityTypeBrowsingWeb,
     let webpageURL = userActivity.webpageURL {
    print("Received Universal Link: \(webpageURL)")
  }
  return true
}
OneSignal’s iOS SDK uses openURL for Launch URL. This redirects to the browser first, then back into the app.To suppress this:
  • Use data instead of url in the API and handle the deep link in your Notification Click Listener
  • Or add OneSignal_suppress_launch_urls to Info.plist as a Boolean with value YES
More Info

Host the apple-app-site-association file

The file must be hosted at:
https://your_url/.well-known/apple-app-site-association
Replace the placeholders in the example below:
PlaceholderReplace with
TEAMIDYour Apple Team ID (found in Apple Developer account)
com.example.exampleYour iOS app bundle identifier
/page-nameThe path(s) in your app that should handle deep links
{
  "applinks": {
    "apps": [],
    "details": [{
      "appID": "TEAMID.com.example.example",
      "paths": ["/page-name", "/page-name/*"]
    }]
  }
}

Hosting the verification files

Both Android and iOS require a verification file hosted at a .well-known path on your domain. Here’s a Node.js example serving both:
// Node server example
const http = require('http');
const url = require('url');

http.createServer((req, res) => {
  const path = url.parse(req.url).pathname;
  if (path === '/.well-known/assetlinks.json') {
    res.writeHead(200, {'Content-Type': 'application/json'});
    res.end(JSON.stringify([{
      relation: ["delegate_permission/common.handle_all_urls"],
      target: {
        namespace: "android_app",
        package_name: "com.example.deeplink",
        sha256_cert_fingerprints: ["8A:4C:3D:..."]
      }
    }]));
  } else if (path === '/.well-known/apple-app-site-association') {
    res.writeHead(200, {'Content-Type': 'application/json'});
    res.end(JSON.stringify({
      applinks: {
        apps: [],
        details: [{ appID: "TEAMID.com.example.deeplink", paths: ["*"] }]
      }
    }));
  } else {
    res.writeHead(404);
    res.end('Not Found');
  }
}).listen(3000);

Include the deep link as:
  • url property (Launch URL)
  • Or data property (recommended for iOS to suppress browser redirect)
Behavior:
  • Android: Opens to the linked activity directly
  • iOS: Opens browser, then app (unless suppressed — see iOS setup Warning above)

By default, email links use OneSignal’s tracking, which alters the URL and breaks deep linking.

To support deep linking

  • Disable link tracking in the dashboard (Track link clicks)
  • Or set disable_email_click_tracking: true in the API
Tradeoff: Disabling tracking means you lose click metrics in Email Reports.

Behavior matrix

ScenarioResult
iOS + Safari + Universal Link + Tracking EnabledOpens Safari, asks to open app
iOS + Safari + Universal Link + Tracking DisabledOpens app directly
iOS + Non-Safari + Universal LinkOpens App Store
Android + Universal Link or App LinkMay open App Store if not installed
Android + App Link + Tracking DisabledOpens app directly
Android + App Link + Tracking EnabledOpens browser first, then app

Drag-and-drop editor

HTML editor

Use an event listener

OneSignal.getInAppMessages().addClickListener(event -> {
  if ("https://your_url_here".equals(event.getResult().getActionId())) {
    // Redirect user
  }
});