Web to App in Two Seconds
A user logs in on the website, taps "Open in App," downloads from the App Store, and opens the app already authenticated. Here's how it works, who does it well, and what it would take for Ramp Network.
The core problem is the App Store gap. A user is authenticated on the web, but the moment they click through to the App Store, that session is lost. They download the app, open it, and hit a cold login screen. Every on-ramp and exchange loses users at this boundary.
The solution is called deferred deep linking: a link that carries context (in this case, an encrypted authentication token) through the install process. The user clicks a smart link on the web. If the app is installed, it opens directly. If not, the link routes them to the App Store, and when they open the app for the first time after downloading, the SDK recovers the original payload. The app uses that payload to authenticate them instantly.
The "2 seconds" is the biometric prompt (Face ID or Touch ID) that MiCA requires as a second authentication factor. A magic token alone counts as one factor (possession of the email). European crypto service providers need two. But a Face ID tap is barely perceptible friction.
How Coinbase, Binance, and Revolut do this
Coinbase: the dual-stack approach
Coinbase runs two SDKs in parallel. Branch.io handles the user-facing deep linking: creating smart links, routing through the App Store, and resolving deferred payloads on first open. AppsFlyer handles marketing attribution and fraud detection (Protect360). This separation is deliberate. Branch is better at matching a web click to a post-install app open (their "Identity Graph" uses device fingerprinting, IP matching, and clipboard-based deterministic matching). AppsFlyer is better at detecting bot farms and attribution fraud on paid campaigns.
Coinbase's most interesting use of this is Linkdrop Claim Links. They generate URLs that let you send USDC to someone who doesn't have the app. The recipient clicks the link, gets routed to the App Store, downloads Coinbase Wallet, opens it, and the claim screen appears immediately with their USDC waiting. The link data survived the install gap via Branch's deferred deep linking. This is the pattern most directly relevant to Ramp Network: "Click this link to buy $50 of ETH" that persists through download.
Binance: fraud-first with magic.link
Binance uses AppsFlyer OneLink as their primary deep linking SDK, paired with magic.link for passwordless authentication in their Web3 wallet. When a user clicks an email login link, magic.link generates a Decentralized ID (DID) token that gets passed through the redirect URI to the app. For referral and marketing links, AppsFlyer OneLink handles deferred deep linking with Protect360 fraud detection running on every install. Binance Pay uses a prepayId as a session token in deep links, so a payment request can survive the app install process.
The Binance approach optimizes for a different problem than Coinbase. Binance processes vastly more paid acquisition traffic and faces more sophisticated install fraud. Their choice of AppsFlyer over Branch reflects this: they need fraud detection at the attribution layer, not just the auth layer.
Revolut: order tokens for payment continuity
Revolut's Merchant SDK generates an order_token server-side for each payment session. This token is passed to the mobile SDK, which uses a deep link (revolut://) to open the app in a specific checkout state. For new users, AppsFlyer's onConversionDataSuccess callback delivers the referral context on first open, personalizing the onboarding experience based on which "Invite a Friend" link brought them in.
Revolut's pattern is the simplest of the three. The order_token is short-lived, single-use, and exchanged server-side for a real session. There's no encryption in the link itself because the token is opaque and meaningless without the server-side state.
MoonPay: the deliberate exception
MoonPay is the only major on-ramp that doesn't use deferred deep linking. Their Auth SDK sends "Login Links" via email that use Universal Links to open the app if installed. If the app isn't installed, the link falls back to mobile web. There's no attempt to carry context through the App Store.
This is a deliberate product decision, not a technical limitation. MoonPay's distribution is purely B2B: their SDK lives inside partner apps (MetaMask, Trust Wallet, etc.), and the end user never installs a "MoonPay" app. When you don't own the direct user relationship, deferred deep linking into your own app isn't a growth lever. MoonPay's Auth SDK loading time (8x faster, now 1 second) matters more than install-gap continuity.
Transak: backend sessions without deferred links
Transak takes yet another approach. They generate a one-time widgetUrl server-side with a 5-minute TTL session token baked in. Their SDK is WebView-based, so the partner app loads Transak's checkout inside a WebView. When the session completes, a redirectURL using a custom URI scheme (myapp://) returns the user to the host app. Partners can pass pre-verified user details during session creation to skip Transak's OTP step entirely ("Auth Reliance").
This model doesn't need deferred deep linking because there's no app install in the flow. Everything happens inside a WebView within the partner's app. It's the simplest architecture but also the most constrained: no native app experience, no push notification retention, no biometric payment flows.
What all implementations have in common
Despite different SDK choices, every successful implementation follows the same security architecture:
Never put auth tokens in the link. The deep link carries only a short-lived, opaque identifier - a random string that means nothing without the server-side state. Coinbase's claim IDs, Binance's prepayIds, Revolut's order tokens, and Transak's session tokens all follow this pattern. The link is a lookup key, not a credential.
Single-use, server-side exchange. When the app opens and extracts the identifier from the deferred payload, it makes a server call to exchange it for a real session. The server atomically reads and deletes the identifier (Redis GETDEL or equivalent). If the identifier has already been used, the exchange fails. This prevents replay attacks even if someone intercepts the link.
Short TTL. Every implementation uses a 3-5 minute time-to-live on the server-side token. If the user takes longer than that to install and open the app, the token expires and they need to re-authenticate. This is the tradeoff: a longer TTL improves conversion (slow installs on bad connections) but widens the attack window.
Domain-verified links only. Universal Links (iOS) and App Links (Android) use domain verification to prove the app and the website are owned by the same entity. This prevents the most dangerous attack vector: any app registering a custom URI scheme like rampnetwork:// and intercepting tokens intended for the real app. Custom schemes are fundamentally insecure for auth. Every major player uses verified links.
The SDK market after Firebase. Firebase Dynamic Links shut down in August 2025. The market consolidated around Branch.io (best deferred deep link matching accuracy, preferred for UX) and AppsFlyer (best fraud detection, preferred for paid acquisition). Coinbase and Revolut run both. Binance runs AppsFlyer only. Dub.co is an emerging open-source alternative but unproven at fintech scale.
How this would work end to end
The user is on ramp.network or a partner widget. They authenticate via Email OTP (the existing flow, unchanged). After authentication, the server does three things: generates a 32-byte random magic token, creates a PKCE challenge pair, and stores both in Redis with a 5-minute TTL. The server then calls the Branch.io API to create a deferred deep link containing only the encrypted opaque handle. No email, no user ID, no auth token. Branch sees ciphertext.
The user taps the link. If the app is installed, it opens directly via Universal Links. If not, Branch routes them to the App Store. They download the app and open it for the first time. The Branch SDK initializes, detects a deferred payload, and delivers the encrypted handle to the app.
The app decrypts the handle and immediately triggers a biometric prompt: Face ID on modern iPhones, Touch ID on older ones, fingerprint or PIN on Android. This is the MiCA SCA gate. The magic token provides the first factor (possession: the user had access to the email where the link was sent). The biometric provides the second factor (inherence: the user physically proved their identity via the device's Secure Enclave). Together, they satisfy Strong Customer Authentication.
The app sends the handle plus the PKCE code verifier to POST /auth/exchange. The server runs GETDEL on Redis (atomic read-and-delete, preventing replay), validates the PKCE proof (SHA256(code_verifier) == stored code_challenge), checks the TTL hasn't expired, and if everything passes, issues a Turnkey-scoped JWT with a refresh token. The session gets bound to the device's Secure Enclave key. Subsequent app opens use biometric + device key without needing another magic link.
Every purchase still needs its own biometric. MiCA Art. 68/75 requires "dynamic linking": the authentication code must be cryptographically bound to the specific transaction amount and payee. The magic token handles session establishment only. Every buy or sell triggers a fresh biometric confirmation with the transaction details embedded in the challenge. There's no way around this for EU-licensed CASPs.
What it would take to build this
Ramp Network has the hard parts done. The Apple App Site Association file is already configured at app.ramp.network with paths for /wallet/link/*. Android's assetlinks.json is live. The OTP backend already generates, validates, and expires short-lived tokens. Extending this to accept a URL-embedded token instead of a manually-entered code is a minor backend change.
The missing piece is the deferred deep linking SDK. Without Branch.io or equivalent, there's no way to carry a payload through the App Store install gap. Building probabilistic matching in-house (IP + device fingerprint + timestamp correlation) is an engineering trap: Apple's privacy restrictions make it unreliable, and it's a maintenance burden that a $50k/year SaaS solves better. Branch's free tier covers the initial integration.
The second missing piece is web surface area. The ramp.network homepage currently has zero mobile app mentions, no download CTAs, no Smart App Banners. Even with perfect deferred deep linking, there's no organic entry point to trigger it. This is a product/marketing decision more than an engineering one.
The total build is 6-10 weeks: Branch SDK integration across iOS and Android (2-3 weeks), the magic token exchange endpoint with Redis and PKCE (1-2 weeks), biometric step-up integration (1 week), AASA path extension and testing (1-2 days), web CTAs and smart banners (1-2 weeks), ePrivacy consent gate with Branch Strict Mode (1 week), and country-level feature flags for Poland and Germany (1 week). The server-side token exchange is roughly 200 lines of code. The rest is SDK integration and configuration.
What could go wrong
Apple's AASA caching can silently break Universal Links for days. Apple caches the App Site Association file aggressively, with 24-48 hour propagation delays. New path patterns can fail without any error. This is the most common cause of "deep links stopped working" incidents. Test with swcutil and the Apple CDN validator before every deployment. Never create a new domain for deep links. Extend existing paths on app.ramp.network.
15-30% of EU users won't get the seamless flow. Branch SDK fingerprints devices to match deferred links (IP, screen resolution, OS version). EDPB Guidelines 2/2023 classify this as terminal equipment access under ePrivacy Art. 5(3), requiring explicit consent before the SDK initializes. Branch must run in Strict Mode with a CMP consent gate on the web. Users who decline tracking need a fallback path: manual code entry or QR scan. The seamless experience is opt-in.
KNF warns against "active links" in financial communications. Ramp Network's Irish CASP passport governs under MiCAR, but KNF retains host-state consumer protection powers via Art. 92. The warning targets URLs that auto-execute transactions, not passive links that route to a review screen. But the practical risk is real: if Polish users report phishing-style magic links, KNF can request the Central Bank of Ireland to investigate and can impose marketing restrictions. Implement country-level feature flags from day one. Poland and Germany get stricter defaults. Exclude magic links from Polish marketing communications entirely.
Custom URI scheme hijacking is a documented attack vector. The existing rampnetwork:// scheme can be registered by any app on the device. Documented incidents include the Dfns 2023 magic link redirect attack (open redirects enabled token theft to attacker-controlled domains) and fake WalletConnect apps that registered legitimate schemes to drain wallets. The Godfather trojan (active since June 2025) uses virtualization to overlay fake screens on crypto apps during authentication. Deprecate rampnetwork:// for any auth flow. Universal Links with domain verification are the only safe option.
The DORA cross-device problem. If a user receives the magic link via email on their desktop and opens it on their phone, the session originates from two different devices. DORA's operational resilience requirements demand session binding to device and IP. This is solvable by constraining magic links to mobile-only delivery (in-browser redirect on mobile web, not email), but it's a design constraint that needs to be decided upfront.