← Back to blog

Magic links in mobile apps


If your app uses magic links for sign-in and runs on iOS or Android, you've probably hit this: the email arrives, the user taps the link, and nothing happens. The link uses a custom URL scheme like myapp://auth/verify?token=abc, and the email client doesn't know what to do with it.

Why custom schemes break in email

Email clients like Gmail, Outlook, and Yahoo Mail open links in an embedded browser or webview. These browsers only understand https:// links. A custom scheme like myapp:// gets silently swallowed, blocked, or opened as a broken web page.

Apple Mail on iOS is the exception. It will open custom schemes. But you can't assume your users are all on Apple Mail.

The fix: use an https link

Instead of putting a custom scheme URL in your magic link email, use a normal https URL on your domain. Something like:

Magic link URL
https://yourapp.com/auth/magic-link/verify?token=abc123

This URL works in every email client. The page at that URL is responsible for getting the user into your app.

What that web page does

The page at your https URL has one job: redirect the user into the native app. There are two approaches, and you should use both.

Universal Links and App Links

On iOS, Universal Links let you claim an https URL so that tapping it opens your app directly, skipping the browser entirely. On Android, App Links do the same thing. Both require a config file hosted on your domain that proves you own the app.

  • iOS: host an apple-app-site-association file at https://yourapp.com/.well-known/apple-app-site-association
  • Android: host an assetlinks.json file at https://yourapp.com/.well-known/assetlinks.json

When configured correctly, tapping the magic link in any email client opens your native app with the full URL passed through. No browser, no redirect, no delay.

JavaScript redirect as fallback

Universal Links and App Links don't always fire. The user might not have the app installed. Or the OS might not have indexed your domain yet. Your web page should try to redirect to your custom scheme as a fallback, and show a manual button if that fails.

Redirect fallback
// On your /auth/magic-link/verify page
const token = new URLSearchParams(window.location.search).get("token");

// Try opening the app
window.location.href = `myapp://auth/verify?token=${token}`;

// If still here after 1 second, app isn't installed
setTimeout(() => {
  document.getElementById("fallback").style.display = "block";
}, 1000);

What to send to Own Auth Delivery

When you request a magic link email through Own Auth Delivery, the url field in your request should be the https URL, not the custom scheme. Own Auth Delivery puts that URL directly into the email button and the plain-text copy link.

API request
// Do this
{ "url": "https://yourapp.com/auth/magic-link/verify?token=abc123" }

// Not this
{ "url": "myapp://auth/verify?token=abc123" }

React Native specifics

If your app is built with React Native, you handle incoming deep links with the Linking API. Register your custom URL scheme in Info.plist (iOS) and AndroidManifest.xml (Android), then handle the URL in JavaScript.

App.tsx
import { Linking } from "react-native";

// Handle link that launched the app
const initialUrl = await Linking.getInitialURL();
if (initialUrl) handleMagicLink(initialUrl);

// Handle link while app is already open
Linking.addEventListener("url", ({ url }) => handleMagicLink(url));

function handleMagicLink(url: string) {
  const parsed = new URL(url);
  const token = parsed.searchParams.get("token");
  if (token) {
    // Verify the token with your backend
  }
}

If you use React Navigation, pass a linking config to your NavigationContainer and it handles the URL parsing for you.

Summary

Use https URLs in your magic link emails. Set up Universal Links (iOS) and App Links (Android) so those URLs open your app directly. Add a JavaScript redirect as a fallback for when the native link interception doesn't fire. Your users tap the button in their email, and they're in your app.