▸ Agent Skills
7 min read

Deep Linking

GitHubnpmcrates.io

API Reference:

Set your Tauri application as the default handler for an URL.

Supported Platforms

This plugin requires a Rust version of at least 1.77.2

[TABLE]

Setup

Install the deep-link plugin to get started.

Use your project’s package manager to add the dependency:

npm run tauri add deep-link
yarn run tauri add deep-link
pnpm tauri add deep-link
deno task tauri add deep-link
bun tauri add deep-link
cargo tauri add deep-link
  1. Run the following command in the src-tauri folder to add the plugin to the project’s dependencies in Cargo.toml:

    cargo add [email protected]
  2. Modify lib.rs to initialize the plugin:

    #[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() {    tauri::Builder::default()        .plugin(tauri_plugin_deep_link::init())        .run(tauri::generate_context!())        .expect("error while running tauri application");}

    src-tauri/src/lib.rs

  3. Install the JavaScript Guest bindings using your preferred JavaScript package manager:

    npm install @tauri-apps/plugin-deep-link
    yarn add @tauri-apps/plugin-deep-link
    pnpm add @tauri-apps/plugin-deep-link
    deno add npm:@tauri-apps/plugin-deep-link
    bun add @tauri-apps/plugin-deep-link

Setting up

Android

There are two ways to open your app from links on Android:

  1. App Links (http/https + host, verified) For app links, you need a server with a .well-known/assetlinks.json endpoint that must return a text response in the given format:
[  {    "relation": ["delegate_permission/common.handle_all_urls"],    "target": {      "namespace": "android_app",      "package_name": "$APP_BUNDLE_ID",      "sha256_cert_fingerprints": [        $CERT_FINGERPRINT      ]    }  }]

.well-known/assetlinks.json

Where $APP_BUNDLE_ID is the value defined on tauri.conf.json > identifier with - replaced with _ and $CERT_FINGERPRINT is a list of SHA256 fingerprints of your app’s signing certificates, see verify Android applinks for more information.

  1. Custom URI schemes (no host required, no verification) For URIs like myapp://..., you can declare a custom scheme without hosting any files. Use the scheme field in the mobile configuration and omit the host.

iOS

There are two ways to open your app from links on iOS:

  1. Universal Links (https + host, verified) For universal links, you need a server with a .well-known/apple-app-site-association endpoint that must return a JSON response in the given format:
{  "applinks": {    "details": [      {        "appIDs": ["$DEVELOPMENT_TEAM_ID.$APP_BUNDLE_ID"],        "components": [          {            "/": "/open/*",            "comment": "Matches any URL whose path starts with /open/"          }        ]      }    ]  }}

.well-known/apple-app-site-association

Where $DEVELOPMENT_TEAM_ID is the value defined on tauri.conf.json > bundle > iOS > developmentTeam or the TAURI_APPLE_DEVELOPMENT_TEAM environment variable and $APP_BUNDLE_ID is the value defined on tauri.conf.json > identifier.

To verify if your domain has been properly configured to expose the app associations, you can run the following command, replacing <host> with your actual host:

curl -v https://app-site-association.cdn-apple.com/a/v1/<host>

Terminal window

See applinks.details for more information.

  1. Custom URI schemes (no host, no verification) For URIs like myapp://..., you can declare a custom scheme under mobile configuration with "appLink": false (or omit it). The plugin generates the appropriate CFBundleURLTypes entries in your app’s Info.plist. No .well-known files or HTTPS host are needed.

Desktop

On Linux and Windows deep links are delivered as a command line argument to a new app process. The deep link plugin has integration with the single instance plugin if you prefer having a unique app instance receiving the events.

  • First you must add the deep-link feature to the single instance plugin:
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\"))".dependencies]tauri-plugin-single-instance = { version = "2.0.0", features = ["deep-link"] }

src-tauri/Cargo.toml

  • Then configure the single instance plugin which should always be the first plugin you register:
#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() {    let mut builder = tauri::Builder::default();
    #[cfg(desktop)]    {        builder = builder.plugin(tauri_plugin_single_instance::init(|_app, argv, _cwd| {          println!("a new app instance was opened with {argv:?} and the deep link event was already triggered");          // when defining deep link schemes at runtime, you must also check `argv` here        }));    }
    builder = builder.plugin(tauri_plugin_deep_link::init());}

src-tauri/lib.rs

Configuration

Under tauri.conf.json > plugins > deep-link, configure mobile domains/schemes and desktop schemes you want to associate with your application.

Examples

Custom scheme on mobile (no server required):

{  "plugins": {    "deep-link": {      "mobile": [        {          "scheme": ["ovi"],          "appLink": false        }      ]    }  }}

tauri.conf.json

This registers the ovi://* scheme on Android and iOS.

App Link / Universal Link (verified https + host):

{  "plugins": {    "deep-link": {      "mobile": [        {          "scheme": ["https"],          "host": "your.website.com",          "pathPrefix": ["/open"],          "appLink": true        }      ]    }  }}

This registers https://your.website.com/open/* as an app/universal link.

Desktop custom schemes:

