Convert URLs to Mobile Deep Links with Vanilla JavaScript – Universal App Opener

Category: Javascript , Recommended | January 7, 2026
Authormdsaban
Last UpdateJanuary 7, 2026
LicenseMIT
Tags
Views40 views
Convert URLs to Mobile Deep Links with Vanilla JavaScript – Universal App Opener

Universal App Opener is a lightweight JavaScript library that converts standard HTTP URLs into platform-specific native deep links.

It detects the user’s platform and automatically generates iOS custom schemes or Android intent URLs. This allows web applications to open content directly in native apps like YouTube, LinkedIn, Reddit, GitHub, Instagram, and other platform URLs instead of mobile browsers.

Features:

  • 15+ Platform Support: Handles YouTube, LinkedIn, Instagram, Facebook, Reddit, Spotify, WhatsApp, Discord, GitHub, Pinterest, Twitch, Telegram, Threads, and Snapchat.
  • Automatic OS Detection: Identifies iOS, Android, or desktop environments using user agent parsing.
  • Smart Fallback Logic: Opens the web URL if the native app is not installed after a configurable delay.
  • Custom Scheme & Intent URLs: Generates both iOS custom URL schemes and Android intent URLs automatically.
  • Timestamp Preservation: Maintains video timestamps when converting YouTube URLs to deep links.

How To Use It:

1. Install the universal-app-opener package and import the openLink module into your project.

# Yarn
$ yarn add universal-app-opener
# NPM
$ npm install universal-app-opener
# PNPM
$ pnpm install universal-app-opener
import { openLink } from 'universal-app-opener';

2. The openLink function is the primary entry point. It detects the device and attempts to open the app. If the app fails to load, it falls back to the web URL.

// This automatically handles the 'vnd.youtube://' scheme for iOS
// and 'intent://' structure for Android.
openLink('https://www.youtube.com/watch?v=Jpzf4NsqSag');

3. The openLink() function accepts an options object to control fallback behavior:

  • fallbackToWeb (boolean): Controls whether the library opens the web URL if the native app fails to launch. Set to false if you want to handle the failure manually.
  • fallbackDelay (number): Time in milliseconds to wait before triggering fallback. The library checks if the page became hidden (indicating the app opened). Increase this value on slower devices.
  • openInNewTab (boolean): Opens the fallback web URL in a new browser tab instead of replacing the current page.
openLink('https://www.linkedin.com/in/iamsaban/', {
  fallbackToWeb: true,
  fallbackDelay: 2500,
  openInNewTab: false
});

4. For cases where you need granular control over the deep link generation process, use the lower-level API. his approach is useful when you need to:

  • Display the deep link to the user before opening it
  • Log analytics events before redirecting
  • Implement custom fallback logic
  • Store the deep link for later use
import { generateDeepLink, detectOS } from 'universal-app-opener';
// Generate deep link data without opening it
const result = generateDeepLink('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
// Detect the current operating system
const os = detectOS(); // Returns 'ios', 'android', or 'desktop'
// Manually handle the redirect based on platform
if (os === 'ios' && result.ios) {
  window.location.href = result.ios; // Opens iOS app
} else if (os === 'android' && result.android) {
  window.location.href = result.android; // Opens Android app
} else {
  window.open(result.webUrl, '_blank'); // Falls back to web
}

5. API methods.

// Converts a web URL into platform-specific deep links
// Returns an object with ios, android, webUrl, and platform properties
const result = generateDeepLink(url);
// Example: Generate deep links for a LinkedIn profile
const result = generateDeepLink('https://www.linkedin.com/in/iamsaban/');
console.log(result.ios);      // 'linkedin://in/iamsaban'
console.log(result.android);  // Android intent URL
console.log(result.platform); // 'linkedin'
// Detects the current operating system
// Returns 'ios', 'android', or 'desktop'
const os = detectOS();
// Example: Conditional logic based on platform
const os = detectOS();
if (os === 'ios') {
  console.log('iOS device detected');
}

Supported Platforms:

YouTube

  • Video URLs (watch, shorts, embed, live)
  • Preserves timestamp parameters (?t= or &start=)

LinkedIn

  • User profiles (/in/username)
  • Posts (/posts/ or /feed/update/)
  • Company pages (/company/name)
  • Job listings (/jobs/view/id)

Instagram

  • User profiles
  • Posts (/p/)
  • Reels (/reel/)
  • IGTV videos (/tv/)

Facebook

  • General Facebook URLs (profiles, posts, pages)

Reddit

  • Subreddits (/r/name)
  • User profiles (/u/name or /user/name)

Spotify

  • Tracks, artists, albums, playlists
  • Podcasts (shows, episodes)
  • Audiobooks

WhatsApp

  • Chat links with phone numbers (wa.me/+1234567890)
  • Pre-filled text messages

Discord

  • Server channels (/channels/guild/channel)
  • Invite links (discord.gg/ or /invite/)

GitHub

  • User profiles
  • Repositories
  • Pull requests, issues, file paths

Pinterest

  • Pins
  • Boards
  • User profiles

Twitch

  • Channels
  • Videos
  • Clips
  • Game directories

Telegram

  • Channels and groups
  • Messages with IDs

Threads

  • User profiles

Snapchat

  • Add user by username

FAQs:

Q: Why does the fallback sometimes trigger even when the app is installed?
A: The fallback mechanism relies on detecting whether the page became hidden after attempting to open the deep link. On some Android devices, the OS doesn’t hide the browser immediately when launching an app. Increase the fallbackDelay option to 3000-4000ms to allow more time for the app transition. You can also disable fallback entirely by setting fallbackToWeb: false and implementing your own detection logic.

Q: Can I use this library with server-side rendered applications?
A: The library requires browser APIs like navigator.userAgent and window.location, so it only works in client-side JavaScript. For Next.js or other SSR frameworks, wrap your calls in a useEffect hook or check for typeof window !== 'undefined' before importing. The library will throw an error if you attempt to use it during server-side rendering.

Q: Does this work with app clip links or universal links on iOS?
A: No. This library generates traditional custom URL schemes (youtube://) and Android intents. It does not handle iOS universal links (which use standard HTTPS URLs and require server-side configuration) or app clips.

Q: Why do some YouTube timestamps fail to convert properly?
A: The library supports ?t= and &start= parameters in formats like 45, 1m30s, or 1h2m3s. If you’re using a different timestamp format or the parameter is misspelled, the timestamp will be ignored.

You Might Be Interested In:


Leave a Reply