Deep Linking for Desktop Apps: Avoiding Browser Blocks
How to make deep linking work reliably in desktop apps by handling browser popup blockers


I'm on X/Twitter at@iparaskev
TL;DR#
Problem: Browsers block automatic deep links to desktop apps because they're treated as unwanted popups. Solution: Always require a manual user click to trigger the deep link. Show a modal with a button instead of automatically redirecting.
Contents#
Desktop app deep linking#
Deep linking for desktop apps is when you want your app to open directly via a custom URI scheme (like myapp://
), typically from a web page. This is commonly used in authentication flows where users complete OAuth on a web page and get redirected back to your desktop app.
In this post, I'll explain why deep linking doesn't always work as expected in browsers and how to make it work reliably every time.
This applies to all desktop app frameworks including Tauri, Electron, and native applications.
The problem#
Since we launched Hopp's waiting list, we had an annoying issue with our authentication flow: deep linking was not working with all browsers.
But he struggled with the auth token. He had to insert the auth token manually to log in.
Hopp's real user
This is how our sign-up flow looks:

In the above flow, the problem was the last step, where it was not working all the time and the browser was blocking the deep linking pop-up.
Example from Safari blocking the deep linking pop-up:

Why this is happening#
Modern browsers block deep linking requests that happen automatically because they're treated as popup attempts without explicit user interaction. This is a security feature to prevent websites from opening unwanted applications or windows without the user's consent.

The solution#
The solution is straightforward: always require manual user interaction. Instead of automatically triggering the deep link, show a modal dialog that prompts the user to click a button to open the app.
Yes, this adds one extra click, but it guarantees that deep linking works reliably across all browsers. The key insight is that browsers allow deep links when they're triggered by a direct user action (like clicking a button), but block them when they happen automatically.
const handleOpenHopp = () => {
// ...
try {
window.open(`hopp:///authenticate?token=${appAuthToken}`, "_blank");
} catch {
toast.error("Could not open the app. Please try the manual copy option below.");
}
};
<Button size="lg" onClick={handleOpenHopp}>
Open Hopp
</Button>
The authentication flow went from this:

to this:

Conclusion#
The key takeaway is simple: browsers block automatic deep links, but allow user-initiated ones. When implementing deep linking for desktop apps, always show a confirmation dialog with a button rather than automatically redirecting. This ensures your deep linking works consistently across all browsers and provides a better user experience.
If you have any questions about implementing deep linking in your desktop app, feel free to reach out to me on X/Twitter or email me directly at iason at gethopp dot app.