dbader.org

Guessing a user’s favorite contacts on iOS

Many iOS applications contain an “invite your friends” feature. Ideally this feature should suggest people that the user is likely to invite. This article explains an App Store-legal method of guessing a user’s favorite contacts from their address book on iOS. The method is described in detail and a demo application is available for download.

Demo application screenshot

The problem

From a usability perspective it can be useful for an iOS application to know a user’s favorite contacts. For example, if your application contains an “invite your friends” feature you’ll want it to suggest contacts that the user is likely to invite, such as close friends and family members.

Some mobile platforms, such as Google Android, allow applications to access a user’s call or messaging history. From this information it is quite simple to infer a list of contacts that are important to the user. We could, for example, use communication recency as a scoring function to determine the most-frequently contacted address book contacts.

On iOS, applications cannot access call or messaging histories. Neither are applications allowed to access the favorite contacts listed in Phone.app or Mail.app’s VIP list. While this protects users’ privacy, it makes it difficult for developers to determine their users’ most important contacts.

The solution

To solve this problem I developed a score-based heuristic that guesses a user’s most important contacts. The heuristic uses only information from the address book that is accessible to iOS applications. Therefore it is legal to use on the App Store.

The heuristic is based on the following assumption:

People know more about people that are important to them.

Or in other words:

The more information an address book contact contains about a person, the more important that person is to the owner of the address book.

Based on this idea we define a scoring function that returns the importance score of an iOS address book contact as a numeric value. The scoring function gives score depending on the types of the available contact information. For example, a phone number gives more score than a Twitter handle. You can see an outline of the scoring function here:

+ (NSInteger) importanceScoreForContact:(ABRecordRef) contact {
  NSInteger score = 0;

  // 1. Award score for single-value ABPropertyIDs, e.g.
  //       kABPersonNicknameProperty,
  //       kABPersonBirthdayProperty, etc.

  // 2. Award score for each element within multi-value
  //    ABPropertyIDs, e.g.
  //       kABPersonRelatedNamesProperty,
  //       kABPersonPhoneProperty, etc.

  // 3. Award score for contacts that have an associated image.

  // 4. Penalize contacts that belong to companies instead
  //    of real persons by decreasing their score.

  return score;
}

In the full implementation available on GitHub the amount of score awarded for each ABPropertyID is data-driven by two NSArrays that function as score tables. This lets us easily tweak the heuristic’s behavior by modifying the score tables.

Using the importanceScoreForContact: scoring function we can now compile a list of the most important contacts in an iOS address book. We do this by selecting the contacts with the highest importance scores:

+ (NSArray*) mostImportantContacts {

  // For each person in the address book:
  //
  //     1. Compute an importance score for the person.
  //
  //     2. Store a reference to the person and
  //        their importance score.

  // Return the n highest-ranking results based
  // on their score values.

}

This gives us a sorted list of contacts that are likely to be important to the owner of the address book. We could now use this list of a user’s most important contacts for an “invite your friends” feature in our application.

The resulting list of friend suggestions only contains, let’s say, ten items. This feels more manageable to the user than letting them pick invitees from their entire address book. Therefore the user is more likely to send these invitations. Consequently, I believe that using a method like this improves the usability of your app’s sharing or “invite your friends” features.

Performance

On my phone the guessed list of most important contacts is quite close to my actual favorite contacts. Of course the heuristic we’re using here is likely biased towards the contents of my own address book. Your mileage may vary, but I am very interested in hearing what results you get.

Syncing services are also going to affect the accuracy of this approach. I’ve tried to lessen the effects of Facebook and Twitter syncs though. The score tables in the actual implementation only give little score for information like first and last names. Other information such as nicknames, related persons (kABPersonRelatedNamesProperty), or anniversary dates are weighted much stronger. To my knowledge, this information is never added by Facebook’s or Twitter’s syncing. Related names, for example, are often only added via Siri.

Computing importance scores for 236 contacts in my address book takes about 800 ms on an iPhone 4. The complexity of the algorithm is O(n) where n is the number of contacts in the address book. For real world applications you should probably run this on a background thread.

Download the code

An implementation of the heuristic and an example iOS application are available under the MIT license on GitHub. The interesting parts can be found in DBFriendInviter.h and DBFriendInviter.m.

Using the heuristic in your own applications is quite simple. Calling [DBFriendInviter mostImportantContacts] gives you a list of ABRecordIDs of the ten most important contacts in a user’s address book. Check out the included demo application for a simple example.

Possible improvements

Three improvements come to my mind that may help increase the heuristic’s accuracy:

  • We could tweak the score values for each ABPropertyID so that the importance scores become more accurate.
  • We could rank people higher that have the same (or a similar) last name as the user. This requires us to know more information about the user. But this is quite likely if they signed up for our service, for example.
  • We could somehow take the creation or the last-modified timestamps into account. Older contacts may be more important than younger ones, for example.

I’d love to hear what you think of this method or if you have more ideas on how to improve it.