After registration, our app prompts users to invite her friends (aka phone contacts) to use the app too. This allows us to send an email/sms to the useer's contacts with some sort of invitation key. Works fine for a web version app, just embed the key in the url you provide in the invitation.
I'm having trouble figuring out how to make this work smoothly with IOS only. It would be brilliant if I could send the invitee a link to appstore.apple.com/myapp?registrationKey=abcXYZ and have the key magically available to my app once it's installed, but I guess this is a lot to hope for?
The obvious way around this is to make the user manually enter their registration key on first launch, but this seems less reliable and (to my mind) adds friction to the UX.
Has anybody come up with something clever to get around this?
Here is what is flowing through my brain on how to solve this solution, please note, I have not vetted, psudeo-coded, coded, or applied this theory.
Since you will know who is being sent an invitation, save that data to your database with a relationship to the user sending and a unique id to the user being invited (email address if its in the contact's card). When new users sign up scan the database for invitations, if one is found present it to the user asking We're you referred by <existing user>? Once the new user selects their response continue through the registration process, updating the relationship table accordingly and applying any extra settings you need to for the referral.
This combines automatic referral tracking with referral codes for a basic, straight-forward, almost (but not quite) fool proof method to make sure referrals are linked to the right users.
As far as I can tell, the App Store provides an information firewall between an invitation and the installed app.
The closest workaround I've seen is the following:
email link sends you to your website
the website logs reference information in the URL and the IP address
the website instantly redirects you to the App Store (if iOS detected)
user installs the app
user loads the app
app contacts your website, IP addresses matched ... BINGO
Obviously not a secure method though.
There are many failure cases:
business networks commonly share IPs
home and mobile networks release and reuse IPs
The more is frequently used to resolve cases where its good enough to know that the user 'almost-certainly' was referred to download app by the email.
For example, it can be a good mechanism to prompt the user with a "who do you know" question in an app and limit the options based on the (IP+reference) data. If they pick the original poster, then maybe that's good enough, and then you can attach any other data that the inviter provided.
(Full disclosure, currently work at Branch)
The best solution to this is to fingerprint a user. This requires you to do the following steps:
For each user, using your own domain, generate a link for said user. So, right when they complete registration, generate their unique URL, that contains the invitation key.
For anyone clicking this link, they will redirect to Safari first. When they do, capture their IP address and iOS operating system version from the headers and user-agent.
Save this data on your server, and set window.location to your iTunes url.
If the user downloads and consequently opens, inside AppDelegate.m, send a message to your server with the IP address + major/minor/min version you collect upon app launch. If it matches with what you have on the server, you can now pass that invitation key back to the new user.
It's not perfect, and has the ability to misattribute. You could also use branch.io, where all of this is taken care of (link-generation, fingerprinting a user, attribution). Branch also drops a first party cookie and ties it with the device level ID, so attributions are much more accurate.
Related
I want to implement deferred deep linking in my iOS app as a means of tracking referrals. When a user of my app wants to refer a friend, I'll generate a URL that has a unique referral code. When the other person receives the link and opens it, I want it to take them to my app's page in the App Store. Then if they install my app, when it first opens, I need a way for it to read the referral code from the original URL.
I've found may pages about deferred deep linking on the web but none that really explain how to do it. Instead, these pages all end up telling you to install some third-party code or use some commercial service. This isn't what I'm after. I want to learn how to do this myself.
There are lots of old pages out there that recommend convoluted and error-prone solutions, like tracking the user's IP address, putting the referral code into the clipboard, or somehow obtaining it from a cookie in a web view. I don't think these are the correct solutions to be using in 2022.
If anyone can recommend the appropriate resource, I'd appreciate it.
If it is the case that Apple simply doesn't want us to do this and doesn't provide any support for it, then I'd like to know that too. I was under the impression that they did, but maybe I'm wrong.
Thanks,
Frank
Apple's Universal Links allow for this (would understand the difference between the typical URL Scheme and Universal Links as threshold). This assumes you're willing to do some lifting server-side along with other hurdles on the iOS side, largely administrative.
A benefit of Universal Links and the server-side work is that you're provided a fallback webpage if a user does not have the app installed. Since the app should open if downloaded, you could typically just redirect to the app store from this URL. In this case, though, before any redirects, you could execute an operation to decode the unique params passed in the URL and persist it in a remote data store. The data encoded needs to be required and verifiably unique during your registration -- email seems ideal.
If that's feasible, your standard registration flow could require email verification with a link to the app as a mandatory entry point (think slack magic link). When the user submits his/her email to verify, you could first check that email against your data store to see if it maps to any previously decoded referrals saved from the flow above. If so, you could generate a unique link for this email to your app with params that will direct the deferred/deep link.
The good news is, I found a solution. I could construct a web page that redirects the user to the app store, but before doing so, copies some text into their clipboard (without telling them or asking them to do anything). Then later if they install my app I can get the text by pasting from the clipboard. I tested this idea and it works.
The bad news is, starting with iOS 16, Apple now asks you for permission to paste. So if you try to do this, your user will launch your app and immediately get promoted with a message asking them to allow a paste from Safari. I expect most users will deny the request and just the fact that they saw it will erode their trust in the app (I know I wouldn't trust an app that tried consume my clipboard without a direct command from me).
We're trying to implement deferred deep linking in one of our iOS applications to encourage users to invite their friends to use the app, and reward users based on how many installs occur from their referral link. Basically similar to TapStream's product.
Consider this example:
So, UserA shares their link, “ourappURL.com/refer?id=userA”, on any
network they want. UserB clicks that link, which will take them to
Safari and then bounce them to the App Store page where UserB
downloads the app.
When UserB opens the app, the app checks which referral ID they came
in on (if any). In this example, the referral ID would be “userA” as
that’s the ID that was in the referral link. The app then sends this to
our servers and we award UserA with a referral credit.
I'm trying to break this issue down into its core parts. I believe the first part is getting the web page for the user's referral link to save the referral ID to the device somewhere that the app can access it. But I'm not sure this is possible because of the sandboxed nature of iOS.
I know this is fundamentally possible because many ad providers offer the ability to track installations from an ad campaign (see Mobile App Tracking for example).
We have also attempted to do this ourselves and I will try to break down the different steps here.
Going back to your example, you are correct about "remembering" the device identification, and all relevant data "id=userA". You are also correct about "sandboxed nature of iOS" which I presume it means a web page is not allowed to store information outside of the browser app (Safari) and apps (your app) are not able to access information stored by other apps (Safari).
Our solution to this is to store this device to data key-value pair in an environment that is both accessible by the browser as well as by your app, i.e. your backend server.
The next challenge, which remains to be the biggest challenge, is how to uniquely identify this device from the information collectable from the browser? Javascripts in browsers, unlike native apps, don't have access to IDFAs which could be used to uniquely identify a iOS device. To overcome this, one can imagine to use a combination of common information that is available both to the browser app as well to your native app, i.e. OS type, public IP, screen size, etc. etc. Please note, a composite key from these data fields does not guarantee uniqueness (imagine two iPhone 6 visiting this web page via the same router). Therefore, your backend server (assuming you are using it to store this key-value pair), will want to have a strategy on how to handle collisions on keys i.e. the second key deletes the first key, or you allow collision to exist by having a queue of values for a single key. This really depends on how you actual plan to use this technology.
The last step is to form this composite key on your app using the exact same fields you used earlier in the browser to perform a "lookup" on your backend server to retrieve the value previously stored.
Here is a summary of the steps:
User 1 invites User 2 by sending the following link to 2: example.com?inviter=1
User 2 visit Web Page P
P constructs and sends the following key-value pair to your server S iOS|55.55.55.55|750×1334 -> inviter_id=1
User 2 goes to the app store and downloads your App A
User 2 first launches A, A contacts S with the same key (assuming the IP hasn't changed).
S finds the value inviter_id=1 by using this key passed in and, let's say, reward User 1 five points for inviting 2.
Hope this help!
Edit 04/24:
Since Derrick mentioned it in the comments, I figure I would take this chance to finish our story here.
Going back to the beginning of my answer where I mentioned we've attempted to do this ourselves. We had a working prototype based on our current system architecture (which is not in anyway optimized, or meant to be optimized, for storing and analyzing deep link data like this), we ultimately decided not to allocate any additional engineering resource into this project.
Due to the heuristic nature of this matching process, we found this project needing debugging, tuning and optimizing constantly for a diminishing ROI. More importantly, we have found other companies which are more specialized and do a much better job than ourselves.
It has been probably 6 months since we stopped using our internal system and we haven't regretted making such decision.
During this processes, we've worked with a number of vendors, Appsflyer, Adjust, TapStream and we have ultimately ended up with Branch Metrics https://branch.io.
Whether you should DIY or work with another company again depends on your specific objective. We finally decided to stay with Branch, not only because the other vendors charged anywhere from $500 to thousands of dollars per month while Branch is completely free, but also the level of the support they have provided is simply unparalleled.
We've successfully used the clipboard (NSPasteboard) to achieve this: the web page that processes the redirect to the app store does a paste to the mobile device's clipboard before letting the user download the app. Once the app is installed, it uses NSPasteboard on first launch to check for an appropriately coded string. This string can contain the text of interest or, more securely, a token used to fetch interesting data from the backend. In Objective C:
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
NSString *pasteboardString = pasteboard.string;
The clipboard can be cleared once the app is done with it, to avoid repeating the same action.
There is a good solution here: http://blogs.innovationm.com/deferred-deep-linking-in-ios-with-universal-link/
Basic workflow:
User selects domain link on web.
Link sets referral ID to cookie.
User redirected to app store.
On app launch, load referral page in SFSafariViewController.
Referral page checks for cookie and if it exists calls a deeplink into the app with the referral ID.
My answer from HERE
Apple no longer supports Deep Links. It is now called Universal Links and works a bit differently.
Source
Now that Apple no longer supports URI schemes for deep linking, developers must implement Universal Links in order to deep link properly on iOS. If you are already using URI schemes, check out our blog on transitioning to Universal Links.
From: HERE
And HERE is another article on Universal Links and what they are.
Scenario:
I "control" two different apps, App A and App B, both which the user has installed
App A is running
App A needs to obtain a string that was set by App B when App B last ran.
After obtaining the string, App A will still be running
User should not receive any feedback this communication is happening. E.g. no "switching animations" between A or B, no pop-ups, etc.
Constraints:
Apps are released under different vendors
Apps are already in the app store; updated versions will have this communication ability.
It is acceptable for the data stored in App B to be accessible to other apps on the device.
It is not acceptable for the data stored in App B to be visible to general third parties (e.g. if an external server is used, there needs to be some sort of secured scheme)
The data read should be able to occur immediately upon App A being opened after install. For instance, I cannot require the user of App A to enter log in credentials for an external communication service.
Must work on non-jailbroken devices.
This is seeming rather difficult to pull off in iOS7. Help is appreciated.
Tricky work around. Not recommended, but it will get the job done if you can't afford servers.
On the first app create a contact in the user's contacts book. Give it a generic name like "000 - NameOfAppB Data - Don't Delete" (I start with "000" so it goes to the bottom of the users contact book so they never see it, I also add "don't delete" so if the user does somehow find it they don't delete it hahaha) (who looks at contact books anyways). In the contact info under notes add your NSData in string format.
Then when app A is opened search for that contact, read the data, then delete the contact.
Apple does allow you to create and delete users contacts without their permission. (At least in 2011 they did, this may have changed).
This might serve your purpose
https://developer.apple.com/library/ios/documentation/Security/Reference/keychainservices/Reference/reference.html
I am not sure of its limitations though, i have seen implementations where credentials have been shared between apps.
I have an app that is uniquely branded for each customer (think restaurants, etc.) I need to have the user be able to click on a link to my server that contains a unique code, stores that temporarily on the iOS device (cookie, etc.) and then directs them to the app store to download the app. Then when it is downloaded, the app grabs that cookie or temp. data on launch and brands the app for that customer. I know this is possible on Android, but is it on iOS?
Downloading the app first and then selecting the brand (or restaurant) is not feasible in this case, as the url wil be shared with other customers of the same business and we want to create a fluid experience, where they won't be able to "see behind the scenes" and choose a different branding.
Thanks
Edit
Thank you for all the replies. We've reevaluated and are considering having the url be opened on the device and grabbing the IP address or another unique id, and saving that along with the correct brand to a database. The app will then connect to the database on launch, and if the IP's match, will brand accordingly. We're looking for a more reliable identifier than IP, however. Now that UDID is deprecated, are there any other identifiers we can use?
I think the design you propose of a webserver link creating the code that needs to be read by the iOS app later is the issue. You should have a solution that is entirely app based. Perhaps you can have the same services on the website be available as one app which then sets up the code in pasteboard. The user then launches the actual app that looks at the pasteboard and skins itself accordingly.
That being said, data can be shared between apps from the same app seed ID by using UIPasteboard in addition to a few other ways.
I use the pasteboard to share info between apps quickly and easily using this class.
You can use identifierForVendor (UDID replacement) to identify individual devices. Are you planning on harvesting those identifiers prior to the end user "registering" the device at the final location? If not you'll never be able to determine which device belongs where.
What about having the end-user logging into your server as that restaurant? It can be a somewhat generic login per restaurant like "Wendys/Wendys5?" and "McDonalds/McDonalds7!" to determine their App Store URL. As long as the password is easy and non-programmatic to guess it would be unlikely they figure out how to register as a different restaurant. You could also do a simple restaurant selection screen coupled with a password specific to each chain but this would expose the user to which other restaurants are using the app. This way you won't have to continually add IPs if they expand locations and can revoke credentials if the login is compromised.
One question, though: Do all of your clients understand that they'll have to have an AppleID tied to each device? You can only shared a single AppleID across 20 devices.
I'm developing my first iOS app and I'm facing a challenge.
I'd like to present new users a personalized screen when the app starts at the first time. Let me explain more.
The flow should be more or less like this:
My app isn't installed on the user's device.
Then the user gets an SMS on his iPhone with a short message and a link to install my app. The message is part of a conversation. Another user of this app had sent this message (through my backend) in order to join this user to the conversation.
This install URL doesn't necesarrily link directly to the itunes store, it can link to a conversations specific link such as myapp.com/conv/12345
The page at myapp.com/conv/* will detect the device and if it's an iPhone would redirect the user to the appstore to install myapp.
The user then installs myapp and launches it.
Now I'd like to present the same conversation 12345 to the user, before he even needs to login, register or what have you. That's the difficult part... I don't want the user to start an a blank page, I'd like to take it right to the conversation 12345 page.
I assume steps 1-5 are easy, but I can't think of a way to implement 6. I admit that I'm not familiar enough with the intrinsic of the appstore but as far as my understanding goes, "all apps are made equal", I mean the app itself when it gets installed it has no context, it doesn't know what "caused" it to be installed, it isn't aware of the click on myapp.com/conv/12345. Is this correct?
If there was a way for an app to know something like a referrer URL for the instllation or something along these lines that would be awesome.
If there was a way for app to query the device for its phone number
then I could make this work (b/c the SMS was sent to a specific phone
number, so I can track the most recent conversation sent to this
number on my backend). But since apps are sandboxed, accessing the phone
number is off limit.
Well, I suppose I could ask the user to type a unique code from the SMS when the
app starts, say 12345 and then I'd be able to display the
conversation to him. But that's problematic in two ways, first,
security - the user can join a conversation not meant
for him, and second, that's less than optimal
user experience, I want this to work like magic, I don't want to make
users memorize and type strings into my app the first time they
install, I'm sure they won't appreciate it... (they could
copy-paste, but still...)
Another option is asking the user to type his phone number. But that
again has a few drawbacks, one is that again it's less than optimal
UX, I'm asking a user to type his phone number to an app he doesn't
yet know or trust, second I'll need to verify (authenticate) the
phone number, I mean what prevents that user from typing a phone
number that doesn't belong to him?
If I had access to the SMSs then I could dig up that code, but I find
it hard to believe that apps get access to SMSs, it's just sounds
like another reasonable sandbox restriction. Of course I'm not
speaking of jailbroken devices.
BTW, if the user just went over to the appstore to install my app (and didn't go through a conversation SMS) that's fine, in this case I'll just present a normal register/login page. The interesting case is where the user was already part of the conversation when receiving the SMS and now I want him to (effortlessly) become part of the same conversation through my app.
To sum up - is there a trick to present "personalized" pages the first time an app is installed and launched that would get that user right into the context of the conversation sent to him over SMS without having to request additional input?
Thanks!
It's impossible to do. Your application is installed without the knowledge you need whatsoever. As you pointed out, it's a reasonable sandboxing restriction.
What you could do is a challenge-response based system, but it would be about as intrusive to the user as is registering/login in.
Ran, you can keep a flag in NSUserDefaults (equivalent to Android's SharedPreferences)
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html