Skip to content
Tolinku
Tolinku
Sign In Start Free
Engineering · · 7 min read

Testing Deep Links Across Platforms and Devices

By Tolinku Staff
|
Tolinku webhooks integrations dashboard screenshot for engineering blog posts

Deep links can break in subtle ways: working on one platform but not another, opening in some apps but not others, handling cold starts but failing on warm starts. A systematic testing approach catches these issues before your users do.

This guide provides a testing matrix, manual testing procedures, and automation patterns for verifying deep links across iOS and Android. For platform-specific troubleshooting, see the Tolinku troubleshooting guide. For testing tools, see Best Deep Link Testing Tools.

The Testing Matrix

Every deep link test has four dimensions:

  1. Platform: iOS, Android
  2. Link type: Universal Link, App Link, custom scheme, web fallback
  3. App state: Cold start (not running), warm start (backgrounded), not installed
  4. Source app: Safari/Chrome, Messages, Email, social apps, QR scanner

A full matrix for a single link path looks like this:

Scenario iOS Android
Cold start from Messages Test Test
Cold start from Mail Test Test
Cold start from Safari/Chrome Test Test
Warm start from Messages Test Test
Warm start from Safari/Chrome Test Test
App not installed (web fallback) Test Test
App not installed (deferred deep link) Test Test
Custom scheme from another app Test Test
QR code scan Test Test

For each cell, verify:

  • The app opens (or the correct fallback occurs)
  • Navigation lands on the correct screen
  • Parameters are passed correctly

Manual Testing Procedures

iOS Testing

Prerequisites:

  • Physical iPhone (not just Simulator; some Universal Link behaviors differ)
  • App installed via TestFlight or development build
  • AASA file deployed and cached by Apple

Test 1: Universal Link from Notes

  1. Open Notes
  2. Paste: https://go.yourapp.com/product/123
  3. Tap the link
  4. Expected: App opens, Product screen with ID 123

Test 2: Universal Link from Messages

  1. Send https://go.yourapp.com/product/123 to yourself via iMessage
  2. Tap the link in the conversation
  3. Expected: App opens, Product screen

Test 3: Cold start

  1. Force-quit the app (swipe up in app switcher)
  2. Tap a link from Notes or Messages
  3. Expected: App launches from scratch and navigates to the correct screen

Test 4: Warm start

  1. Open the app, navigate to any screen
  2. Press Home to background the app
  3. Tap a link from Messages
  4. Expected: App comes to foreground and navigates to the linked screen

