Every professional who works across a mobile app and a website knows the feeling: a user taps a link in the app, the browser opens, and nothing works. The session is lost. The cart is empty. The user has to log in again. This is the app-site handoff, and when it fails, it frustrates users and hurts conversion. In this guide, we walk through a practical checklist to make that handoff seamless. We will cover what to prepare, how to implement the core workflow, which tools to use, how to adapt for different constraints, and what to check when things go wrong. This is not a theoretical overview; it is a step-by-step plan you can apply today.
1. Who Needs This Checklist and What Goes Wrong Without It
This checklist is for anyone who manages a product that exists on both a mobile app and a website. That includes product managers coordinating a cross-platform launch, developers building deep linking or single sign-on, designers ensuring consistent navigation, and QA engineers testing the transition. If your users ever click a link from your app and land on your website, or vice versa, you need this handoff to work reliably.
Without a structured handoff, several problems emerge. The most common is session fragmentation: a user logs in on the app, then opens a link on the web and sees a login screen. They have to re-enter credentials, which often leads to abandonment. Another issue is state loss: a user adds items to a cart on the app, then moves to the web to complete checkout, and the cart is empty. Deep linking failures are also frequent: a user receives a push notification about an order update, taps it, and lands on the website home page instead of the order details page. Each of these breaks the user's mental model and erodes trust.
We have seen teams spend weeks debugging handoff issues after launch because they assumed shared authentication would 'just work.' The reality is that cookies, token storage, and URL schemes differ between app and web environments. Without explicit planning, the handoff becomes a source of bugs that are hard to reproduce and harder to fix. This checklist helps you catch those issues early, during design and development, rather than after users complain.
Who Should Use This Checklist
This guide is written for teams that have at least one native mobile app (iOS or Android) and a corresponding website. It is also relevant for progressive web apps (PWAs) that need to hand off to a native app, or for websites that launch a native app via custom URL schemes. If you are building a single-page application that also has a mobile wrapper, the same principles apply.
What Happens When You Skip the Handoff
Teams that skip a deliberate handoff often see lower conversion rates on cross-platform journeys. For example, a marketing email sent from the website might include a deep link to the app. If the handoff is broken, the user lands on the app home screen instead of the promoted product, and the click is wasted. Over time, users learn that links from the brand do not work reliably, and they stop clicking. The cost is not just technical debt; it is lost revenue and diminished brand credibility.
2. Prerequisites: What You Need Before the Handoff
Before you implement the handoff, you need to settle a few foundational decisions. These prerequisites will determine how the handoff works and how secure it is. Do not skip this step; it is where most teams make mistakes that cascade into later problems.
Authentication Strategy
First, decide how users will authenticate across app and web. The most common approach is token-based authentication using OAuth 2.0 or OpenID Connect. The app obtains an access token and optionally a refresh token, and the website uses the same token (or a session cookie) to verify identity. However, tokens stored in the app's secure storage cannot be read by the browser, and cookies set by the web cannot be read by the app. You need a mechanism to share the authentication state.
One standard method is to use a shared backend session that both the app and web can query. The app sends its token to an API endpoint that returns a short-lived session identifier, which the app then passes to the web via a deep link parameter. The web uses that session identifier to set its own cookie. Alternatively, you can use an authentication broker like a universal login page that both platforms redirect to. The key is to have a single source of truth for the user's identity, not two separate systems.
Deep Linking Configuration
Second, configure deep linking on both platforms. On iOS, this means setting up Universal Links; on Android, App Links. These allow the website to open the app directly when the user taps a link, without going through a browser first. You also need to handle the reverse: links from the app that open the website. This involves custom URL schemes or universal links that point to your domain. Make sure your server returns the correct apple-app-site-association file (iOS) and assetlinks.json file (Android) so that the operating system trusts your app.
State Persistence Strategy
Third, decide how to persist user state across the handoff. For example, if the user is filling out a form on the website and then switches to the app, the data should not be lost. This often requires a backend that stores draft state tied to the user session. Alternatively, you can use a client-side approach like passing state via deep link query parameters, but that is limited to small amounts of data and raises security concerns. We recommend a backend-based approach for anything beyond trivial data.
Testing Environment
Finally, set up a testing environment that mirrors production. You need a staging server that supports HTTPS (required for universal links), a test app build that registers the correct URL schemes, and a test device that is not logged into production. Without this, you cannot reliably test the handoff end-to-end. Many teams discover handoff bugs only after release because they tested on localhost or with self-signed certificates that the OS does not trust.
3. Core Workflow: Step-by-Step Handoff Process
With the prerequisites in place, you can implement the handoff workflow. This section describes the ideal sequence when a user moves from the app to the website, but the same steps apply in reverse.
Step 1: Initiate the Handoff from the App
The user taps a link in the app that should open a specific page on the website. The app constructs a URL that includes the destination path and, if needed, a handoff token. The handoff token is a short-lived, one-time-use identifier generated by your backend. It encodes the user's session and any relevant state (like the current product ID or cart contents). The app opens this URL in the default browser using a system intent (iOS: openURL; Android: startActivity with ACTION_VIEW).
Step 2: The Backend Validates the Handoff Token
The website receives the URL and extracts the handoff token. It sends the token to a backend endpoint that validates it: checks that it is not expired, has not been used before, and belongs to the correct user. If valid, the backend returns the user's session information (e.g., a session cookie to set) and any state data. The website then sets the session cookie and redirects the user to the intended destination page.
Step 3: The Website Restores State
After the user is authenticated on the web, the website uses the state data from the handoff token to restore the user's context. For example, if the user was viewing a product in the app, the website navigates directly to that product page. If the user had items in the cart, the cart is populated. The user should see a seamless transition with no loss of context.
Step 4: Reverse Handoff (Web to App)
When the user wants to return to the app, the website uses a similar mechanism. It generates a handoff token, encodes the current state, and opens the app via a universal link or custom URL scheme. The app receives the token, validates it with the backend, and restores the user's session and state. This round-trip should feel instantaneous to the user.
Step 5: Verify and Log
Every handoff should be logged on the backend with a unique ID. This log helps you debug failures later. Include timestamps, the token value, the user ID, the source and destination URLs, and the validation result. Monitoring these logs in real time can alert you to a spike in handoff failures, which might indicate a configuration issue or an attack.
4. Tools, Setup, and Environment Realities
Implementing the handoff requires specific tools and configurations. Here we cover the most common ones and the trade-offs you need to consider.
Authentication Libraries and Services
For token-based authentication, consider using established libraries like AppAuth for mobile and a server-side OAuth library. If you use a third-party authentication service (like Auth0, Firebase Authentication, or AWS Cognito), check whether they support handoff tokens out of the box. Many of these services provide session management APIs that can generate short-lived tokens for cross-platform use. However, they also add latency and cost, so evaluate whether your use case justifies the overhead.
Deep Link Testing Tools
Testing deep links is notoriously tricky because the behavior depends on the OS version, browser, and whether the app is installed. Use tools like Branch's deep link testing dashboard or Firebase Dynamic Links to simulate different scenarios. You can also use the command line to test universal links on iOS (with the open command) and App Links on Android (with adb). We recommend creating a test matrix that covers: app installed vs. not installed, user logged in vs. not logged in, and link opened from different sources (email, push notification, in-app banner).
Backend Infrastructure
Your backend needs to support token generation, validation, and state storage. Use a fast key-value store like Redis for handoff tokens because they should expire quickly (e.g., 5 minutes). The token should be a cryptographically random string, not predictable. Ensure that the token validation endpoint is rate-limited to prevent brute force attacks. Also, consider using HTTPS-only cookies for the web session to prevent interception.
Cross-Platform Considerations
iOS and Android handle handoffs differently. On iOS, Universal Links require that your server serves the apple-app-site-association file over HTTPS with a valid certificate. On Android, App Links require the assetlinks.json file and that the app declares the intent filter. Both platforms have changed their behavior over time; for example, iOS 14 introduced new privacy prompts that can affect link handling. Stay updated with the latest OS documentation and test on the latest versions before each release.
When to Avoid a Custom Handoff
If your app and website are both simple and do not need to share state beyond authentication, consider using a standard OAuth flow with a redirect. For example, the user logs in on the web, and the app opens the web login page in a browser (or WebView), then receives the token via a redirect URL. This avoids the need for a custom handoff token. However, this approach is less seamless because the user sees a browser page. Choose the simpler route if your users do not expect a frictionless transition.
5. Variations for Different Constraints
Not every team has the same resources or requirements. Here are common variations of the handoff for different scenarios.
Variation 1: No Backend Control (Static Sites)
If your website is static (e.g., hosted on a CDN with no server-side logic), you cannot generate handoff tokens from the web. In this case, the handoff can only go from the web to the app, and the app must infer the user's session from a cookie or local storage. One workaround is to use a third-party service that acts as a proxy for token generation. Alternatively, you can embed a small JavaScript snippet that calls a serverless function to create a handoff token. This adds a dependency but is feasible.
Variation 2: High Security Requirements
For applications handling sensitive data (finance, healthcare), the handoff must be more secure. Use short-lived tokens (1 minute or less), require re-authentication for high-risk actions, and do not pass state via URL parameters. Instead, use a backend session identifier that the app and web both reference. Also, consider using certificate-based authentication or biometric verification before the handoff completes. The trade-off is user convenience; you need to balance security with friction.
Variation 3: Offline or Low-Connectivity Scenarios
If users often have poor network connectivity, the handoff token validation may fail because the backend is unreachable. In this case, you can cache the handoff token locally and validate it later when connectivity returns. However, this opens a window for replay attacks. An alternative is to use a signed token that the app can verify locally without contacting the backend, but this requires a shared secret and is less secure. For most teams, it is better to require connectivity for the handoff and show a clear error message if the network is unavailable.
Variation 4: Multiple Apps or Sites
If you have multiple apps (e.g., a consumer app and a partner app) or multiple websites (e.g., different country domains), the handoff token needs to include the intended audience. Use a namespace in the token payload so that each app or site only accepts tokens meant for it. This prevents a token meant for the consumer app from being used on the partner app. Also, ensure that your backend validates the token against the requesting origin (via the Referer header or a client ID parameter).
6. Pitfalls, Debugging, and What to Check When It Fails
Even with careful planning, handoffs fail. Here are the most common pitfalls and how to debug them.
Pitfall 1: Token Expiry Mismatch
The handoff token expires before the user completes the handoff. This often happens when the user takes time to read a page before clicking the link. Solution: set the token expiry to at least 5 minutes, and show a friendly error page if the token expires, with a button to re-initiate the handoff.
Pitfall 2: Deep Link Not Registered
The operating system does not open the app because the deep link is not properly configured. For iOS, check that the apple-app-site-association file is accessible at the correct path (/.well-known/apple-app-site-association) and returns JSON with the correct app ID. For Android, verify that the assetlinks.json file is present and that the app's intent filter includes the correct host and scheme. Use online validators to check these files.
Pitfall 3: Session Cookie Not Set
The website receives the handoff token but fails to set the session cookie. This can happen if the token validation endpoint returns the cookie in an incorrect format, or if the cookie domain does not match the website domain. Use browser developer tools to inspect the Set-Cookie header and ensure it has the correct Domain, Path, Secure, and HttpOnly flags. Also, verify that the cookie is not blocked by the browser's privacy settings (e.g., Intelligent Tracking Prevention on Safari).
Pitfall 4: State Data Lost
The handoff succeeds in authenticating the user, but the state (e.g., cart contents) is not restored. This usually means the handoff token did not include the state, or the state was stored with a different user ID. Check that the state is associated with the same user session on the backend. Also, ensure that the state is serialized correctly (e.g., JSON) and that the app and web parse it consistently.
Debugging Steps
When a handoff fails, start by checking the backend logs for the handoff token validation. Look for errors like 'token not found', 'token expired', or 'user mismatch'. Then, reproduce the handoff on a test device with network monitoring (e.g., Charles Proxy or Wireshark) to see the exact HTTP requests and responses. Verify that the deep link URL is correct and that the app or web receives it. Finally, test on different devices and OS versions, because handoff behavior can vary.
What to Check When the Handoff Works Locally but Not in Production
This is a common scenario. The cause is usually a difference in environment: production uses a different domain, HTTPS, or load balancer that strips headers. Check that your production server serves the apple-app-site-association and assetlinks.json files over HTTPS with the correct content type. Also, verify that your production backend is configured to accept handoff tokens from the production app and website domains. If you use a CDN, ensure that it does not cache the handoff token validation responses (set Cache-Control: no-store).
After you fix the handoff, monitor the logs for a few days to confirm that failures decrease. Also, consider adding a client-side analytics event that tracks successful handoffs, so you can measure the impact on user engagement and conversion. A well-tuned handoff should feel invisible to the user; if they notice it, there is still work to do.
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!