Better iOS ratings and reviews using SKStoreReviewController

The iOS app store has millions of apps for each category and as a developer, it is hard to stand out even if you provide great functionalities. Positive ratings and reviews are the major factors that impact the discoverability of your app in the app store. Apple provides a great way to collect positive (or negative) feedback directly from your users right inside the app using iOS rating and review prompt. Let’s see how.

Apple has provided an easy way to request ratings and reviews from your audience. This StoreKit API called SKStoreReviewController has a static function called requestReview() that will display an iOS rating and review prompt to collect the feedback. Here’s how we trigger it:

import StoreKit

@available(iOS 10.3, *)
class RatingManager {

    static func displayRatingPrompt() {
        SKStoreReviewController.requestReview()
    }
    
}

This API works only on iOS 10.3 and above. For iOS versions prior to this, please see the manually requesting a review section. Also, be sure to check out the best practices for displaying iOS rating and review prompt.

Review prompt will still display even in development mode or builds that are distributed through TestFlight for testing purposes, but will not affect the App Store rating or reviews.

Using UserDefaults to control the frequency of iOS rating and review prompt

You also need to be aware that this modal will only get presented to a maximum of 3 times in a year (or 365 days period). So deciding when and where the modal should appear should be chosen carefully. Here are some utility functions to be added to your RatingManager class to help us with it:

private static let promptDisplayLimitPerVersion = 3
private static let promptCounterKey = "RatingReviewPromptDisplayCounter"
private static let promptLastDisplayedVersionKey = "RatingReviewPromptLastDisplayedKey"

/// returns current app version in string format
private static func currentAppVersion() -> String {
    let currentVersion = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String
    return currentVersion ?? ""
}

/// every time rating prompt is shown to the user, it will be persisted in user defaults
/// this function returns the app version in which rating prompt is last shown to the user.
private static func lastRatingPromptDisplayedAppVersion() -> String {
    let lastDisplayedVersion = UserDefaults.standard.string(forKey: promptLastDisplayedVersionKey)
    return lastDisplayedVersion ?? ""
}

/// set current version of the app as the last version
/// on which rating prompt was displayed
private static func setCurrentAsPromptDisplayedVersion() {
    UserDefaults.standard.set(currentAppVersion(), forKey: promptLastDisplayedVersionKey)
}

/// returns an integer that represents how many times rating prompt
/// is displayed to the user in the current version of the app
private static func displayCount() -> Int {
    return UserDefaults.standard.integer(forKey: promptCounterKey)
}

/// when a rating is prompted to the user, increment the counter
private static func incrementDisplayCount() {
    var count = displayCount()
    count += 1
    UserDefaults.standard.set(count, forKey: promptCounterKey)
}

/// reset the app display counter
private static func resetDisplayCount() {
    UserDefaults.standard.set(0, forKey: promptCounterKey)
}

and now changing the rating prompt initialization like this:

import StoreKit

@available(iOS 10.3, *)
class RatingManager {
    
    static func requestReviewIfNeeded() {
        let appVersionDidChange = currentAppVersion() == lastRatingPromptDisplayedAppVersion()
        let displayCountDidReachLimit = displayCount() >= promptDisplayLimitPerVersion
        
        if appVersionDidChange {
            // the app version has changed since the previous prompt is shown to the user
            // so it is safe to display the prompt `promptDisplayLimitPerVersion` times.
            resetDisplayCount()
        }
        
        if !displayCountDidReachLimit {
            displayRatingPrompt()
            incrementDisplayCount()
            setCurrentAsPromptDisplayedVersion()
        }
    }
    
    private static func displayRatingPrompt() {
        SKStoreReviewController.requestReview()
    }
    
    /// insert utility functions here...
}

Now, requestReviewIfNeeded is the only front-facing function for RatingManager and when you request for a rating prompt, it will take all the necessary checks into consideration.

Manually requesting a review

We have certain checks inside our RatingManager class to decide whether or not to display the rating prompt or not. However, you can manually take the user to the App Store review page when the user wishes to do so (say, if you have a “review this app” button in the settings). All you need to do at this time is to open your App Store URL.

/// Open App Store URL to request a manual review from the user
static func manualRequestAppReview(appId: String) {
    let appStoreURL = "https://itunes.apple.com/app/\(appId)?action=write-review"
    guard let reviewURL = URL(string: appStoreURL) else {
        return
    }
    
    UIApplication.shared.open(reviewURL, options: [:], completionHandler: nil)
}

Some best practices for iOS rating and review prompt

  1. Avoid showing rating and review modal as soon the user opens the app. This should be the case even if it is not the first time the user is opening your app.
  2. Let the user use the app for a couple of days (or maybe weeks), and only request a review after they get a chance to play with main functionalities.
  3. Ask for a review at the right time. Probably not a good idea to do so after they lost a game level or dismissed an ad.
  4. Give enough time interval between rating requests. A frequent request might work against you.

Adding a review prompt is also one of the top five features your app should have. To read more about all the essentials features of an app to succeed, please check out my blog post here.

Conclusion

As you just saw, it is very easy to get feedback from your users without having to do much work by using APIs provided by iOS. Implementing this feature following the best practices can help you collect positive feedback, which will translate to better visibility in the App Store.

How useful was this post?

Click on a star to rate it!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?