{"id":1869,"date":"2026-07-28T09:00:00","date_gmt":"2026-07-28T14:00:00","guid":{"rendered":"https:\/\/tolinku.com\/blog\/?p=1869"},"modified":"2026-03-07T03:50:15","modified_gmt":"2026-03-07T08:50:15","slug":"ionic-deep-linking","status":"publish","type":"post","link":"https:\/\/tolinku.com\/blog\/ionic-deep-linking\/","title":{"rendered":"Ionic Deep Linking: Complete Configuration Guide"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Ionic apps can use either Capacitor (recommended) or Cordova as their native runtime. Deep linking configuration differs between the two, but the JavaScript-side URL handling is the same. This guide covers both approaches.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For Capacitor-specific setup, see <a href=\"https:\/\/tolinku.com\/blog\/capacitor-deep-linking\/\">Capacitor deep linking: setup for Ionic apps<\/a>. For the cross-platform overview, see <a href=\"https:\/\/tolinku.com\/blog\/cross-platform-deep-linking-guide\/\">cross-platform deep linking guide for 2026<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Capacitor (Recommended)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Capacitor is the recommended runtime for Ionic apps since Ionic 5+. See the full <a href=\"https:\/\/tolinku.com\/blog\/capacitor-deep-linking\/\">Capacitor deep linking guide<\/a> for detailed setup. The summary:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Add Associated Domains entitlement in Xcode (<code>applinks:yourdomain.com<\/code>).<\/li>\n<li>Add Intent filters in <code>AndroidManifest.xml<\/code>.<\/li>\n<li>Host AASA and assetlinks.json on your domain.<\/li>\n<li>Use <code>@capacitor\/app<\/code> plugin&#39;s <code>appUrlOpen<\/code> event in JavaScript.<\/li>\n<\/ol>\n\n\n\n<pre><code class=\"language-typescript\">import { App } from &#39;@capacitor\/app&#39;;\n\nApp.addListener(&#39;appUrlOpen&#39;, (event) =&gt; {\n  const url = new URL(event.url);\n  this.router.navigateByUrl(url.pathname + url.search);\n});\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Cordova<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If your Ionic app still uses Cordova, use the <code>ionic-plugin-deeplinks<\/code> plugin (or <code>cordova-plugin-deeplinks<\/code>).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Installation<\/h3>\n\n\n\n<pre><code class=\"language-bash\">ionic cordova plugin add ionic-plugin-deeplinks --variable URL_SCHEME=myapp --variable DEEPLINK_SCHEME=https --variable DEEPLINK_HOST=yourdomain.com\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Configuration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The plugin modifies the native configuration automatically:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>iOS:<\/strong> Adds the Associated Domains entitlement.<\/li>\n<li><strong>Android:<\/strong> Adds Intent filters to <code>AndroidManifest.xml<\/code>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">You still need to host AASA and assetlinks.json on your domain.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Handling Deep Links (Cordova)<\/h3>\n\n\n\n<pre><code class=\"language-typescript\">import { Deeplinks } from &#39;@awesome-cordova-plugins\/deeplinks\/ngx&#39;;\n\nconstructor(private deeplinks: Deeplinks) {}\n\ninitializeDeepLinks() {\n  this.deeplinks.route({\n    &#39;\/products\/:productId&#39;: &#39;ProductPage&#39;,\n    &#39;\/offers\/:offerId&#39;: &#39;OfferPage&#39;,\n    &#39;\/referral\/:referrerId&#39;: &#39;ReferralPage&#39;\n  }).subscribe(\n    match =&gt; {\n      console.log(&#39;Deep link match:&#39;, match.$route, match.$args);\n      \/\/ Navigate based on the match\n      this.router.navigate([match.$route], {\n        queryParams: match.$args\n      });\n    },\n    nomatch =&gt; {\n      console.warn(&#39;No deep link match:&#39;, nomatch.$link);\n    }\n  );\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Migration from Cordova to Capacitor<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If migrating from Cordova to Capacitor:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Remove <code>ionic-plugin-deeplinks<\/code>.<\/li>\n<li>Follow the <a href=\"https:\/\/tolinku.com\/blog\/capacitor-deep-linking\/\">Capacitor deep linking setup<\/a>.<\/li>\n<li>Replace the Cordova plugin&#39;s <code>route()<\/code> API with <code>App.addListener(&#39;appUrlOpen&#39;, ...)<\/code>.<\/li>\n<li>The native configuration (entitlements, Intent filters) needs to be set up in the Capacitor project.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Ionic Angular Integration<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Route Configuration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Define routes that match your deep link paths:<\/p>\n\n\n\n<pre><code class=\"language-typescript\">\/\/ app-routing.module.ts\nconst routes: Routes = [\n  { path: &#39;&#39;, component: HomePage },\n  { path: &#39;products\/:productId&#39;, component: ProductPage },\n  { path: &#39;offers\/:offerId&#39;, component: OfferPage },\n  { path: &#39;referral\/:referrerId&#39;, component: ReferralPage },\n  { path: &#39;**&#39;, redirectTo: &#39;&#39; }\n];\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Deep Link Service<\/h3>\n\n\n\n<pre><code class=\"language-typescript\">import { Injectable } from &#39;@angular\/core&#39;;\nimport { Router } from &#39;@angular\/router&#39;;\nimport { Platform } from &#39;@ionic\/angular&#39;;\nimport { App } from &#39;@capacitor\/app&#39;;\n\n@Injectable({ providedIn: &#39;root&#39; })\nexport class DeepLinkService {\n  constructor(\n    private router: Router,\n    private platform: Platform\n  ) {}\n\n  async initialize() {\n    \/\/ Only set up deep links on native platforms\n    if (!this.platform.is(&#39;capacitor&#39;)) return;\n\n    \/\/ Cold start\n    const launchUrl = await App.getLaunchUrl();\n    if (launchUrl?.url) {\n      this.handleUrl(launchUrl.url);\n    }\n\n    \/\/ Warm start\n    App.addListener(&#39;appUrlOpen&#39;, (event) =&gt; {\n      this.handleUrl(event.url);\n    });\n  }\n\n  private handleUrl(urlString: string) {\n    try {\n      const url = new URL(urlString);\n      const path = url.pathname;\n\n      \/\/ Use Angular router to navigate\n      this.router.navigateByUrl(path + url.search).catch(err =&gt; {\n        console.error(&#39;Navigation failed:&#39;, err);\n        this.router.navigate([&#39;\/&#39;]);\n      });\n    } catch (e) {\n      console.error(&#39;Invalid deep link URL:&#39;, urlString);\n    }\n  }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Initialize in App Component<\/h3>\n\n\n\n<pre><code class=\"language-typescript\">\/\/ app.component.ts\nimport { Component, OnInit } from &#39;@angular\/core&#39;;\nimport { DeepLinkService } from &#39;.\/services\/deep-link.service&#39;;\n\n@Component({\n  selector: &#39;app-root&#39;,\n  templateUrl: &#39;app.component.html&#39;\n})\nexport class AppComponent implements OnInit {\n  constructor(private deepLinkService: DeepLinkService) {}\n\n  ngOnInit() {\n    this.deepLinkService.initialize();\n  }\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Ionic React Integration<\/h2>\n\n\n\n<pre><code class=\"language-tsx\">\/\/ App.tsx\nimport { useEffect } from &#39;react&#39;;\nimport { useHistory } from &#39;react-router-dom&#39;;\nimport { App as CapApp } from &#39;@capacitor\/app&#39;;\nimport { isPlatform } from &#39;@ionic\/react&#39;;\n\nconst AppDeepLinks: React.FC = () =&gt; {\n  const history = useHistory();\n\n  useEffect(() =&gt; {\n    if (!isPlatform(&#39;capacitor&#39;)) return;\n\n    \/\/ Cold start\n    CapApp.getLaunchUrl().then(result =&gt; {\n      if (result?.url) {\n        const url = new URL(result.url);\n        history.push(url.pathname + url.search);\n      }\n    });\n\n    \/\/ Warm start\n    const listener = CapApp.addListener(&#39;appUrlOpen&#39;, event =&gt; {\n      const url = new URL(event.url);\n      history.push(url.pathname + url.search);\n    });\n\n    return () =&gt; { listener.then(l =&gt; l.remove()); };\n  }, [history]);\n\n  return null;\n};\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Ionic Vue Integration<\/h2>\n\n\n\n<pre><code class=\"language-typescript\">\/\/ composables\/useDeepLinks.ts\nimport { onMounted, onUnmounted } from &#39;vue&#39;;\nimport { useRouter } from &#39;vue-router&#39;;\nimport { App } from &#39;@capacitor\/app&#39;;\nimport { isPlatform } from &#39;@ionic\/vue&#39;;\n\nexport function useDeepLinks() {\n  const router = useRouter();\n  let listener: any;\n\n  onMounted(async () =&gt; {\n    if (!isPlatform(&#39;capacitor&#39;)) return;\n\n    \/\/ Cold start\n    const launchUrl = await App.getLaunchUrl();\n    if (launchUrl?.url) {\n      const url = new URL(launchUrl.url);\n      router.push(url.pathname + url.search);\n    }\n\n    \/\/ Warm start\n    listener = await App.addListener(&#39;appUrlOpen&#39;, (event) =&gt; {\n      const url = new URL(event.url);\n      router.push(url.pathname + url.search);\n    });\n  });\n\n  onUnmounted(() =&gt; {\n    listener?.remove();\n  });\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Testing<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Browser (Development)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Navigate directly to deep link paths:<\/p>\n\n\n\n<pre><code>http:\/\/localhost:8100\/products\/abc123\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Native (iOS Simulator)<\/h3>\n\n\n\n<pre><code class=\"language-bash\">xcrun simctl openurl booted &quot;https:\/\/yourdomain.com\/products\/abc123&quot;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Native (Android)<\/h3>\n\n\n\n<pre><code class=\"language-bash\">adb shell am start -a android.intent.action.VIEW \\\n  -d &quot;https:\/\/yourdomain.com\/products\/abc123&quot; \\\n  -c android.intent.category.BROWSABLE\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Common Issues<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Issue<\/th>\n<th>Cause<\/th>\n<th>Fix<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>Deep links work on Android but not iOS<\/td>\n<td>AASA file issue or missing entitlement<\/td>\n<td>Check AASA and Associated Domains<\/td>\n<\/tr>\n<tr>\n<td>Route not found after deep link<\/td>\n<td>Angular\/React\/Vue router not matching<\/td>\n<td>Verify route paths match deep link paths<\/td>\n<\/tr>\n<tr>\n<td>Works in browser but not on device<\/td>\n<td>Native configuration missing<\/td>\n<td>Check entitlements (iOS) and Intent filters (Android)<\/td>\n<\/tr>\n<tr>\n<td>Cold start shows home then navigates<\/td>\n<td>Navigation timing issue<\/td>\n<td>Handle launch URL before initial render<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Tolinku for Ionic Apps<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/tolinku.com\/features\/deep-linking\">Tolinku<\/a> provides AASA and assetlinks.json hosting, removing the need to manage verification files. The <a href=\"https:\/\/tolinku.com\/docs\/developer\/sdks\/web\/\">Tolinku web SDK<\/a> works with Ionic apps for smart banners.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For React Native deep linking, see <a href=\"https:\/\/tolinku.com\/blog\/react-native-deep-linking-setup\/\">React Native deep linking: complete setup tutorial<\/a>. For the full guide, see <a href=\"https:\/\/tolinku.com\/blog\/cross-platform-deep-linking-guide\/\">cross-platform deep linking guide for 2026<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Configure deep linking in Ionic framework apps. Handle both Cordova and Capacitor plugins for Universal Links and App Links support.<\/p>\n","protected":false},"author":2,"featured_media":1868,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"Ionic Deep Linking: Complete Configuration Guide","rank_math_description":"Configure deep linking in Ionic framework apps. Handle both Cordova and Capacitor plugins for Universal Links and App Links support.","rank_math_focus_keyword":"Ionic deep linking","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-ionic-deep-linking.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-ionic-deep-linking.png","footnotes":""},"categories":[15],"tags":[23,187,564,156,20,563,69,22],"class_list":["post-1869","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engineering","tag-app-links","tag-capacitor","tag-cordova","tag-cross-platform","tag-deep-linking","tag-ionic","tag-mobile-development","tag-universal-links"],"_links":{"self":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1869","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=1869"}],"version-history":[{"count":1,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1869\/revisions"}],"predecessor-version":[{"id":1870,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1869\/revisions\/1870"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media\/1868"}],"wp:attachment":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media?parent=1869"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/categories?post=1869"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/tags?post=1869"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}