{  "plugins": {    "deep-link": {      "desktop": {        "schemes": ["something", "my-tauri-app"]      }    }  }}

Usage

The deep-link plugin is available in both JavaScript and Rust.

When a deep link triggers your app while it’s running, the onOpenUrl callback is called. To detect whether your app was opened via a deep link, use getCurrent on app start.

import { getCurrent, onOpenUrl } from '@tauri-apps/plugin-deep-link';// when using `"withGlobalTauri": true`, you may use// const { getCurrent, onOpenUrl } = window.__TAURI__.deepLink;
const startUrls = await getCurrent();if (startUrls) {  // App was likely started via a deep link  // Note that getCurrent's return value will also get updated every time onOpenUrl gets triggered.}
await onOpenUrl((urls) => {  console.log('deep link:', urls);});

When a deep link triggers your app while it’s running, the plugin’s on_open_url closure is called. To detect whether your app was opened via a deep link, use get_current on app start.

use tauri_plugin_deep_link::DeepLinkExt;
#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() {    tauri::Builder::default()        .plugin(tauri_plugin_deep_link::init())        .setup(|app| {            // Note that get_current's return value will also get updated every time on_open_url gets triggered.            let start_urls = app.deep_link().get_current()?;            if let Some(urls) = start_urls {                // app was likely started by a deep link                println!("deep link URLs: {:?}", urls);            }
            app.deep_link().on_open_url(|event| {                println!("deep link URLs: {:?}", event.urls());            });            Ok(())        })        .run(tauri::generate_context!())        .expect("error while running tauri application");}

src-tauri/src/lib.rs

The configuration section describes how to define static deep link schemes for your application.

On Linux and Windows it is possible to also associate schemes with your application at runtime via the register Rust function.

In the following snippet, we will register the my-app scheme at runtime. After executing the app for the first time, the operating system will open my-app://* URLs with our application:

use tauri_plugin_deep_link::DeepLinkExt;
#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() {    tauri::Builder::default()        .plugin(tauri_plugin_deep_link::init())        .setup(|app| {            #[cfg(desktop)]            app.deep_link().register("my-app")?;            Ok(())        })        .run(tauri::generate_context!())        .expect("error while running tauri application");}

src-tauri/src/lib.rs

Testing

There are some caveats to test deep links for your application.

Desktop

Deep links are only triggered for installed applications on desktop. On Linux and Windows you can circumvent this using the register_all Rust function, which registers all configured schemes to trigger the current executable:

use tauri_plugin_deep_link::DeepLinkExt;
#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() {    tauri::Builder::default()        .plugin(tauri_plugin_deep_link::init())        .setup(|app| {            #[cfg(any(windows, target_os = "linux"))]            {                use tauri_plugin_deep_link::DeepLinkExt;                app.deep_link().register_all()?;            }            Ok(())        })        .run(tauri::generate_context!())        .expect("error while running tauri application");}

src-tauri/src/lib.rs

Windows

To trigger a deep link on Windows you can either open <scheme>://url in the browser or run the following command in the terminal:

start <scheme>://url

Terminal window

Linux

To trigger a deep link on Linux you can either open <scheme>://url in the browser or run xdg-open in the terminal:

xdg-open <scheme>://url

Terminal window

iOS

To trigger an app link on iOS you can open the https://\<host\>/path URL in the browser. For simulators you can leverage the simctl CLI to directly open a link from the terminal:

xcrun simctl openurl booted https://<host>/path

Terminal window

Android

To trigger an app link on Android you can open the https://\<host\>/path URL in the browser. For emulators you can leverage the adb CLI to directly open a link from the terminal:

adb shell am start -a android.intent.action.VIEW -d https://<host>/path <bundle-identifier>

Terminal window

Permissions

By default all potentially dangerous plugin commands and scopes are blocked and cannot be accessed. You must modify the permissions in your capabilities configuration to enable these.

See the Capabilities Overview for more information and the step by step guide to use plugin permissions.

{  "$schema": "../gen/schemas/mobile-schema.json",  "identifier": "mobile-capability",  "windows": ["main"],  "platforms": ["iOS", "android"],  "permissions": [    // Usually you will need core:event:default to listen to the deep-link event    "core:event:default",    "deep-link:default"  ]}

src-tauri/capabilities/default.json

Default Permission

Allows reading the opened deep link via the get_current command

This default permission set includes the following:

  • allow-get-current

Permission Table

IdentifierDescription
deep-link:allow-get-currentEnables the get_current command without any pre-configured scope.
deep-link:deny-get-currentDenies the get_current command without any pre-configured scope.
deep-link:allow-is-registeredEnables the is_registered command without any pre-configured scope.
deep-link:deny-is-registeredDenies the is_registered command without any pre-configured scope.
deep-link:allow-registerEnables the register command without any pre-configured scope.
deep-link:deny-registerDenies the register command without any pre-configured scope.
deep-link:allow-unregisterEnables the unregister command without any pre-configured scope.
deep-link:deny-unregisterDenies the unregister command without any pre-configured scope.

Support on Open CollectiveSponsor on GitHub

© 2026 Tauri Contributors. CC-BY / MIT


Last updated Oct 08, 2026