Like pay-to-play or in-app ads, prompting for a rating is controversial in that some developers frown upon it. Free apps tend to have an average 3 star rating. People rarely bother to go back to the App Store to rate an app. There’s always a small minority that will go out of their way to provide negative reviews. So why not solicit positive feedback by providing a reminder to rate the game? In my opinion, there’s nothing overtly annoying or obnoxious about presenting an alert view that can easily be dismissed.

I rolled my own code to prompt users for a review and the results have been excellent. We’re now getting mostly 4 and 5 star ratings in the prompt-enabled apps. The key of course is in the timing of the prompts. I’ll explain a little about how the code works, then discuss the results so far. For a far better complete code template and explanation see also Noel Llopis’s blog post from last year.

Since the stated objective is to get positive feedback without annoying the user, we want to filter out people who have just launched the app for the first time. One way to do this would be to use a timer, maybe wait until some period of time has elapsed. That’s probably OK, but could lead to a prompt coming up at a truly random time. Instead I have code that checks for two things: time elapsed plus a new high score achieved. To detect a desired length of time, use something like this in your -[UIApplicationDelegate application:didFinishLaunchingWithOptions:] method:

if (![defaults objectForKey:kFirstRunKey]) {
    [defaults setObject:[NSDate date] forKey:kFirstRunKey];
}

This gives you the timestamp of the first run time. I typically define kFirstRunKey to include a unique version number, so I can record the first run of each update. Now each time a new high score (use whatever criteria you see fit) is achieved, check the current time against the first run timestamp, like this:

- (void) askToRateApp {
 if ( ![self reachable] )
   return;
 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
 if ( [defaults boolForKey:kAlreadyDeclinedToRateKey] )
   return;
 NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:[defaults objectForKey:kFirstRunKey]];
 if (elapsed < kAskDelaySeconds ) // approximately 1 day
   return;

Notice a couple of interesting things here. First, I have a Reachability test to exit early if there’s no connection. Second, if the user has previously declined to rate the app, respect that choice and do nothing. Finally, there is a test to see if enough time has elapsed. If not, again do nothing. At this point you could prompt the user, or optionally add more tests. Maybe you only want to prompt on the 17th high score. Then something like this would work:

 NSInteger showAsk = [defaults integerForKey:kShowAskToRateKey];
 // If showAsk is 0, the prompt screen will be shown.
 // If showAsk is > 0, we decrement it now.
 if ( showAsk == 0 ) {
   feedbackAlert = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"AskToRateApp",@"") message:nil delegate:self cancelButtonTitle:NSLocalizedString(@"NoThanks",@"") otherButtonTitles:NSLocalizedString(@"RateNow",@""), NSLocalizedString(@"RemindLater",@""), nil] autorelease];
   [feedbackAlert show];
 } else {
   showAsk = (showAsk - 1) ;
   [defaults setInteger:showAsk forKey:kShowAskToRateKey];
 }
}

In this example, the showAsk variable is tested to see if the counter is zero. If it is, we show the feedback alert. Otherwise we decrement it and store it back in the default settings for next time. Set a reasonable initial value for kShowAskToRateKey. Once the saved value reaches zero, the alert will be shown exactly once. All that’s left to do is handle the buttons on the feedback alert.

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
  if ( alertView == feedbackAlert ) {
    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
    if ( buttonIndex == 0 ) {
      // No Thanks
      // Don't Ask Anymore
      [defaults setBool:YES forKey:kAlreadyDeclinedToRateKey];
    } else if ( buttonIndex == 1 ){
      // Rate Now...
      // and Don't Ask Anymore
      [defaults setBool:YES forKey:kAlreadyDeclinedToRateKey];
      [self showAppStoreReviewPage];
    } else if ( buttonIndex == 2 ) {
      // Remind Me Later
      [defaults setInteger:21 forKey:kShowAskToRateKey];
    }
    feedbackAlert = nil;
  }
}

For the “remind later” choice here, I’m resetting the kShowAskToRateKey to 21, but this can be any value you like. I recommend you use analytics or some other method to determine an appropriate measure of how much time is “later.” FInally you need a small piece of code to make the App Store review page show. This technique can be used on iPhone, iPod touch, iPad, and Mac, but on iPad and Mac it is not possible to go directly to the review page. You’ll go instead to the App description and may want to explain how to actually enter a rating or review in those cases.

- (void) showAppStoreReviewPage {
  [[UIApplication sharedApplication] openURL:[NSURL URLWithString:deepLinkReview]];
}

For the deepLinkReview you will specify the URL that takes users to the application’s review page on iTunes. It’s pretty straightforward to construct the URL manually. Justine Pratt wrote all about this on her blog last year. You can also wrap the URL in a LinkShare link if you are an iTunes affiliate.

So how well does it work? Like Noel I have see an improvement in reMovem ratings from 3.5 stars to 4.5 stars, with about twice as many written reviews per day as there were a year ago. Still, 2 out of 3 users choose not to leave reviews. Of the rest, half opt for the “remind later” choice while about 15% click the “rate now” button. I suspect only a percentage of those actually complete the process, but it’s better than none. It’s debatable whether this leads to more sales, but having more 4 and 5 star reviews certainly helps when people are looking at the App Store description. I also believe they use the number of reviews as a gauge to an app’s popularity, and, in turn, as a data point for their purchasing decision. So the more reviews, the better.

NewImage

—-

This post is part of iDevBlogADay, a group of indie iOS development blogs featuring two new posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, or Twitter.