Kroo is introducing a referral scheme to reward customers who successfully invite their friends to join Kroo. The reward will be in the form of trees planted on behalf of the referrer and the referred, so that you win, they win, we win, and our planet wins. You can read more about why we are planting trees in this blog post.
This is the story of how we implemented the referral links, why we did it this way (using shallow links), and a brief overview and explanation of the alternative, which is to use deep links. You can see the final product here, which happens to be a referral link with my token, so you are more than welcome to use this link to sign up to Kroo 😀.
To assign credit for customer acquisition we need a way of knowing who referred the user who is registering an account. The way this would likely work on the Web is that you would have a link to the registration page with a parameter containing a token that is associated with a referrer. When a user registers on such a page we can use the token to get the referrer of this customer, and that’s all we need to credit the referrer.
The problem is that we currently only support registration within our app (and replicating that process on the Web is not trivial), so how can we use links to send information into an app?
It is possible to create regular web links that will open up an app to a specific place (social networks like to use this to direct you from the web seamlessly to the same page in the app). The way this works differs slightly between platforms and is described in more detail for iOS here and for Android here. (There’s also an older method using custom URL schemes for app links).
The pattern is essentially the same in both, though. The app registers itself as being able to handle URLs from a domain (or URLs with a custom scheme) using its config files. The domain also needs to have a file at a well known location that specifies which paths on the domain should be handled by the app. This prevents apps that do not own the domain from registering themselves as handlers without permission of the domain owner.
When a user who has the app installed clicks on such a link, the device will open the app instead of loading the web page, and it will provide the app with the original link used, so that it can take the user to the correct view within the app.
There are edge cases where deep linking might not work. More importantly, it only works if the user has the app installed. Since we are primarily interested in using referrals for users who do not yet have the app, we need a way to persist deep links all the way through app download and installation. Unfortunately there’s no native support for this, but there are ways to work around it.
Deferred Deep Linking
There are a number of third parties that provide this as a service, such as Adjust, Branch, and Firebase — and you will likely want to use a third party for it because it gets complicated in practice, (more on that below). The basic idea is to track the user from clicking the link all the way into the app. Following is a schematic diagram and simplified description of the process.
Whichever service you use, these would likely be the approximate steps involved in a referral process using deferred deep links:
- A user (the referrer) creates a deep link using the app. The app constructs this link using the third party SDK, its API service, or internally by following the pattern used by the third party. The user can share this link with other people.
- Another user (the referred) clicks on the link, which is actually a link to a service hosted by the third party.
- The third party records a fingerprint (or sets a cookie) to track this user along with the URL that was used in the link, and redirects the user to the relevant app store.
- When the user installs and opens the app, the app sends a request to the third party, which uses the device fingerprint (or cookie) to find the original link used by the user, and shares that with the app. The app can then get the referral information out of the link.
The problem with this simplified scheme is that it only makes sense if the user does not have the app installed, since we are always redirecting to the app store, but what is generally needed is some kind of hybrid link.
In practice we usually want links to work as deferred deep links if the app is not installed, and as regular deep links when the app is installed (and as web links if the user is not on a supported mobile). We also need to be able to deal with the various quirks of the mobile operating systems and how they handle deep links in different situations.
A good overview of some possible permutations is illustrated by the following flowchart. (Firebase provides you with a personalised version of this so you can check which links each path points to).
There are a number of tricks that can be used to make the links work in the many different scenarios; The original link can redirect users to different URLs based on the User-Agent of the request. The URL to which they are redirected can itself a deep link that also contains a redirect to the app store, which will only be triggered if the deep link was not handled by an app. For some cases you may need the deep link page to have a button linking to a deep link on another domain. You can read more about edge cases and workarounds in this article on deep linking.
However, most of the complexity involved in making it work could, in theory, be abstracted away by a third party that specialises in deep linking and provides a service that makes it all work seamlessly by hosting the links on your behalf.
The Problems with Deep Linking
When we actually tried using some of the third party libraries, they were painful to install and difficult to test. Some of them worked partially but not in all cases, and we found out that the tricks they use to track users are not 100% accurate.
Advertisers (and by extension deep link providers that rely on tracking) are in a constant battle with Apple, as the advertisers try to work around the restrictions that Apple adds to protect user privacy. We felt that although the methods used for tracking might work currently for most users, they are fragile and likely to break in the future. When they do break it might take us a while to find out, after many customers have been referred without attribution, and it would then be resource-consuming to fix it.
When our tests were not working correctly it was difficult to debug why, since much of the logic resides with a third party and often involves subtle hacks. They also sometimes seemed to be intentionally vague about how their landing pages work to avoid revealing their “secret sauce” workarounds, which made it harder to figure out why it was broken.
There are also situations when it will obviously not work, for example if a user clicks on the link, but then downloads the app on a different device.
Then there’s the ethical, possibly legal, issue of us tracking potential customers without them having agreed to be tracked by us and sharing that information with a third party, and it’s all for nothing because in principle we don’t really need to track users for the sake of referrals
The act of claiming a referral involves a user bringing a token (usually automatically as a parameter) that says something about who referred them, but we don’t need to know anything else about where they have been before or what device they used to get there. The only reason we needed tracking was as a hack to carry that information through to app installation, and perhaps we don’t actually need to do that.
We opted to keep it simple and ditch the tracking, the deep linking, and the third parties, and use shallow linking instead.
A shallow link is just a regular web link, that takes the user to a classic web page with a form. It is guaranteed to work 100% of the time on every device that has a functioning web browser, and it is very easy to develop and test.
These are the steps involved in a shallow link referral:
- A user (the referrer) creates a regular link using the app. The link contains a token that is unique to the referrer. The referrer can share this link with other people.
- Another user (the referred) clicks on the link, which points to a web page with a form to claim the reward. The user is prompted to enter their email address, the same one they will use to sign up for an account.
- When the form is successfully submitted, the user is redirected to the relevant app store (based on the User-Agent header).
- Once the user has completed registration, we issue an award if the user has made a claim using the web form.
One disadvantage of this scheme is that the user has to enter their email address twice, once in the referral claim form and once during account registration. This makes it possible for a user to accidentally provide two different email addresses, which will result in the referral not being linked correctly. This can be mitigated by expanding the web form to actually begin part of the onboarding process.
After we decided to go down this route, we saw that Monzo and Starling also use a similar approach for their referral schemes, probably for the same reasons.
As we were putting the finishing touches on our shallow link referral system and getting ready to launch, we heard that Apple rejected all apps that were using the SDK from one of the third parties. The ban was lifted after they made changes to remove some device tracking. This didn’t affect our referral scheme at all. We didn’t have to run any tests to see if our referrals still work, and we didn’t have to implement any fixes, because our referral scheme does not rely on tracking or deep links.
Deferred deep linking has its uses, for example to take users to a particular page in an app with many pages like Reddit. However, there’s no need to go overboard and use deep linking if all we need is attribution for referrals.