{"id":1413,"date":"2026-06-11T13:00:00","date_gmt":"2026-06-11T18:00:00","guid":{"rendered":"https:\/\/tolinku.com\/blog\/?p=1413"},"modified":"2026-03-07T03:49:12","modified_gmt":"2026-03-07T08:49:12","slug":"link-format-mapping","status":"publish","type":"post","link":"https:\/\/tolinku.com\/blog\/link-format-mapping\/","title":{"rendered":"Link Format Mapping: Converting Links Between Platforms"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Every deep linking platform uses a different URL structure for its links. When you migrate between platforms, you need to map the old link format to the new one so that redirects work correctly and new links follow the same conventions your team expects.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This guide covers the structural differences between common deep link formats and provides practical mapping strategies. For the migration timeline, see <a href=\"https:\/\/tolinku.com\/blog\/migration-timeline-planning\/\">migration timeline planning<\/a>. For redirect setup, see <a href=\"https:\/\/tolinku.com\/blog\/link-redirect-during-migration\/\">link redirects during migration<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Understanding Deep Link URL Structure<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A deep link URL consists of several components, each carrying different information:<\/p>\n\n\n\n<pre><code>https:\/\/links.yourapp.com\/campaign\/summer-sale?utm_source=email&amp;utm_medium=newsletter&amp;deep_link=products\/123\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Breaking this down:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Component<\/th>\n<th>Value<\/th>\n<th>Purpose<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>Domain<\/td>\n<td><code>links.yourapp.com<\/code><\/td>\n<td>Your custom link domain<\/td>\n<\/tr>\n<tr>\n<td>Path<\/td>\n<td><code>\/campaign\/summer-sale<\/code><\/td>\n<td>Route identifier<\/td>\n<\/tr>\n<tr>\n<td>Query: <code>utm_source<\/code><\/td>\n<td><code>email<\/code><\/td>\n<td>Campaign tracking<\/td>\n<\/tr>\n<tr>\n<td>Query: <code>utm_medium<\/code><\/td>\n<td><code>newsletter<\/code><\/td>\n<td>Campaign tracking<\/td>\n<\/tr>\n<tr>\n<td>Query: <code>deep_link<\/code><\/td>\n<td><code>products\/123<\/code><\/td>\n<td>In-app destination<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Each platform structures these components differently. The mapping challenge is converting between these structures while preserving all the information.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Platform-Specific Link Formats<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Format Type 1: Hash-Based Short Links<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Some platforms encode all link data in a short hash:<\/p>\n\n\n\n<pre><code>https:\/\/platform.link\/AbCd123\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The hash (<code>AbCd123<\/code>) maps to a database record on the platform&#39;s servers. The actual deep link data (destination URL, campaign parameters, fallback behavior) is stored server-side and not visible in the URL.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Migration challenge:<\/strong> You cannot parse these URLs to extract the deep link data. You need to use the old platform&#39;s API to export the link configurations, then recreate them on the new platform.<\/p>\n\n\n\n<pre><code class=\"language-javascript\">\/\/ Export link data from hash-based links\nasync function exportShortLinks(oldPlatformApi) {\n  const links = await oldPlatformApi.getLinks({ limit: 1000 });\n  return links.map(link =&gt; ({\n    shortUrl: link.url,\n    deepLinkPath: link.deepLink,\n    campaign: link.campaign,\n    fallbackUrl: link.fallbackUrl,\n    createdAt: link.createdAt,\n  }));\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Format Type 2: Path-Based Links<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Some platforms encode the deep link destination in the URL path:<\/p>\n\n\n\n<pre><code>https:\/\/links.yourapp.com\/products\/123\nhttps:\/\/links.yourapp.com\/profile\/user456\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The path directly maps to the in-app destination. This format is the most URL-friendly and the easiest to migrate because the intent is visible in the URL itself.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Migration strategy:<\/strong> Create the same routes on the new platform. If your custom domain stays the same, users never see a difference.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Format Type 3: Query Parameter Links<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Some platforms pass deep link data as query parameters:<\/p>\n\n\n\n<pre><code>https:\/\/platform.link\/open?link=https:\/\/yourapp.com\/products\/123&amp;apn=com.yourapp.android&amp;isi=123456789\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>link<\/code><\/td>\n<td>The deep link destination<\/td>\n<\/tr>\n<tr>\n<td><code>apn<\/code><\/td>\n<td>Android package name<\/td>\n<\/tr>\n<tr>\n<td><code>isi<\/code><\/td>\n<td>iOS App Store ID<\/td>\n<\/tr>\n<tr>\n<td><code>ibi<\/code><\/td>\n<td>iOS bundle ID<\/td>\n<\/tr>\n<tr>\n<td><code>efr<\/code><\/td>\n<td>Disable interstitial page<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Migration challenge:<\/strong> The parameter names differ between platforms. You need a parameter mapping table.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Format Type 4: Encoded JSON Links<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Some platforms encode link data as a base64 or JSON payload in the URL:<\/p>\n\n\n\n<pre><code>https:\/\/platform.link\/open?data=eyJkZWVwX2xpbmsiOiJwcm9kdWN0cy8xMjMiLCJjYW1wYWlnbiI6InN1bW1lcl9zYWxlIn0=\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Migration challenge:<\/strong> You need to decode the payload to extract link data, then re-encode it in the new platform&#39;s format.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Building a Link Mapping Table<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For each link you need to migrate, create a mapping entry:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">\/\/ Link mapping entry\nconst linkMapping = {\n  oldUrl: &#39;https:\/\/old-platform.link\/AbCd123&#39;,\n  oldFormat: {\n    deepLink: &#39;products\/123&#39;,\n    campaign: &#39;summer_sale&#39;,\n    source: &#39;email&#39;,\n    medium: &#39;newsletter&#39;,\n    fallbackUrl: &#39;https:\/\/yourapp.com\/products\/123&#39;,\n    iosAppStoreId: &#39;123456789&#39;,\n    androidPackage: &#39;com.yourapp.android&#39;,\n  },\n  newUrl: &#39;https:\/\/links.yourapp.com\/products\/123&#39;,\n  newFormat: {\n    route: &#39;\/products\/:id&#39;,\n    params: { id: &#39;123&#39; },\n    campaign: &#39;summer_sale&#39;,\n    source: &#39;email&#39;,\n    medium: &#39;newsletter&#39;,\n    fallbackUrl: &#39;https:\/\/yourapp.com\/products\/123&#39;,\n  },\n};\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Bulk Export from Old Platform<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Most platforms provide an API for bulk link export:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">async function exportAllLinks(oldPlatformApi) {\n  let page = 1;\n  const allLinks = [];\n\n  while (true) {\n    const response = await oldPlatformApi.getLinks({\n      page,\n      limit: 100,\n      orderBy: &#39;clicks&#39;,\n      direction: &#39;desc&#39;,\n    });\n\n    if (response.links.length === 0) break;\n    allLinks.push(...response.links);\n    page++;\n  }\n\n  return allLinks;\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Export links ordered by click count (descending). Migrate the highest-traffic links first.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Route Mapping Patterns<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Direct Path Mapping<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The simplest case: the path structure is identical on both platforms.<\/p>\n\n\n\n<pre><code>Old: https:\/\/links.yourapp.com\/products\/123\nNew: https:\/\/links.yourapp.com\/products\/123\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">No conversion needed. Configure the same routes on the new platform.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Path Transformation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The path structure changes between platforms:<\/p>\n\n\n\n<pre><code>Old: https:\/\/old.link\/open\/products?id=123\nNew: https:\/\/links.yourapp.com\/products\/123\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Create a mapping function:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">function mapPath(oldPath, oldQuery) {\n  \/\/ Old format: \/open\/products?id=123\n  \/\/ New format: \/products\/123\n  if (oldPath.startsWith(&#39;\/open\/&#39;)) {\n    const resource = oldPath.replace(&#39;\/open\/&#39;, &#39;&#39;);\n    const id = oldQuery.id;\n    return `\/${resource}\/${id}`;\n  }\n  return oldPath;\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Wildcard Routes<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If the old platform uses specific link IDs but your new platform uses path-based routes, set up a wildcard redirect:<\/p>\n\n\n\n<pre><code>Old: https:\/\/old.link\/xK3mP \u2192 resolves to products\/123\nOld: https:\/\/old.link\/yN7qR \u2192 resolves to profile\/user456\n\nNew: https:\/\/links.yourapp.com\/products\/:id\nNew: https:\/\/links.yourapp.com\/profile\/:userId\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You cannot set up wildcard redirects for hash-based short links. Each one needs an individual redirect entry or a redirect service that maps old hashes to new URLs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Campaign Parameter Mapping<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Different platforms use different parameter names for the same concepts:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Concept<\/th>\n<th>Platform A<\/th>\n<th>Platform B<\/th>\n<th>Platform C<\/th>\n<th>Tolinku<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>Campaign name<\/td>\n<td><code>campaign<\/code><\/td>\n<td><code>~campaign<\/code><\/td>\n<td><code>c<\/code><\/td>\n<td><code>campaign<\/code><\/td>\n<\/tr>\n<tr>\n<td>Traffic source<\/td>\n<td><code>source<\/code><\/td>\n<td><code>~channel<\/code><\/td>\n<td><code>pid<\/code><\/td>\n<td><code>source<\/code><\/td>\n<\/tr>\n<tr>\n<td>Medium<\/td>\n<td><code>medium<\/code><\/td>\n<td><code>~feature<\/code><\/td>\n<td><code>af_adset<\/code><\/td>\n<td><code>medium<\/code><\/td>\n<\/tr>\n<tr>\n<td>Ad creative<\/td>\n<td><code>ad<\/code><\/td>\n<td><code>~ad_name<\/code><\/td>\n<td><code>af_ad<\/code><\/td>\n<td><code>ad<\/code><\/td>\n<\/tr>\n<tr>\n<td>Custom data 1<\/td>\n<td><code>data<\/code><\/td>\n<td><code>~tags<\/code><\/td>\n<td><code>af_sub1<\/code><\/td>\n<td><code>custom<\/code><\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Conversion Script<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Write a script that converts parameter names:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">function mapCampaignParams(oldParams, platformType) {\n  const mapping = {\n    platformA: {\n      campaign: &#39;campaign&#39;,\n      source: &#39;source&#39;,\n      medium: &#39;medium&#39;,\n    },\n    platformB: {\n      &#39;~campaign&#39;: &#39;campaign&#39;,\n      &#39;~channel&#39;: &#39;source&#39;,\n      &#39;~feature&#39;: &#39;medium&#39;,\n    },\n    platformC: {\n      c: &#39;campaign&#39;,\n      pid: &#39;source&#39;,\n      af_adset: &#39;medium&#39;,\n    },\n  };\n\n  const map = mapping[platformType];\n  const newParams = {};\n\n  for (const [oldKey, value] of Object.entries(oldParams)) {\n    const newKey = map[oldKey] || oldKey;\n    newParams[newKey] = value;\n  }\n\n  return newParams;\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Redirect Strategy for Old Links<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After mapping link formats, you need to redirect old links to their new equivalents.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Individual Redirects<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For high-traffic links, set up individual 301 redirects:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">\/\/ Generate redirect rules from mapping table\nfunction generateRedirects(mappings) {\n  return mappings.map(m =&gt; ({\n    source: new URL(m.oldUrl).pathname,\n    destination: m.newUrl,\n    statusCode: 301,\n  }));\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Pattern-Based Redirects<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If the path structure follows a consistent pattern, use regex-based redirects:<\/p>\n\n\n\n<pre><code class=\"language-nginx\"># Nginx: redirect old format to new format\nrewrite ^\/open\/(.+)\\?id=(.+)$ \/$1\/$2 permanent;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Redirect Service<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For large-scale migrations with thousands of hash-based short links, consider a lightweight redirect service:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">\/\/ Simple redirect service\nimport express from &#39;express&#39;;\n\nconst app = express();\nconst redirectMap = loadRedirectMap(); \/\/ Load from database or JSON\n\napp.get(&#39;\/:hash&#39;, (req, res) =&gt; {\n  const newUrl = redirectMap.get(req.params.hash);\n  if (newUrl) {\n    res.redirect(301, newUrl);\n  } else {\n    \/\/ Fallback: redirect to app homepage\n    res.redirect(302, &#39;https:\/\/yourapp.com&#39;);\n  }\n});\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This service runs on the old domain and redirects to the new platform&#39;s URLs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Validation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After mapping and configuring redirects, validate:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Automated Testing<\/h3>\n\n\n\n<pre><code class=\"language-javascript\">async function validateRedirects(mappings) {\n  const results = [];\n\n  for (const mapping of mappings) {\n    const response = await fetch(mapping.oldUrl, { redirect: &#39;manual&#39; });\n    const location = response.headers.get(&#39;location&#39;);\n\n    results.push({\n      oldUrl: mapping.oldUrl,\n      expectedNewUrl: mapping.newUrl,\n      actualRedirect: location,\n      status: response.status,\n      pass: location === mapping.newUrl &amp;&amp; response.status === 301,\n    });\n  }\n\n  const passed = results.filter(r =&gt; r.pass).length;\n  console.log(`Passed: ${passed}\/${results.length}`);\n\n  const failed = results.filter(r =&gt; !r.pass);\n  if (failed.length &gt; 0) {\n    console.log(&#39;Failed redirects:&#39;);\n    failed.forEach(f =&gt; console.log(`  ${f.oldUrl} \u2192 ${f.actualRedirect} (expected ${f.expectedNewUrl})`));\n  }\n\n  return results;\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Manual Spot-Check<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For the top 20 links by traffic, manually verify:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Click the old link on a mobile device.<\/li>\n<li>Verify it redirects to the new platform.<\/li>\n<li>Verify the app opens to the correct screen.<\/li>\n<li>Verify campaign parameters are preserved in the new platform&#39;s analytics.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Tolinku Link Format<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/tolinku.com\/features\/deep-linking\">Tolinku<\/a> uses path-based routing. Routes are configured in the <a href=\"https:\/\/tolinku.com\/docs\/\">Tolinku dashboard<\/a> with pattern matching:<\/p>\n\n\n\n<pre><code>Route: \/products\/:productId\n  \u2192 iOS: yourapp:\/\/products\/{productId}\n  \u2192 Android: yourapp:\/\/products\/{productId}\n  \u2192 Fallback: https:\/\/yourapp.com\/products\/{productId}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Campaign parameters are passed as query parameters using standard names (<code>campaign<\/code>, <code>source<\/code>, <code>medium<\/code>). For migration from other platforms, see <a href=\"https:\/\/tolinku.com\/blog\/migrating-to-tolinku\/\">migrating to Tolinku<\/a>. For the migration checklist, see <a href=\"https:\/\/tolinku.com\/blog\/deep-linking-migration-checklist\/\">deep linking migration checklist<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Map link formats between deep linking platforms. Understand the structural differences between platform link formats and convert them accurately during migration.<\/p>\n","protected":false},"author":2,"featured_media":1412,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"Link Format Mapping: Converting Links Between Platforms","rank_math_description":"Map link formats between deep linking platforms. Convert deep link structures accurately during migration.","rank_math_focus_keyword":"link format mapping","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-link-format-mapping.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-link-format-mapping.png","footnotes":""},"categories":[17],"tags":[254,20,351,52,69,183,72,352],"class_list":["post-1413","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-comparisons","tag-best-practices","tag-deep-linking","tag-link-format","tag-migration","tag-mobile-development","tag-routing","tag-tutorial","tag-url-structure"],"_links":{"self":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1413","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=1413"}],"version-history":[{"count":4,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1413\/revisions"}],"predecessor-version":[{"id":2596,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1413\/revisions\/2596"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media\/1412"}],"wp:attachment":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media?parent=1413"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/categories?post=1413"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/tags?post=1413"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}