Annual Defect Report 2026Download
Blog & Reports
How-to guide6 min read · Team Mobot

How to Test Deferred Deep Links on iOS

Open a deep link in the iOS Simulator with xcrun simctl openurl, then test deferred deep links on a real iPhone: delete, tap, install, first open, route.

Short answer: start in the iOS Simulator. With your app installed on a booted simulator, run xcrun simctl openurl booted "myapp://product/42" for a custom scheme, or the HTTPS URL for a Universal Link (the Simulator can send HTTPS links to Safari, so rely on the custom scheme there). Then check that the app opens the right screen. That tests your routing. A deferred deep link also has to survive an App Store install, so finish on a real iPhone:

  1. Delete the app so you start with no app data.
  2. Tap the deferred link from Messages, Mail or a web page.
  3. Install from the App Store, or TestFlight for pre-release builds.
  4. Open the app for the first time.
  5. Check that the right screen shows, along with any attribution or referral parameters, and that a second open doesn't route again.

To test the first-open route without a store install, see the reinstall section.

  1. Run your app from Xcode on a simulated iPhone.
  2. In Terminal, open the link on the booted simulator:

``` # custom URL scheme xcrun simctl openurl booted "myapp://product/42"

# Universal Link (HTTPS) xcrun simctl openurl booted "https://example.com/product/42" ```

simctl is Apple's command-line tool for simulated devices. xcrun simctl help lists its subcommands (Apple: Interacting with devices using the command line). Usage: xcrun simctl openurl <device> <URL> (for example, xcrun simctl openurl booted myapp://promo/123). On the Simulator, an HTTPS Universal Link may open in Safari or show an "Open in app?" prompt even when the association works. Apple doesn't document this, and results vary. 3. Check that the app opens the right screen, with the app not running and again with it in the background. 4. If an HTTPS link opens Safari instead of your app on a real iPhone, the Universal Link setup is the problem, not your deferred logic. On the Simulator, Safari or an "Open in app?" prompt can appear even when the setup is correct. See How to test Universal Links on iOS.

What the Simulator does and doesn't cover. It tests the "open" and "route" halves of a deferred link: URL parsing, routing, and what your app does with a destination returned by your backend or attribution SDK. To test the full install path from the link to the App Store and first open, use a real device with a real App Store or TestFlight install. The simulated "first open" check is in the "without reinstalling" section below.

How does deferred deep linking work on iOS?

There's no system API for this on iOS, so every deferred deep link setup has the same three parts:

  1. Before install: the link goes to your web or attribution server, which records the destination and sends the person to the App Store.
  2. First open: your app or the attribution provider's SDK asks the server for the destination it recorded for this install.
  3. Route: the app opens that screen, and should do it only once.

How step 2 matches the install to the original tap depends on your provider. Read their documentation for the exact behavior, and test every path they support.

About Firebase Dynamic Links: Google discontinued Firebase Dynamic Links. The service shut down on August 25, 2025, and links served by Dynamic Links, on page.link or custom domains, no longer work (Firebase: Dynamic Links deprecation FAQ). If your app still has the Dynamic Links SDK or page.link URLs, those deferred links are broken. Google points to Universal Links and Android App Links for standard deep links, with another provider or your own backend for routing after install.

Run this loop on a real iPhone for every link type you ship, such as campaign, referral and share links:

  1. Reset: delete the app. If your provider remembers devices, also clear the test device in their dashboard.
  2. Tap: open the link from the source people actually use, such as Messages, Mail, a social app or a web page. Confirm it reaches the App Store page for the correct app.
  3. Install: use the same install path your users will. App Store installs and TestFlight installs can behave differently, so test both before release.
  4. First open: launch the app. Answer any system prompts, such as tracking or paste, the way a typical person would, then test the other answers as well.
  5. Assert: the right screen shows, attribution and referral parameters reach your backend, and nothing routes again on the second launch.

Then repeat the loop with the variations in the next section.

You can't avoid deleting and reinstalling for the full test, because the first open after install is the thing you're testing. You can reduce how often you do it:

  • Unit-test the routing code separately by passing it a destination your server returned.
  • Use a debug-only setting that pretends the app was just installed and calls your "get deferred destination" endpoint, so you can test parsing and routing on any build. Remove it from release builds.
  • Keep the full delete → tap → install → open loop for a fixed set of release checks on real devices.
Cause What to test
The paste prompt was declined. Some setups read the clipboard on first open. Since iOS 16, reading the pasteboard in code shows a permission alert unless the person uses a system paste control (Apple: UIPasteControl; UIPasteboard). Decline and allow the prompt; check both paths
Tracking permission. If your provider uses data that needs App Tracking Transparency permission, the result can depend on the person's answer (Apple: App Tracking Transparency). Run the loop with tracking allowed and with tracking denied
Link expired or the matching window passed Tap, wait longer than your provider's window, then install
Routing ran before sign-in or onboarding and then got dropped First open while logged out; the destination should be kept through onboarding
Wrong app or bundle A TestFlight or staging bundle points at the production link domain
Universal Link setup is broken See How to test Universal Links on iOS

Android counterpart: on Google Play, the Play Install Referrer API gives your app the referrer URL and the click and install timestamps after install. Test it with the same delete → tap → install → open loop.

The full test needs a clean device, a real App Store or TestFlight install and a first open, so Mobot runs it on real iPhones and Android phones with physical robots. Mobot AI and Mobot's team build your test cases around each link: where it's tapped, the install, the first open and the screen it should reach. When a link lands on the wrong screen, the defect report includes device screenshots of every step.

FAQ

How do you open a deep link in the iOS Simulator? Install your app on a booted simulator and run xcrun simctl openurl booted "<your link>", with a custom scheme URL. The app should open to the linked screen. An HTTPS Universal Link may open in Safari on the Simulator even when it's set up correctly, so test those on a real iPhone.

What is the difference between a deep link and a deferred deep link? A deep link opens content in an app that's already installed. Routing happens as soon as the link is tapped, and it's built into iOS through Universal Links and custom URL schemes. A deferred deep link still works when the app isn't installed: the person installs the app, and on first open it goes to the linked content. iOS has no system API that carries the link through the App Store install, so deferred links depend on your own backend or an attribution provider. A broken deep link usually opens Safari instead of the app. A broken deferred deep link usually opens the app to its home screen. Test a deep link by tapping it with the app installed, and a deferred deep link by deleting the app, tapping, installing and opening it for the first time.

How does deferred deep linking work on iOS? iOS has no system API for it. A server records the link's destination before the App Store install, and on first open your app or an attribution SDK gets that destination and routes to it.

How do you test a deferred deep link without reinstalling every time? Unit-test the routing and use a debug-only "pretend first install" setting for quick checks. You still need the full delete → tap → install → open loop on real devices before each release.

Why does my deferred deep link open the home screen? Common causes are a declined paste prompt, tracking permission denied, an expired link, routing dropped during onboarding, or a broken Universal Link setup.

Test your deferred deep links on real devices.

Start free trial (1,000 credits)or talk to sales →
How-to

See What Your Emulators Are Missing

Get a real, verified defect report from Mobot’s robots and QA analysts — on your app, on real devices.

or talk to sales