{"id":1845,"date":"2026-07-25T13:00:00","date_gmt":"2026-07-25T18:00:00","guid":{"rendered":"https:\/\/tolinku.com\/blog\/?p=1845"},"modified":"2026-03-07T03:37:27","modified_gmt":"2026-03-07T08:37:27","slug":"deep-link-parameters","status":"publish","type":"post","link":"https:\/\/tolinku.com\/blog\/deep-link-parameters\/","title":{"rendered":"Deep Link Parameters: Passing Data Through Links"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A deep link that opens the app is useful. A deep link that opens the app, navigates to the right product, applies a discount code, and attributes the visit to the right campaign is powerful. The difference is parameters: data encoded in the URL that the app reads on arrival.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This guide covers how to pass and handle parameters in deep links. For routing, see <a href=\"https:\/\/tolinku.com\/blog\/deep-link-routing-guide\/\">deep link routing: how to route users to the right screen<\/a>. For contextual deep linking, see <a href=\"https:\/\/tolinku.com\/blog\/contextual-deep-linking-guide\/\">contextual deep linking: pass data through the install<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><img decoding=\"async\" src=\"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/platform-route-form.png\" alt=\"Tolinku route creation form with link type, path, and behavior settings\">\n<em>The route creation form with basics, behavior, and advanced settings sections.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Parameter Types<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Path Parameters<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Data embedded in the URL path:<\/p>\n\n\n\n<pre><code>https:\/\/app.example.com\/products\/abc123\n                                 ^^^^^^\n                                 Path parameter: productId = &quot;abc123&quot;\n\nhttps:\/\/app.example.com\/users\/jane\/posts\/42\n                              ^^^^       ^^\n                              userId     postId\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Path parameters are best for resource identification: which product, which user, which post.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Query Parameters<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Data after the <code>?<\/code> in the URL:<\/p>\n\n\n\n<pre><code>https:\/\/app.example.com\/products\/abc123?ref=email&amp;campaign=summer&amp;discount=SAVE20\n                                        ^^^       ^^^^^^^^        ^^^^^^^^\n                                        source    campaign        promo code\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Query parameters are best for metadata: tracking, configuration, and optional modifiers.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Fragment Parameters<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Data after the <code>#<\/code>:<\/p>\n\n\n\n<pre><code>https:\/\/app.example.com\/docs\/guide#section-3\n                                   ^^^^^^^^^\n                                   Scroll to section\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Fragments are rarely used in deep links because they are not sent to the server. Use them only for client-side navigation within a page.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Parsing Parameters<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">iOS (Swift)<\/h3>\n\n\n\n<pre><code class=\"language-swift\">func parseDeepLink(_ url: URL) -&gt; DeepLinkData? {\n    guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {\n        return nil\n    }\n\n    \/\/ Path parameters\n    let pathComponents = components.path\n        .split(separator: &quot;\/&quot;)\n        .map(String.init)\n\n    \/\/ Query parameters\n    let queryItems = components.queryItems ?? []\n    let queryDict = Dictionary(\n        uniqueKeysWithValues: queryItems.compactMap { item in\n            item.value.map { (item.name, $0) }\n        }\n    )\n\n    \/\/ Example: \/products\/abc123?ref=email\n    if pathComponents.first == &quot;products&quot;, let productId = pathComponents.dropFirst().first {\n        return DeepLinkData(\n            screen: .product(id: String(productId)),\n            source: queryDict[&quot;ref&quot;],\n            campaign: queryDict[&quot;campaign&quot;],\n            discountCode: queryDict[&quot;discount&quot;]\n        )\n    }\n\n    return nil\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Android (Kotlin)<\/h3>\n\n\n\n<pre><code class=\"language-kotlin\">fun parseDeepLink(uri: Uri): DeepLinkData? {\n    \/\/ Path parameters\n    val pathSegments = uri.pathSegments\n\n    \/\/ Query parameters\n    val ref = uri.getQueryParameter(&quot;ref&quot;)\n    val campaign = uri.getQueryParameter(&quot;campaign&quot;)\n    val discount = uri.getQueryParameter(&quot;discount&quot;)\n\n    \/\/ Example: \/products\/abc123?ref=email\n    if (pathSegments.firstOrNull() == &quot;products&quot; &amp;&amp; pathSegments.size &gt;= 2) {\n        val productId = pathSegments[1]\n        return DeepLinkData(\n            screen = Screen.Product(productId),\n            source = ref,\n            campaign = campaign,\n            discountCode = discount\n        )\n    }\n\n    return null\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">TypeScript (Server-Side)<\/h3>\n\n\n\n<pre><code class=\"language-typescript\">function parseDeepLink(url: string): DeepLinkData | null {\n  const parsed = new URL(url);\n  const segments = parsed.pathname.split(&#39;\/&#39;).filter(Boolean);\n\n  \/\/ Path parameter extraction with pattern matching\n  const routes: RoutePattern[] = [\n    { pattern: [&#39;products&#39;, &#39;:productId&#39;], screen: &#39;ProductDetail&#39; },\n    { pattern: [&#39;users&#39;, &#39;:userId&#39;, &#39;posts&#39;, &#39;:postId&#39;], screen: &#39;Post&#39; },\n    { pattern: [&#39;offers&#39;, &#39;:offerId&#39;], screen: &#39;Offer&#39; },\n    { pattern: [&#39;referral&#39;, &#39;:referrerId&#39;], screen: &#39;Referral&#39; },\n  ];\n\n  for (const route of routes) {\n    const params = matchRoute(segments, route.pattern);\n    if (params) {\n      return {\n        screen: route.screen,\n        pathParams: params,\n        queryParams: Object.fromEntries(parsed.searchParams),\n      };\n    }\n  }\n\n  return null;\n}\n\nfunction matchRoute(\n  segments: string[],\n  pattern: string[]\n): Record&lt;string, string&gt; | null {\n  if (segments.length !== pattern.length) return null;\n\n  const params: Record&lt;string, string&gt; = {};\n  for (let i = 0; i &lt; pattern.length; i++) {\n    if (pattern[i].startsWith(&#39;:&#39;)) {\n      params[pattern[i].substring(1)] = segments[i];\n    } else if (pattern[i] !== segments[i]) {\n      return null;\n    }\n  }\n  return params;\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Common Parameter Patterns<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Campaign Tracking (UTM)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use <a href=\"https:\/\/en.wikipedia.org\/wiki\/UTM_parameters\" rel=\"nofollow noopener\" target=\"_blank\">UTM parameters<\/a> for campaign attribution:<\/p>\n\n\n\n<pre><code>https:\/\/app.example.com\/offers\/summer?utm_source=email&amp;utm_medium=newsletter&amp;utm_campaign=july-promo&amp;utm_content=hero-banner\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Parameter<\/th>\n<th>Purpose<\/th>\n<th>Example<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td><code>utm_source<\/code><\/td>\n<td>Traffic source<\/td>\n<td><code>email<\/code>, <code>facebook<\/code>, <code>push<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>utm_medium<\/code><\/td>\n<td>Marketing medium<\/td>\n<td><code>newsletter<\/code>, <code>paid<\/code>, <code>social<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>utm_campaign<\/code><\/td>\n<td>Campaign name<\/td>\n<td><code>july-promo<\/code>, <code>back-to-school<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>utm_content<\/code><\/td>\n<td>Content variant<\/td>\n<td><code>hero-banner<\/code>, <code>footer-link<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>utm_term<\/code><\/td>\n<td>Paid search keyword<\/td>\n<td><code>deep linking tutorial<\/code><\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Referral Parameters<\/h3>\n\n\n\n<pre><code>https:\/\/app.example.com\/referral?ref=user123&amp;reward=both\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Parameter<\/th>\n<th>Purpose<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td><code>ref<\/code><\/td>\n<td>Referrer&#39;s user ID or code<\/td>\n<\/tr>\n<tr>\n<td><code>reward<\/code><\/td>\n<td>Reward type (<code>referrer<\/code>, <code>referee<\/code>, <code>both<\/code>)<\/td>\n<\/tr>\n<tr>\n<td><code>channel<\/code><\/td>\n<td>How the referral was shared (<code>sms<\/code>, <code>whatsapp<\/code>, <code>copy<\/code>)<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Promotional Parameters<\/h3>\n\n\n\n<pre><code>https:\/\/app.example.com\/products\/summer-sale?promo=SAVE20&amp;expires=2026-08-01\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Parameter<\/th>\n<th>Purpose<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td><code>promo<\/code><\/td>\n<td>Discount\/promo code to auto-apply<\/td>\n<\/tr>\n<tr>\n<td><code>expires<\/code><\/td>\n<td>When the offer expires<\/td>\n<\/tr>\n<tr>\n<td><code>min_order<\/code><\/td>\n<td>Minimum order value<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Personalization Parameters<\/h3>\n\n\n\n<pre><code>https:\/\/app.example.com\/home?locale=de&amp;theme=dark&amp;onboarding=skip\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Parameter<\/th>\n<th>Purpose<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td><code>locale<\/code><\/td>\n<td>Language\/region for localized content<\/td>\n<\/tr>\n<tr>\n<td><code>theme<\/code><\/td>\n<td>UI theme preference<\/td>\n<\/tr>\n<tr>\n<td><code>onboarding<\/code><\/td>\n<td>Whether to show onboarding flow<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Encoding and Security<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">URL Encoding<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Parameters must be properly <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/encodeURIComponent\" rel=\"nofollow noopener\" target=\"_blank\">URL-encoded<\/a>:<\/p>\n\n\n\n<pre><code class=\"language-typescript\">\/\/ Encoding parameters\nconst productName = &quot;Summer Sale &amp; 20% Off!&quot;;\nconst encoded = encodeURIComponent(productName);\n\/\/ Result: &quot;Summer%20Sale%20%26%2020%25%20Off!&quot;\n\nconst url = `https:\/\/app.example.com\/search?q=${encoded}`;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Characters that must be encoded:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Character<\/th>\n<th>Encoded<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>Space<\/td>\n<td><code>%20<\/code> or <code>+<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>&amp;<\/code><\/td>\n<td><code>%26<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>=<\/code><\/td>\n<td><code>%3D<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>?<\/code><\/td>\n<td><code>%3F<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>#<\/code><\/td>\n<td><code>%23<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>\/<\/code><\/td>\n<td><code>%2F<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>%<\/code><\/td>\n<td><code>%25<\/code><\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Input Validation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Never trust parameters from deep links. Validate everything:<\/p>\n\n\n\n<pre><code class=\"language-typescript\">function validateParams(params: Record&lt;string, string&gt;): Record&lt;string, string&gt; {\n  const validated: Record&lt;string, string&gt; = {};\n\n  \/\/ Whitelist allowed parameter names\n  const allowed = [&#39;ref&#39;, &#39;campaign&#39;, &#39;promo&#39;, &#39;locale&#39;, &#39;q&#39;];\n\n  for (const [key, value] of Object.entries(params)) {\n    if (!allowed.includes(key)) continue;\n\n    \/\/ Limit value length\n    if (value.length &gt; 256) continue;\n\n    \/\/ Strip HTML\/script tags\n    const sanitized = value.replace(\/&lt;[^&gt;]*&gt;\/g, &#39;&#39;);\n\n    validated[key] = sanitized;\n  }\n\n  return validated;\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Sensitive Data<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Never put sensitive information in URL parameters:<\/p>\n\n\n\n<pre><code>\/\/ BAD: Token in URL (visible in logs, analytics, referrer headers)\nhttps:\/\/app.example.com\/login?token=eyJhbGciOiJI...\n\n\/\/ BETTER: Short-lived reference that resolves server-side\nhttps:\/\/app.example.com\/auth\/callback?code=abc123\n\/\/ The app exchanges the code for a token via a secure API call\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">AASA and Query Parameters<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The modern AASA format supports query parameter matching:<\/p>\n\n\n\n<pre><code class=\"language-json\">{\n  &quot;applinks&quot;: {\n    &quot;details&quot;: [\n      {\n        &quot;appIDs&quot;: [&quot;TEAMID.com.example.app&quot;],\n        &quot;components&quot;: [\n          {\n            &quot;\/&quot;: &quot;\/products\/*&quot;,\n            &quot;comment&quot;: &quot;All product pages&quot;\n          },\n          {\n            &quot;\/&quot;: &quot;\/offers\/*&quot;,\n            &quot;?&quot;: { &quot;source&quot;: &quot;app&quot; },\n            &quot;comment&quot;: &quot;Only offers with source=app open in the app&quot;\n          }\n        ]\n      }\n    ]\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">With this configuration, <code>https:\/\/app.example.com\/offers\/summer?source=app<\/code> opens the app, but <code>https:\/\/app.example.com\/offers\/summer?source=web<\/code> does not.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dynamic Routes with Parameters<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Server-Side Parameter Resolution<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For dynamic routes, the server resolves the path parameter to content:<\/p>\n\n\n\n<pre><code class=\"language-typescript\">app.get(&#39;\/products\/:productId&#39;, async (req, res) =&gt; {\n  const { productId } = req.params;\n  const product = await db.getProduct(productId);\n\n  if (!product) {\n    \/\/ Unknown product: show 404 or redirect to products listing\n    return res.redirect(&#39;\/products&#39;);\n  }\n\n  \/\/ Mobile: redirect to app\n  if (isMobile(req)) {\n    return res.redirect(`myapp:\/\/products\/${productId}`);\n  }\n\n  \/\/ Desktop: show web page\n  res.render(&#39;product&#39;, { product });\n});\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Client-Side Parameter Handling<\/h3>\n\n\n\n<pre><code class=\"language-swift\">\/\/ iOS: Handle the product ID from the deep link\nfunc showProduct(from url: URL) {\n    let data = parseDeepLink(url)\n    guard let productId = data?.pathParams[&quot;productId&quot;] else {\n        showHomeScreen()\n        return\n    }\n\n    \/\/ Apply query parameters\n    if let promoCode = data?.queryParams[&quot;promo&quot;] {\n        applyPromoCode(promoCode)\n    }\n\n    \/\/ Navigate\n    navigationController.pushViewController(\n        ProductViewController(productId: productId),\n        animated: true\n    )\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Tolinku for Deep Link Parameters<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/tolinku.com\/features\/deep-linking\">Tolinku&#39;s routes<\/a> support both path parameters and query parameters. Configure <a href=\"https:\/\/tolinku.com\/docs\/user-guide\/routes\/dynamic-routes\/\">dynamic routes<\/a> with parameter patterns like <code>\/products\/:id<\/code> to pass data through deep links automatically.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For routing, see <a href=\"https:\/\/tolinku.com\/blog\/deep-link-routing-guide\/\">deep link routing: how to route users to the right screen<\/a>. For the full guide, see <a href=\"https:\/\/tolinku.com\/blog\/complete-guide-deep-linking-2026\/\">the complete guide to deep linking in 2026<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to pass parameters through deep links. Handle query strings, path parameters, and custom data for personalized app experiences.<\/p>\n","protected":false},"author":2,"featured_media":1844,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"Deep Link Parameters: Passing Data Through Links","rank_math_description":"Learn how to pass parameters through deep links. Handle query strings, path parameters, and custom data for personalized app experiences.","rank_math_focus_keyword":"deep link parameters","rank_math_canonical_url":"","rank_math_facebook_title":"","rank_math_facebook_description":"","rank_math_facebook_image":"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/og-deep-link-parameters.png","rank_math_facebook_image_id":"","rank_math_twitter_title":"","rank_math_twitter_description":"","rank_math_twitter_image":"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/og-deep-link-parameters.png","footnotes":""},"categories":[11],"tags":[25,20,75,24,69,236,43,183],"class_list":["post-1845","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-deep-linking","tag-android","tag-deep-linking","tag-developer-tools","tag-ios","tag-mobile-development","tag-parameters","tag-personalization","tag-routing"],"_links":{"self":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1845","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/comments?post=1845"}],"version-history":[{"count":2,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1845\/revisions"}],"predecessor-version":[{"id":2429,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1845\/revisions\/2429"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media\/1844"}],"wp:attachment":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media?parent=1845"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/categories?post=1845"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/tags?post=1845"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}