Skip to main content

One of the best ways to increase App Store ranking is increase the amount and quality of the ratings and reviews that your app gets.

The goal is to request reviews from users that use your app multiple times because if they are using it more, it is more likely that they enjoy it and will rate it highly. If we were to request a review often or too early, it increases the chances of lower star ratings because the user may feed infringed upon and the inconvenience would lower your star rating

Store Review Request API

Today we are going to learn how to track sessions in and iOS app, and then request users ratings within the application after they’ve had three sessions. We can change the number of sessions if we want to but I’ve found three to a be a good number.

Apple provides an API called SKStoreReviewController that allows us to request ratings from within our app and we can call this API after certain actions have been taken inside of the app. In this case we  will request a review after three successful sessions on the next app open.

The way we will do this is to use notifications that Apple provides, UIApplication.didBecomeActiveNotification and UIApplication.willResignActiveNotification, to tell us when the application becomes active to start a session timer and then when the app goes into the background or terminates we will stop the timer and log the session. We can also include a minimum session time in seconds so that if the user just opens the app accidentally and closes it we can skip that and not log it as a session.

Create a new app

Go to Xcode and create a new app using a SwiftUI interface.

Create a Ratings Request Class

Inside your project, create a new File call RatingRequest.swift

import Foundation
import StoreKit

class RatingRequester {
    private let userDefaultsSessionKey = "app-sessions"
    private let userDefaultsSeenReviewKey = "seen-app-review"
    private let notificationCenter: NotificationCenter
    private let userDefaults: UserDefaults
    private var minimumDuration: Int
    private var sessionStartDate = Date()

    public static let shared = RatingRequester(minimumDuration: 10)

    private var numSessions: Int {
        userDefaults.integer(forKey: userDefaultsSessionKey)
    }

    init(
        minimumDuration: Int,
        userDefaults: UserDefaults = .standard,
        notificationCenter: NotificationCenter = .default
    ) {
        self.minimumDuration = minimumDuration
        self.userDefaults = userDefaults
        self.notificationCenter = notificationCenter

        self.registerNotifications()
    }

    public func showReviewIfNeeded(minimumSessions: Int) {
        let seenReview = userDefaults.bool(forKey: userDefaultsSeenReviewKey)
        let numSessions = numSessions
        guard !seenReview, numSessions > minimumSessions else { return }

        requestRating()
    }

    private func requestRating() {
        userDefaults.set(true, forKey: userDefaultsSeenReviewKey)

        DispatchQueue.main.async {
            if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
                SKStoreReviewController.requestReview(in: scene)
            }
        }
    }

    @objc private func startSession() {
        self.sessionStartDate = Date()
    }

    @objc private func endSession() {
        let diff = Date().timeIntervalSince1970 - sessionStartDate.timeIntervalSince1970
        guard diff > Double(minimumDuration) else {
            return
        }

        userDefaults.setValue(numSessions + 1, forKey: userDefaultsSessionKey)
    }

    private func registerNotifications() {
        notificationCenter.addObserver(
            self,
            selector: #selector(startSession),
            name: UIApplication.didBecomeActiveNotification,
            object: nil
        )
        notificationCenter.addObserver(
            self,
            selector: #selector(endSession),
            name: UIApplication.willResignActiveNotification,
            object: nil
        )
        notificationCenter.addObserver(
            self,
            selector: #selector(endSession),
            name: UIApplication.willTerminateNotification,
            object: nil
        )
    }
}
Swift

This will allow you to call RatingRequester.shared.showReviewIfNeeded(minimumSessions: 3) and the object will ask the system to show the review request alert to the user on the main scene.

For a session to count as a session it will need to last for at least 10 seconds. This minimum session length can be changed by changing the minimumDuration property on the shared instance.

Also after the review gets requested a flag is set in the UserDefaults that will block the review from being requested again in the future when showReviewIfNeeded is called. If you want to keep attempting to show the review you can remove this check by removing the seenReview variable and guard statement inside the showReviewIfNeeded method.

Note: Per Apple’s documentation there is no way to know if the review box was actually shown or can we know what the review is. Alls we can do is request the rating and the system handles the rest:

Add RatingRequester to your app

So in order for the alert to be shown we will need to call the RatingRequester.shared.showReviewIfNeeded method in the SceneDelegate if we’re building a UIKit application or in the ContentView if we’re building a SwiftUI app:

SceneDelegate.swift (for UIKit applications)
...
func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
               options connectionOptions: UIScene.ConnectionOptions) {

    // Bootstrap your apps UI...
    RatingRequester.shared.showReviewIfNeeded(minimumSessions: 3)

}
...
Swift

Or for SwiftUI

ContentView.swift
struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
        .onAppear {
            RatingRequester.shared.showReviewIfNeeded(minimumSessions: 3)
        }
    }
}
Swift

The Resulting Alert

After completing 3 sessions of the app for at least 10 seconds per session, on the next app load you swill see:

Hope you enjoyed this article, if you need any help feel free to get in touch!

David

Hi I'm David – I'm a creator, entrepreneur, and engineer. I add value to people to help them live a better life.

Leave a Reply