Deep Links
Use throne:// links to add subscriptions, routing profiles and proxy profiles with one click, on desktop and Android.
A deep link is a throne:// URL that tells Throne to do one job: add a subscription, import a routing profile, add remote routing profiles, or add one proxy profile. Providers put deep links on websites and in QR codes. You can also use them to share your own routing profiles.
How Throne receives a deep link
Your system must know that Throne opens throne:// links. Throne registers itself for your user account only, and this needs no administrator rights.
| System | Registered by default |
|---|---|
| Linux | Yes |
| macOS | Yes, when you run Throne from Throne.app |
| Windows, installed with the installer | Yes |
| Windows, unpacked from a ZIP file | No |
To turn registration on, for example for a Windows ZIP copy:
- Open
Settings→Basic Settings. - On the
Commontab, underLinks and Files, tickRegister throne:// links at startup. - Press
OK. Throne registers itself right away.
While the option is on, Throne checks the registration at every start and repairs it, for example after you move the Throne folder. If you keep several copies on Windows or Linux, links open in the last copy that started with the option on.
The status next to the option shows Installed when links open this copy of Throne. The Install button registers once, without turning the option on. Uninstall removes the registration and turns the option off. Unticking the option alone keeps the existing registration.
macOS: the link handler is part of Throne.app, so there are no Install and Uninstall buttons. If Throne does not run from the app bundle, the option shows Not available for this installation.
Throne accepts a deep link in these ways:
- Click the link in a browser, chat app or document. If Throne is not running, it starts and then handles the link.
- Copy the link and press
Ctrl+Vin the main window (Program→Add profile from clipboard). This works even when registration is off. - Drag the link text onto the main window.
- Pass the link as an argument when you start Throne. See Command line.
Link format
Every deep link has the same shape:
throne://<command>/<payload>
- Write
throne://in lowercase. The command is not case-sensitive:throne://AddSub/…works. - A slash and the payload must follow the command. Without the slash, most links do nothing.
- Throne ignores anything after
?or#in the link. Everything the link carries is inside the payload. - If the payload is percent-encoded (for example
%2Binstead of+), Throne decodes it first.
| Command | What it does | Asks first? |
|---|---|---|
addsub |
Adds a subscription group and updates it | Yes |
route |
Imports a routing profile carried inside the link | Yes |
remoteroute |
Adds remote routing profiles by URL | Yes |
add |
Adds one proxy profile to the current group | No. On Android, yes when you tap the link in another app. |
Base64 rules
The payload is Base64 text. Which Base64 alphabet works depends on the command:
| Command | Accepted payload |
|---|---|
addsub, remoteroute |
Standard Base64 only: letters, digits, + and /. The = padding at the end is optional. |
route, add |
URL-safe Base64 (- and _) or standard Base64, with or without padding. Throne itself writes URL-safe Base64 without padding. |
For addsub and remoteroute, a URL-safe payload that contains - or _ fails. Keep the payload on one line, without spaces.
To encode a payload on Linux, or in Git Bash on Windows:
printf '%s' 'https://example.com/sub/abc123#MyProvider' | base64 -w 0
On macOS, leave out -w 0. In PowerShell:
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('https://example.com/sub/abc123#MyProvider'))
Both commands print standard Base64 with padding.
addsub: add a subscription
Adds a new subscription group and updates it right away.
throne://addsub/<base64>
The payload is the Base64 of one line:
<subscription_url>#<group_name>
| Part | Required | Description |
|---|---|---|
<subscription_url> |
Yes | The subscription URL, unchanged. Its ?, & and / are safe inside the Base64, so you do not need to percent-encode it. |
#<group_name> |
No | The name of the new group. Without it, the group is named after the host of the URL. Percent-encoding the name is optional: a plain space works. |
For example, to add https://example.com/sub/abc123 as a group named MyProvider, encode https://example.com/sub/abc123#MyProvider:
throne://addsub/aHR0cHM6Ly9leGFtcGxlLmNvbS9zdWIvYWJjMTIzI015UHJvdmlkZXI=
Throne shows "Add this subscription?" with the group name and the URL, and an Auto update checkbox that is ticked. After you confirm, Throne creates the group and updates it.
route: import a routing profile
Imports a whole routing profile (default outbound and rules) that is carried inside the link.
throne://route/<base64>
You do not need to build these links by hand. In Routing Settings, on the Route tab, select the profile and press Export, or press Ctrl+C in the list. Throne copies a throne://route/… link to the clipboard.
When someone opens the link, Throne shows "Add this routing profile?" with the name, plus notes about anything it could not import. After they confirm, the profile is added to their list. If the profile has VPN endpoints, Throne creates those OpenVPN or OpenConnect profiles before it asks, and keeps them even when the import is cancelled. The imported routing profile does not become active: choose it in the list at the bottom of the Routing menu.
The payload is the Base64 of a small JSON object like this one:
{
"kind": "throne-route-profile",
"v": 1,
"name": "Example",
"default_outbound": "proxy",
"rules": []
}
This link carries that JSON:
throne://route/eyJraW5kIjoidGhyb25lLXJvdXRlLXByb2ZpbGUiLCJ2IjoxLCJuYW1lIjoiRXhhbXBsZSIsImRlZmF1bHRfb3V0Ym91bmQiOiJwcm94eSIsInJ1bGVzIjpbXX0
default_outbound is proxy, direct, block or warp-bypass. A raw profile (a hand-written sing-box route section) carries "raw": true and a route object instead of rules. Throne looks up the servers that the rules use by their names and tells you about any it could not find. For more about sharing, see Routing.
Import in Routing Settings
You can also paste a link on the Route tab of Routing Settings: press Import, or press Ctrl+V in the list. In the main window, only text that starts with throne:// counts as a deep link. Here, Throne also accepts the Base64 payload alone, the plain JSON, and an old-style JSON list of rules, which opens in the editor so you can name it. A profile imported from a route link, its Base64 or its JSON also becomes the selected Routing Profile on the Common tab when you press OK.
A remoteroute link pasted here adds its profiles with auto update off, because this prompt has no Auto update checkbox. You can tick Auto update later in the editor of each profile.
remoteroute: add remote routing profiles
Adds one or more remote routing profiles. A route link carries the whole profile. A remoteroute link carries only URLs: Throne downloads each profile and can keep it up to date. Use it to hand out a routing profile that you maintain.
throne://remoteroute/<base64>
The payload is the Base64 of a plain list of URLs, one per line. It is not JSON:
<profile_url_1>#<name_1>
<profile_url_2>#<name_2>
| Part | Required | Description |
|---|---|---|
<profile_url> |
Yes | An http:// or https:// URL. Lines that do not start with one of these are skipped. |
#<name> |
No | The profile name. Without it, the profile is named after the host of the URL. |
Each URL must serve a structured routing profile: a throne://route/ link, its Base64 payload, or the JSON inside it. Raw profiles cannot be used as remote profiles.
For example, encode these two lines:
printf '%s\n%s' 'https://example.com/routes/bypass-iran.json#BypassIran' 'https://example.com/routes/ads.json' | base64 -w 0
The result is this link:
throne://remoteroute/aHR0cHM6Ly9leGFtcGxlLmNvbS9yb3V0ZXMvYnlwYXNzLWlyYW4uanNvbiNCeXBhc3NJcmFuCmh0dHBzOi8vZXhhbXBsZS5jb20vcm91dGVzL2Fkcy5qc29u
Throne lists the URLs under "Add these remote routing profiles?" with one Auto update checkbox for all of them. The checkbox is ticked. After you confirm, Throne adds the profiles and downloads them. The log shows how many it fetched.
- Throne refreshes profiles that have
Auto updateon only whenBasic Settings→Subscription→Routing profiles auto update→Enableis ticked. It is off by default. To update by hand, useUpdateon theRoutetab ofRouting Settings. See Remote profiles. - An update replaces the rules and the default outbound of the profile with the downloaded ones. The name of the profile stays.
- URLs on
raw.githubusercontent.comare downloaded through theRemote Rule-set Mirrorchosen on theCommontab ofRouting Settings(a jsDelivr mirror by default). A mirror may serve an older copy for some time after you change the file. Routing→Download Profilesworks the same way: it downloads aremoteroutelink from Throne's routing profile repository and shows the same prompt.
add: add one proxy profile
Adds one proxy profile to the current group.
throne://add/<base64>
The payload is the Base64 of the profile's outbound settings as JSON. On desktop this link does not ask for confirmation: the profile is added at once, as if you had pasted a vless:// or ss:// link.
Throne generates these links for you:
- Right-click profiles in the list →
Share→Copy links of selected (Deep Links)(Ctrl+Alt+C). - Right-click a profile →
Share→QR Code and link. The window shows either the normal share link or the deep link. TickDeep Linkto switch between them. Groups→Edit current Group→Copy profile share links (Deep Links).
A deep link carries the full profile configuration, so it also works for profile types and options that have no standard share link. For such profiles, Copy links of selected (Ctrl+C) usually copies a deep link automatically, and the QR window opens with Deep Link ticked. If such a profile has advanced connection options, such as a bind interface, use Copy links of selected (Deep Links) instead.
add links also work wherever normal share links work: inside subscriptions, in files and in QR codes.
On Android
Throne for Android 2.0.0 handles the same four commands. It also accepts clash://install-config?url=…&name=… links, which add a subscription like addsub. In these links, percent-encode the url value. The throne:// scheme is registered when you install the app; there is no setting for it.
Tap the link in another app, or use Add profile → Import from clipboard or Scan QR code on the Profiles screen. On Android, QR codes work for all four commands. route and remoteroute links also work with Import on the Routing screen.
Differences from desktop:
- An
addlink that you tap in another app asks "Confirm you want to import profile …?" first. Links such asvless://tapped in another app ask the same. From the clipboard or a QR code, the profile is imported without a question. - An imported routing profile is added but does not become active. Tap it on the
Routingscreen to use it. - Raw routing profiles from desktop (
"raw": true) are refused with "raw routing profiles are not supported on Android". Endpoints in a shared routing profile are dropped with a note. - An unknown command shows "Ignored deeplink with unknown command: …" on the screen, not only in the log.
- Scheduled updates need
Settings→Subscriptions→Subscription auto updatefor subscriptions, andSettings→Routing→Auto update remote profilesfor remote routing profiles. Both are off by default.
The Android app can also create these links: add links for profiles and route links for routing profiles.
Troubleshooting
These messages are from Throne desktop.
- Clicking a link does nothing, or the browser asks which app to use. The link handler is not registered for this copy. On a Windows ZIP copy, turn on
Register throne:// links at startup(see How Throne receives a deep link). On macOS, run Throne fromThrone.app. Otherwise start Throne once. If you keep several copies, pressInstallin the copy that should open links. You can always copy the link and pressCtrl+Vin Throne instead. - Linux: links still do not open. Registration runs the
update-desktop-databasetool from thedesktop-file-utilspackage. If the tool was missing, install it, then pressInstallnext toRegister throne:// links at startup. - Nothing happens and the log stays empty. Throne drops these links without a message:
- an
addsublink whose payload is not valid standard Base64, for example URL-safe Base64 with-or_, or a payload with spaces or line breaks; - a link without the slash after the command, except
addandremoteroutelinks; - a link with an unknown command whose payload does not decode.
- an
- "Ignored deeplink with unknown command: …" in the log. The word after
throne://is notaddsub,route,remoterouteoradd. Check the spelling. - "The link did not contain a subscription URL." The
addsubpayload decoded, but there is no URL before the#. Encode<url>#<name>, not only#<name>. - "Deep link has no data" or "Base64 is invalid." These come from
remoteroutelinks: nothing followsthrone://remoteroute/, or the payload is not standard Base64. - "The link did not contain any valid http(s) routing profile URLs." The
remoteroutepayload decoded, but no line starts withhttp://orhttps://. The payload must be a list of URLs, one per line, not JSON. - "The link did not contain any valid remote routing profiles." The link has no slash after
remoteroute. - "The link could not be parsed:" and a reason. This comes from
routelinks:- "Empty input": nothing follows
throne://route/. - "Input is not valid JSON, base64, or a Throne route link": the payload is damaged or cut off.
- "Unrecognized route object": the JSON has no
"kind": "throne-route-profile".
- "Empty input": nothing follows
- "Imported 0 profile(s)" in the log. An
addpayload is damaged or cut off. Or you scanned a QR code that holds anaddsub,routeorremoteroutelink: copy the text afterQR Code Result:from the log and pressCtrl+V. - "Remote routing profile … failed: …" in the log. The profile was added, but its URL could not be downloaded or does not serve a structured routing profile. Fix the URL or the file, then use
Updateon theRoutetab ofRouting Settings.