Deep linking in Ionic and how to handle custom URLs

Hey all,

I’d noticed there’s been a few posts about deep linking and handling custom URLs with the handleOpenURL function recently. We’ve been cleaning up some code in this area so I thought I’d share some insight into how we handle it.

I’ve written up a small post on medium. Hope it helps someone.



I was just about to tackle doing this in my app, thanks!

Hi Jamie,

This is a really nice article - it’s a cleaner way of doing it than the other versions I’ve seen here, and it’s very clearly explained. However, I’m having one issue with it:

  • if the app’s not running when I link into it, everything is fine
  • if the app’s already running, the first deep link into it works fine. On subsequent links, though, I can see that the global openURL function gets called, but the OpenUrlService doesn’t pick it up the event so I don’t end up at the correct state.

I’m using ionic beta 14 and Cordova-ios 3.8.0. Am I doing something stupid somewhere in this? Is there something I don’t understand about Cordova’s event model?

Any advice or help would be much appreciated!


1 Like

Ahhh we might need to add something to reset the trigger if it’s fired. Let me have a look into it.

Have you found any solution for this?


Hey @chris08002 So I finally got some time to go back to this and I’ve fixed it I think. You need to remove the sticky handler and reapply it again once you’ve opened the URL.

(function (window, document, angular) { 'use strict';

  angular.module('mlz.openurl', ['ionic'])
  .factory('OpenUrlService', ['$log', '$location', '$rootScope', '$ionicHistory', function ($log, $location, $rootScope, $ionicHistory) {

    var openUrl = function (url) {

      //window.alert('Opening URL ' + url);

      // Stop it from caching the first view as one to return when the app opens
        historyRoot: true,
        disableBack: true,
        disableAnimation: true

      if (url) {
        window.location.hash = url.substr(5);
        $rootScope.$broadcast('handleopenurl', url);

        document.removeEventListener('handleopenurl', handleOpenUrl);


    var handleOpenUrl = function (e) {
      // Check for the CustomEvent detail field for testing.
      // Difficult to trigger cordova events under test
      var url = e.url || e.detail.url;

    var onResume = function () {
      //window.alert('On resume handle url');
      document.addEventListener('handleopenurl', handleOpenUrl, false);

    return {
      handleOpenUrl: handleOpenUrl,
      onResume: onResume

  }]).run(['OpenUrlService', function (OpenUrlService) {
    if (OpenUrlService) {
      document.addEventListener('handleopenurl', OpenUrlService.handleOpenUrl, false);
      document.addEventListener('resume', OpenUrlService.onResume, false);


})(window, document, angular);

Is there a way to install the app by taking them to the appropriate location in Google Play or Apple App Store. Then proceed with the deep link?

I can’t find any information that would suggest this is possible. Unless you could figure out a way to take them to the store, install the app, then launch the app from your site again.

The problem is the app doesn’t launch from install and the app store doesn’t save the deep link when you direct people to the install page to pass on when you hit the open button.

I found an interesting article related to deferred deep linking. Im not sure if this company has a solution for this or not. I suspect they offer a “click” server.

Thanks for this solution! It seems to work stable for us. I am now also looking into campaign referrals from the app stores.

1 Like has a free service that provides among other things (deferred deep linking and deep linking). They also have a Cordova plugin. I am in the early stages of looking into this. I will post more information in case someone else is interested.

1 Like

I’ve been experimenting the last couple of days with Branch.Io. Looks like I got it to work now. I had some problems with the right sequence of initSession, closeSession, setIdentity… e.g. on a forced app close (android back button or task manager) the closeSession was not called and eventually params didn’t get caught at next start. Let me know if you want to share info on this one.

That would be great. Can you post some code on a gist perhaps?

Never done that, but I have given it a try :smile:

Let me know if it is understandable

1 Like

Im getting this error:

handleOpenURL is not defined

when I click on a custom URL.

Never mind, I realized I needed to define it properly (I had a typo).

Can you explain why we set window.location.hash ? Also wondering if we broadcast the event in the root scope, what handles that? What actually makes the state change? Im still trying to understand and get this working in my app (my app launches but doesn’t actually transition anywhere). Also noticed that the global handleOpenURL handler fires a handleurl event but the events in the service are all called handleopenurl ?

We are looking at this…it seems seems good (and is free for now)…can you post the code in detail. For now, when I click the link, nothing happens…

Thank you in advance…

Hey team - I built a lot of the Branch service. Happy to help where I can. The repo that @keithdmoore linked to is outdated. Here are the docs for the new, fully native SDK we built.

@chris08002 - did you figure out the issue with the session closing? We should fix the docs or otherwise if it’s incorrect.

I think I had issues with using the angular $window service which was the reason for using straight window. It’s been a while so it was probably something I was doing wrong and I never switched them back. You’re free to use whatever view switching method. Hash was just a quick way. You could use $state.go or whatever.

We broadcast on the rootScope so the app can listen for the event and hook into it. It’s not responsible for actually switching views and does nothing in the context of this example.

Good catch on the typo. I’ve updated the gist.