Test 5: Safari address bar (negative test)

  1. Type https://go.yourapp.com/product/123 directly in Safari's address bar
  2. Expected: Opens in Safari (Universal Links don't trigger from typed URLs; this is by design)

Test 6: Web fallback

  1. Uninstall the app
  2. Tap a link
  3. Expected: Opens the web fallback URL in Safari

Android Testing

Prerequisites:

  • Physical Android device (emulator works for most tests, but real device recommended)
  • App installed (debug or release build)
  • assetlinks.json deployed

Test 1: App Link from ADB

adb shell am start -a android.intent.action.VIEW \
  -d "https://go.yourapp.com/product/123" \
  com.yourapp

Expected: App opens to Product screen. No disambiguation dialog.

Test 2: From Chrome

  1. Open Chrome
  2. Navigate to a page that contains a link to https://go.yourapp.com/product/123
  3. Tap the link
  4. Expected: App opens directly

Note: Pasting a URL in Chrome's address bar may not trigger App Links. The link must be tapped from a page context.

Test 3: From Messages

  1. Send the link to yourself via SMS
  2. Tap it from the messaging app
  3. Expected: App opens to correct screen

Test 4: Verification status

adb shell pm get-app-links com.yourapp

Expected output includes verified for your domain.

Test 5: Web fallback

  1. Uninstall the app
  2. Tap a link from Messages
  3. Expected: Opens in Chrome to the web fallback URL

Deferred deep linking requires a full install cycle, making it harder to test.

Manual Test

  1. Uninstall the app completely
  2. Clear browser cookies and data
  3. Tap https://go.yourapp.com/product/123
  4. The browser opens (app not installed)
  5. You're redirected to the App Store / Play Store
  6. Install the app
  7. Open the app
  8. Expected: App navigates to Product screen with ID 123 on first launch

Tips for Reliable Tests

  • Use a different network: The fingerprinting system matches device IP, user agent, and other signals. Testing from the same Wi-Fi as your development machine may cause false matches. Use cellular data or a different network.
  • Act quickly: Most platforms have a 30-minute to 24-hour matching window. Install the app shortly after clicking the link.
  • Fresh device state: Clear app data, browser data, and any SDK cache before testing.
  • Test both platforms: Deferred deep linking uses different fingerprinting signals on iOS vs Android. A match on one platform doesn't guarantee a match on the other.

Testing OG Previews

When users share your deep links on social media or messaging apps, the link preview (title, description, image) should render correctly.

Facebook

Use the Sharing Debugger to check how Facebook renders your link. It also lets you clear the cache.

Twitter/X

Use the Card Validator to preview your link's Twitter card.

LinkedIn

Use the Post Inspector to check LinkedIn's rendering.

iMessage

Send the link to yourself via iMessage. The preview should show the OG title, description, and image.

WhatsApp

Send the link in a WhatsApp chat. WhatsApp fetches its own preview; verify it matches your OG tags.

Automated Testing

URL Validation Script

Write a script that verifies all your deep link routes resolve correctly:

#!/bin/bash
# test-deep-links.sh

DOMAIN="https://go.yourapp.com"
ROUTES=(
  "/product/123"
  "/invite/abc"
  "/promo/summer-sale"
  "/category/shoes"
)

for route in "${ROUTES[@]}"; do
  status=$(curl -s -o /dev/null -w "%{http_code}" "$DOMAIN$route")
  if [ "$status" = "200" ] || [ "$status" = "301" ] || [ "$status" = "302" ]; then
    echo "PASS: $route (HTTP $status)"
  else
    echo "FAIL: $route (HTTP $status)"
  fi
done
#!/bin/bash
# validate-config.sh

DOMAIN="go.yourapp.com"

# Check AASA
echo "Checking AASA..."
aasa_status=$(curl -s -o /dev/null -w "%{http_code}" "https://$DOMAIN/.well-known/apple-app-site-association")
echo "AASA: HTTP $aasa_status"

# Check assetlinks
echo "Checking assetlinks..."
asset_status=$(curl -s -o /dev/null -w "%{http_code}" "https://$DOMAIN/.well-known/assetlinks.json")
echo "assetlinks: HTTP $asset_status"

# Validate AASA JSON
echo "Validating AASA JSON..."
curl -s "https://$DOMAIN/.well-known/apple-app-site-association" | python3 -m json.tool > /dev/null 2>&1
if [ $? -eq 0 ]; then
  echo "AASA JSON: Valid"
else
  echo "AASA JSON: INVALID"
fi

# Validate assetlinks JSON
echo "Validating assetlinks JSON..."
curl -s "https://$DOMAIN/.well-known/assetlinks.json" | python3 -m json.tool > /dev/null 2>&1
if [ $? -eq 0 ]; then
  echo "assetlinks JSON: Valid"
else
  echo "assetlinks JSON: INVALID"
fi

ADB Automation (Android)

Automate Android deep link testing with a script:

#!/bin/bash
# test-android-deep-links.sh

PACKAGE="com.yourapp"
ROUTES=(
  "https://go.yourapp.com/product/123"
  "https://go.yourapp.com/invite/abc"
  "https://go.yourapp.com/promo/summer-sale"
)

for url in "${ROUTES[@]}"; do
  echo "Testing: $url"
  adb shell am start -a android.intent.action.VIEW -d "$url" "$PACKAGE"
  sleep 3
  # Take screenshot for visual verification
  adb shell screencap -p /sdcard/screenshot.png
  adb pull /sdcard/screenshot.png "screenshot_$(echo $url | sed 's/[^a-zA-Z0-9]/_/g').png"
  echo "Screenshot saved"
  # Press back to return to launcher
  adb shell input keyevent KEYCODE_HOME
  sleep 1
done

CI/CD Integration

Add deep link configuration validation to your CI pipeline:

# .github/workflows/deep-link-check.yml
name: Deep Link Config Check
on: [push, pull_request]

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Validate AASA file
        run: |
          curl -sf "https://go.yourapp.com/.well-known/apple-app-site-association" | python3 -m json.tool

      - name: Validate assetlinks.json
        run: |
          curl -sf "https://go.yourapp.com/.well-known/assetlinks.json" | python3 -m json.tool

      - name: Check route resolution
        run: bash scripts/test-deep-links.sh

Common Cross-Platform Discrepancies

If links open the app on iOS but not Android (or vice versa):

  • Check that both AASA and assetlinks.json are deployed
  • Verify the signing fingerprint on Android (this is the most common cause)
  • iOS caches the AASA on install; try uninstalling and reinstalling

Different Navigation Behavior

If the same link navigates to different screens on iOS vs Android:

  • Check your routing code for platform-specific branches
  • Verify the URL is being parsed identically on both platforms
  • Some URL parsing libraries handle trailing slashes or query string encoding differently

Timing Differences

Deferred deep links may resolve faster on one platform than the other due to different fingerprinting signals and matching algorithms. Test with realistic timing (not instantly after installing).

Testing Checklist

  • Direct deep link works on iOS (cold start)
  • Direct deep link works on iOS (warm start)
  • Direct deep link works on Android (cold start)
  • Direct deep link works on Android (warm start)
  • Web fallback works on iOS (app not installed)
  • Web fallback works on Android (app not installed)
  • Deferred deep link works on iOS
  • Deferred deep link works on Android
  • Links work from Messages on both platforms
  • Links work from email on both platforms
  • OG previews render correctly on Facebook, Twitter, iMessage
  • AASA and assetlinks.json return HTTP 200 with valid JSON
  • No disambiguation dialog on Android (verified App Links)
  • Parameters passed correctly on both platforms

For Universal Link testing specifics, see How to Test Universal Links. For the cross-platform overview, see Cross-Platform Deep Linking Guide.

Get deep linking tips in your inbox

One email per week. No spam.

Ready to add deep linking to your app?

Set up Universal Links, App Links, deferred deep linking, and analytics in minutes. Free to start.