Use Case: Email Verification

Email Verification Deep Links

Verify users seamlessly with deferred deep links. Preserve verification context even when users tap verification emails before installing your app.

The Problem

The email verification problem

Email verification links break a critical user flow for uninstalled apps. Here's the typical scenario:

What happens without deep links:

  1. 1.User signs up via web or email. They don't have your app installed yet.
  2. 2.Verification email arrives. User taps the link on mobile.
  3. 3.Browser opens the verification URL. App isn't installed, so verification page is incomplete.
  4. 4.User is prompted to install app. Even after install, they lose context—don't know what to verify.
  5. 5.User abandons flow. Sign-up conversion drops.

Without deferred deep links

  • Verification token lost when navigating to app
  • User sees generic app home screen, not verification context
  • Manual re-verification needed (friction)
  • Higher app abandonment in onboarding

With deferred deep links

  • Verification token preserved across app install
  • App opens directly to verification completion screen
  • One-tap confirmation in app after install
  • Seamless onboarding experience
How It Works

How deferred deep links solve email verification

Deferred deep links preserve your verification token and context even when the app isn't installed at the time the user taps the link.

Step 1: User receives email

Your backend sends a verification email with a Redirectly deep link containing the verification token: https://myapp.redirectly.app/verify?token=abc123&email=user@example.com

Step 2: User taps link on mobile

If the app is already installed, the deep link opens directly to your verification screen with token intact.

If the app is not installed, Redirectly captures the full URL (token included) and stores it.

Step 3: App store redirect

User is sent to App Store or Play Store to install your app. The verification token is preserved in Redirectly's servers.

Step 4: SDK retrieves deferred link

When your app launches for the first time, the Redirectly SDK queries the servers: "What deep link was intended for this device?" Redirectly responds with the full verification URL including the token.

Step 5: App navigates to verification screen

Your app receives the deep link with the token and navigates to the verification completion screen, ready for one-tap confirmation. Token is intact. User is delighted.

Implementation

Implementation with Redirectly

Backend: Generate verification links

When a user signs up, create a Redirectly deep link with the verification token as a query parameter:

# Example backend code (Python) verification_token = generate_token() deep_link = ( f"https://myapp.redirectly.app/verify" f"?token={verification_token}" f"&email={user_email}" ) # Send email with deep_link send_verification_email(user_email, deep_link)

Mobile: Setup and listen for deep links

Initialize Redirectly in your Flutter app and listen for deep link events:

import 'package:redirectly/redirectly.dart'; import 'package:go_router/go_router.dart'; void main() async { // Initialize Redirectly with your API key await Redirectly.initialize( apiKey: 'your_api_key_here', ); // Listen for deferred deep links Redirectly.onDeepLink.listen((link) { print('Received deferred link: ${link.fullUrl}'); }); runApp(const MyApp()); }

Navigation: Handle verification deep links

When the app receives a verification deep link, navigate to the verification screen:

// In your main.dart or routing setup Redirectly.onDeepLink.listen((link) { // Parse the deep link if (link.path == 'verify') { final token = link.queryParameters['token']; final email = link.queryParameters['email']; // Navigate to verification screen with token context.go('/verify?token=$token&email=$email'); } }); // Or with go_router route guards final goRouter = GoRouter( routes: [ GoRoute( path: '/verify', builder: (context, state) { final token = state.queryParameters['token']; final email = state.queryParameters['email']; return EmailVerificationScreen( token: token, email: email, ); }, ), ], );
Code Example

Complete Dart/Flutter example

import 'package:flutter/material.dart'; import 'package:redirectly/redirectly.dart'; import 'package:go_router/go_router.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await Redirectly.initialize( apiKey: 'your_api_key_here', ); runApp(const MyApp()); } class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { @override void initState() { super.initState(); // Listen for deep links (both foreground and deferred) Redirectly.onDeepLink.listen((link) { _handleDeepLink(link); }); } void _handleDeepLink(RedirectlyLink link) { if (link.path == 'verify') { final token = link.queryParameters['token']; final email = link.queryParameters['email']; // Navigate to verification screen context.go('/verify?token=$token&email=$email'); } } @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: _buildRouter(context), ); } GoRouter _buildRouter(BuildContext context) { return GoRouter( routes: [ GoRoute( path: '/', builder: (context, state) => const HomeScreen(), ), GoRoute( path: '/verify', builder: (context, state) { final token = state.queryParameters['token']; final email = state.queryParameters['email']; return EmailVerificationScreen( token: token ?? '', email: email ?? '', ); }, ), ], ); } } class EmailVerificationScreen extends StatefulWidget { final String token; final String email; const EmailVerificationScreen({ required this.token, required this.email, Key? key, }) : super(key: key); @override State<EmailVerificationScreen> createState() => _EmailVerificationScreenState(); } class _EmailVerificationScreenState extends State<EmailVerificationScreen> { bool _isVerifying = false; Future<void> _verifyEmail() async { setState(() => _isVerifying = true); try { // Send token to your backend to verify final response = await http.post( Uri.parse('https://api.example.com/verify-email'), body: { 'token': widget.token, 'email': widget.email, }, ); if (response.statusCode == 200) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Email verified! Welcome!')), ); context.go('/home'); } } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error: $e')), ); } } finally { setState(() => _isVerifying = false); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Verify Email')), body: Center( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.mail_outline, size: 64), const SizedBox(height: 16), Text( 'Verify your email', style: Theme.of(context).textTheme.headlineMedium, ), const SizedBox(height: 8), Text( 'Confirm your email: ${widget.email}', style: Theme.of(context).textTheme.bodyMedium, ), const SizedBox(height: 32), ElevatedButton( onPressed: _isVerifying ? null : _verifyEmail, child: _isVerifying ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( strokeWidth: 2, ), ) : const Text('Verify Email'), ), ], ), ), ), ); } }

This example shows the complete flow:

  • Initialize Redirectly in main.dart with your API key
  • Listen for deep links from Redirectly (works even if app was just installed)
  • Parse the token from the deep link query parameters
  • Navigate to verification screen with token intact
  • Verify with your backend using the token
FAQ

Frequently asked questions

Does this work if the app is already installed?

Yes. If your app is installed when the user taps the verification link, the deep link opens immediately with the token intact. If the app isn't installed, Redirectly stores the token and delivers it after install.

What if the user never installs the app?

The verification link still works in the browser. The user can verify via web, then install the app later. Deferred deep links are an enhancement for better UX, not a replacement for web verification.

Can I use this with React Native?

Yes. Redirectly works with Flutter and React Native. The implementation is similar—initialize the SDK, listen for deep links, and parse the token from the URL.

How long are tokens stored?

By default, Redirectly stores deferred deep link data for 30 days. You can configure this in your dashboard. After that period, the link expires.

Is this secure? Can someone intercept the token?

Deep links travel in URLs, which can be logged. For maximum security, use short-lived tokens that expire quickly (5-15 minutes), and require user verification of their email address before activation.

Try Redirectly Free

Get a free API key, subdomain, and 10k monthly links.