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.
For Capacitor-specific setup, see Capacitor deep linking: setup for Ionic apps. For the cross-platform overview, see cross-platform deep linking guide for 2026.
Capacitor (Recommended)
Capacitor is the recommended runtime for Ionic apps since Ionic 5+. See the full Capacitor deep linking guide for detailed setup. The summary:
- Add Associated Domains entitlement in Xcode (
applinks:yourdomain.com). - Add Intent filters in
AndroidManifest.xml. - Host AASA and assetlinks.json on your domain.
- Use
@capacitor/appplugin'sappUrlOpenevent in JavaScript.
import { App } from '@capacitor/app';
App.addListener('appUrlOpen', (event) => {
const url = new URL(event.url);
this.router.navigateByUrl(url.pathname + url.search);
});
Cordova
If your Ionic app still uses Cordova, use the ionic-plugin-deeplinks plugin (or cordova-plugin-deeplinks).
Installation
ionic cordova plugin add ionic-plugin-deeplinks --variable URL_SCHEME=myapp --variable DEEPLINK_SCHEME=https --variable DEEPLINK_HOST=yourdomain.com
Configuration
The plugin modifies the native configuration automatically:
- iOS: Adds the Associated Domains entitlement.
- Android: Adds Intent filters to
AndroidManifest.xml.
You still need to host AASA and assetlinks.json on your domain.
Handling Deep Links (Cordova)
import { Deeplinks } from '@awesome-cordova-plugins/deeplinks/ngx';
constructor(private deeplinks: Deeplinks) {}
initializeDeepLinks() {
this.deeplinks.route({
'/products/:productId': 'ProductPage',
'/offers/:offerId': 'OfferPage',
'/referral/:referrerId': 'ReferralPage'
}).subscribe(
match => {
console.log('Deep link match:', match.$route, match.$args);
// Navigate based on the match
this.router.navigate([match.$route], {
queryParams: match.$args
});
},
nomatch => {
console.warn('No deep link match:', nomatch.$link);
}
);
}
Migration from Cordova to Capacitor
If migrating from Cordova to Capacitor:
- Remove
ionic-plugin-deeplinks. - Follow the Capacitor deep linking setup.
- Replace the Cordova plugin's
route()API withApp.addListener('appUrlOpen', ...). - The native configuration (entitlements, Intent filters) needs to be set up in the Capacitor project.
Ionic Angular Integration
Route Configuration
Define routes that match your deep link paths:
// app-routing.module.ts
const routes: Routes = [
{ path: '', component: HomePage },
{ path: 'products/:productId', component: ProductPage },
{ path: 'offers/:offerId', component: OfferPage },
{ path: 'referral/:referrerId', component: ReferralPage },
{ path: '**', redirectTo: '' }
];
Deep Link Service
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Platform } from '@ionic/angular';
import { App } from '@capacitor/app';
@Injectable({ providedIn: 'root' })
export class DeepLinkService {
constructor(
private router: Router,
private platform: Platform
) {}
async initialize() {
// Only set up deep links on native platforms
if (!this.platform.is('capacitor')) return;
// Cold start
const launchUrl = await App.getLaunchUrl();
if (launchUrl?.url) {
this.handleUrl(launchUrl.url);
}
// Warm start
App.addListener('appUrlOpen', (event) => {
this.handleUrl(event.url);
});
}
private handleUrl(urlString: string) {
try {
const url = new URL(urlString);
const path = url.pathname;
// Use Angular router to navigate
this.router.navigateByUrl(path + url.search).catch(err => {
console.error('Navigation failed:', err);
this.router.navigate(['/']);
});
} catch (e) {
console.error('Invalid deep link URL:', urlString);
}
}
}
Initialize in App Component
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { DeepLinkService } from './services/deep-link.service';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit {
constructor(private deepLinkService: DeepLinkService) {}
ngOnInit() {
this.deepLinkService.initialize();
}
}
Ionic React Integration
// App.tsx
import { useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { App as CapApp } from '@capacitor/app';
import { isPlatform } from '@ionic/react';
const AppDeepLinks: React.FC = () => {
const history = useHistory();
useEffect(() => {
if (!isPlatform('capacitor')) return;
// Cold start
CapApp.getLaunchUrl().then(result => {
if (result?.url) {
const url = new URL(result.url);
history.push(url.pathname + url.search);
}
});
// Warm start
const listener = CapApp.addListener('appUrlOpen', event => {
const url = new URL(event.url);
history.push(url.pathname + url.search);
});
return () => { listener.then(l => l.remove()); };
}, [history]);
return null;
};
Ionic Vue Integration
// composables/useDeepLinks.ts
import { onMounted, onUnmounted } from 'vue';
import { useRouter } from 'vue-router';
import { App } from '@capacitor/app';
import { isPlatform } from '@ionic/vue';
export function useDeepLinks() {
const router = useRouter();
let listener: any;
onMounted(async () => {
if (!isPlatform('capacitor')) return;
// Cold start
const launchUrl = await App.getLaunchUrl();
if (launchUrl?.url) {
const url = new URL(launchUrl.url);
router.push(url.pathname + url.search);
}
// Warm start
listener = await App.addListener('appUrlOpen', (event) => {
const url = new URL(event.url);
router.push(url.pathname + url.search);
});
});
onUnmounted(() => {
listener?.remove();
});
}
Testing
Browser (Development)
Navigate directly to deep link paths:
http://localhost:8100/products/abc123
Native (iOS Simulator)
xcrun simctl openurl booted "https://yourdomain.com/products/abc123"
Native (Android)
adb shell am start -a android.intent.action.VIEW \
-d "https://yourdomain.com/products/abc123" \
-c android.intent.category.BROWSABLE
Common Issues
| Issue | Cause | Fix |
|---|---|---|
| Deep links work on Android but not iOS | AASA file issue or missing entitlement | Check AASA and Associated Domains |
| Route not found after deep link | Angular/React/Vue router not matching | Verify route paths match deep link paths |
| Works in browser but not on device | Native configuration missing | Check entitlements (iOS) and Intent filters (Android) |
| Cold start shows home then navigates | Navigation timing issue | Handle launch URL before initial render |
Tolinku for Ionic Apps
Tolinku provides AASA and assetlinks.json hosting, removing the need to manage verification files. The Tolinku web SDK works with Ionic apps for smart banners.
For React Native deep linking, see React Native deep linking: complete setup tutorial. For the full guide, see cross-platform deep linking guide for 2026.
Get deep linking tips in your inbox
One email per week. No spam.