Build mobile app deep link URI
Assemble a deep link that opens your app instead of a browser: scheme myapp, host product and path /item/42 become myapp://product/item/42, with query pairs encoded after the question mark. Illegal scheme characters are stopped. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Runs in your browser. Free, unlimited — your data never leaves this page.
Mobile apps open content through custom URL schemes such as myapp://product/item/42? Hand-built strings drift—spaces in the scheme, unescaped ampersands, missing slashes—and break open-in-app flows on iOS and Android.
What a custom-scheme deep link is and how the URI is assembled
A mobile deep link with a custom scheme is a URI that the operating system routes to your installed app instead of a browser. The scheme is the token before the colon and double slash—myapp, com.example.app, or my-app+v2—and it must follow the URI scheme grammar: a letter first, then only letters, digits, plus, period, or hyphen. Spaces, underscores, colons, and slashes inside the scheme are illegal and are the most common copy-paste mistakes when a product name is used as the scheme without sanitizing.
After scheme:// comes an optional host (sometimes called authority), such as product, open, or auth, then an optional path like /item/42, then an optional query string of key equals value pairs joined by ampersands. This builder concatenates those pieces in a fixed order: scheme, literal ://, host (may be empty), a path that always gains a single leading slash when non-empty, and a query string only when at least one parameter is present.
Query keys and values are percent-encoded with the same rules browsers use for application/x-www-form-urlencoded style components, so spaces become %20-style escapes and reserved characters cannot split the query. When the host is empty and the path is /promo, the result looks like myapp:///promo; when both host and path are empty you still get a legal scheme:// shell useful as a bare open-app intent.
Where a deep-link URI builder earns its keep
Growth and CRM pipelines generate personalized open-in-app links for every campaign without asking engineers to re-implement percent-encoding. QR and packaging tools need a stable string to print; validating the scheme up front prevents a production recall when someone pastes My App! as the scheme.
Multi-tenant white-label apps map each brand to its own scheme token and still share one builder for path and query conventions. Failed validation does not consume balance. Keep schemes in a documented allow-list on your side, reject illegal characters here, and you get reproducible deep links for SMS, email, ads, and in-app shares without standing up a full link shortener or attribution stack for URI assembly alone.
What you can do with it
Campaign and CRM open-in-app links
Build personalized myapp://host/path?utm… deep links for email, SMS, and ads from a validated scheme and query map.
FAQ
Which scheme characters are allowed?
RFC 3986: a letter first, then only letters, digits, plus (+), period (.), or hyphen (-).
Is host or path required?
No. Both default to empty. You can emit scheme:// alone, scheme://host, scheme:///path, or the full scheme://host/path? query form.
What does the link look like without a host?
With an empty host and the path /promo, the link becomes myapp:///promo, with three slashes. If host and path are both empty, you still get a valid bare link such as myapp:// that simply opens the app.
How are spaces and special characters in the query handled?
Every key and value is percent-encoded with the same rules browsers use for form data, so a space becomes an escape sequence and an ampersand cannot split the query into the wrong pairs.
How many query pairs can one link carry?
Up to 50. Each key must still contain text after trimming spaces, while values may be text, numbers or true and false, and all of them are turned into text before encoding.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/web/deep-link-scheme-build \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"scheme":"myapp"}'const res = await fetch("https://api.kit.forhosting.com/web/deep-link-scheme-build", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"scheme": "myapp"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/web/deep-link-scheme-build",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"scheme": "myapp"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/web/deep-link-scheme-build", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"scheme":"myapp"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"scheme":"myapp"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/web/deep-link-scheme-build", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"scheme": "myapp"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "web.deep_link_scheme_build",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
timeout_sec | 30 |
max_crawl_pages | 25 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
ref=email. Product, growth, and engineering teams need those deep-link URIs to be well-formed every time: a legal scheme token, a predictable host and path, and percent-encoded query pairs that survive copy-paste into push payloads, SMS, QR codes, and ad destinations. This capability accepts a custom scheme, optional host, optional path, and an optional list of query key/value pairs, validates the scheme against the RFC 3986 production, normalizes the path, encodes the query, and returns the finished deep_link string plus structured echo fields. Invalid scheme characters fail with invalid_input instead of emitting a silent broken URI.
What a custom-scheme deep link is and how the URI is assembled
The response echoes scheme, host, path, query_params, query_string, deep_link, and has_query so clients can log structured parts without re-parsing the URI. Because the algorithm is pure and deterministic, the same inputs always yield the same deep_link byte for byte across the free browser path and the paid API path.
Input contract, validation rules, and error behaviour
At most fifty pairs are accepted. Each key must be non-empty after trim; values may be strings, numbers, or booleans and are coerced to string before encoding. POST a JSON body with scheme as the only strictly required field: a non-empty string after trim that matches the pattern letter then letters, digits, plus, period, or hyphen. Aliases url_scheme, custom_scheme, and protocol are accepted. host is optional and defaults to the empty string; when set it must not contain spaces, slash, question mark, or hash. path is optional; when non-empty it must not contain spaces, question mark, or hash, and a leading slash is inserted if you omit it so item/42 becomes /item/42. query_params is an optional array of objects, each with a required key and an optional value (default empty string); aliases query, params, and search_params work the same. Missing scheme, empty scheme, scheme with invalid characters, illegal host or path characters, non-array query_params, or blank keys all fail with invalid_input and a clear message naming the problem—those failures are not billed. On success you receive the normalized scheme, host, and path; the normalized query_params list; query_string without a leading question mark; deep_link as the full URI; and has_query as a boolean. Example: scheme myapp, host product, path /item/42, and query_params ref equals email plus utm_source equals newsletter yields myapp://product/item/42? ref=email&utm_source=newsletter. Pair the deep_link with your app’s associated domains or intent filters on the client; this endpoint only builds the URI string and does not register schemes with the OS or verify that the app is installed.
Where a deep-link URI builder earns its keep
Push notification backends compose scheme, screen host, and entity id into a single deep_link field that the mobile client can parse on cold start.
Integration use cases
Push notification payload targets
Compose scheme, screen host, and entity path into a single deep_link string the mobile client opens on notification tap.
QR, packaging, and QA goldens
Generate printable deep-link URIs and pin byte-stable deep_link values in tests so illegal schemes never ship.
Technical questions
How do I build a mobile app deep-link URI?
Send a custom scheme (required), optional host and path, and optional query_params as {key, value} pairs. The API returns deep_link as scheme://host/path?query with percent-encoded parameters.
What happens if the scheme has invalid characters?
The task fails with invalid_input and a message that names the invalid scheme. No deep_link is returned and the call is not billed.
What does the deep-link URI builder cost?
The browser tool is free. API requests use prepaid KIT balance at $0.002 per successful call; invalid input is not billed.