![An app store review prompt](/_app/immutable/assets/skstorereviewcontroller.Cx0B8QjK.png)
This guide will help you request App Store reviews in your app using Apple's SKStoreReviewController. We will cover:
- SKStoreReviewController API
- SKStoreReviewController limitations and alternatives
- How the right timing can increase your app rating
- Preventing negative reviews
- About our SDK: easier reviews and better ratings
Using SKStoreReviewController
Requesting reviews with SKStoreReviewController is relatively easy but there are some important considerations to keep in mind. Here's what you need to know:
- Be aware that MacOS has a different API than iOS/iPadOS/Catalyst.
- These APIs have changed since they were introduced, so it's important to call the right version depending on the host OS.
- You'll need to specify a UIWindowScene to display the prompt inside.
The following sections walk though how to add SKStoreReviewController programmatically.
Link StoreKit Framework
This usually isn't required on projects setup with a recent version of Xcode. However, if you encounter linking errors, you may need to manually link the StoreKit framework.
First, open Xcode > Project Config > General > Frameworks, Libraries and Embedded Content > Add Button > Search “storekit” > Select StoreKit > Add. Ensure the framework is set to “Do not embed” after you add it.
![Xcode UI to add StoreKit framework](/_app/immutable/assets/xcode_storekit.Djqoy8yr.png)
Request Review API
Lots of guides recommend simply calling requestReview
. However,
that approach is out of date and has several drawbacks including using a
deprecated API, crashing on older OS versions, failing if called too soon, and
needing to be called from the main thread.
We're offering a helper which handles the concerns we had. This method:
- Can be called from any thread, not just main.
- Won't fail if called too early in application lifecycle. It waits for your UI to attach.
- Finds you main UIWindowScene, without adding new helpers to your App Delegate.
- Does not use deprecated APIs on any OS version.
- Is backwards compatible for older OS versions, including avoiding crashing when SKStoreReviewController is not available.
Be sure to look at the SDK method below before integrating this code directly. Using the SDK has several benefits over direct API integration:
- Improve your app rating
- Prevent negative reviews
- Reduce the time to integrate
- Enable over-the-air updates
- Tracks user engagement, and helps show the prompt at the perfect moment
If you want to directly integrate with the API without using our SDK, add this helper to your project then call it when you want the review prompt to appear.
After you add CMReviewHelper to your project, call CMReviewHelper.requestReview()
To add the helper, create the file CMReviewHelper.swift
with the
content:
import Foundation
import StoreKit
class CMReviewHelper: NSObject {
static func requestReview() {
// Ensure we're on main thread.
// Dispatch async even if already on main thread to give the primary UIWindowScene time to attach.
DispatchQueue.main.async {
CMReviewHelper.requestReviewMain()
}
}
private static func requestReviewMain() {
if #available(iOS 14, *) {
// Default to displaying in your app's keyWindow, fallback to first connected scene
// If your app manages multiple UIWindowScenes, you can specify one here
let keyWindowScene = CMReviewHelper.appKeyWindowScene();
if let keyWindowScene {
SKStoreReviewController.requestReview(in: keyWindowScene)
}
} else if #available(iOS 10.3, *) {
// Older iOS
SKStoreReviewController.requestReview()
}
}
@available(iOS 14, *)
private static func appKeyWindowScene() -> UIWindowScene? {
// This logic finds the keyWindow's UIWindowScene on all iOS versions >= 14
// While slightly complex, other implementations found online crash on earlier versions of iOS (v14.*), or use deprecated APIs.
var keyWindowScene: UIWindowScene?
UIApplication.shared.connectedScenes
.forEach { scene in
let winScene = scene as? UIWindowScene
var isKeyWindow = false
if let winScene {
winScene.windows.forEach { win in
if win.isKeyWindow {
isKeyWindow = true
}
}
}
if isKeyWindow || keyWindowScene == nil {
keyWindowScene = winScene
}
}
return keyWindowScene
}
}
Add the utility class CMReviewHelper to your project, then call [CMReviewHelper requestReview];
Add a file CMReviewHelper.h
with the content:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface CMReviewHelper : NSObject
+ (void)requestReview;
@end
NS_ASSUME_NONNULL_END
Add a file CMReviewHelper.h
with the content:
#import "CMReviewHelper.h"
#import <StoreKit/StoreKit.h>
@implementation CMReviewHelper
+ (void)requestReview {
// Ensure we're on main thread.
// Dispatch async even if already on main thread to give the primary UIWindowScene time to attach.
dispatch_async(dispatch_get_main_queue(), ^{
[self requestReviewMain];
});
}
+ (void)requestReviewMain {
if (@available(iOS 14.0, *)) {
// Default to displaying in your app's keyWindow, fallback to first connected scene
// If your app manages multiple UIWindowScenes, you can specify one here
UIWindowScene *keyWindowScene = [self appKeyWindowScene];
if (keyWindowScene) {
[SKStoreReviewController requestReviewInScene:keyWindowScene];
}
} else if (@available(iOS 10.3, *)) {
// Older iOS
[SKStoreReviewController requestReview];
}
}
+ (UIWindowScene*) appKeyWindowScene API_AVAILABLE(ios(14)) {
// This logic finds the keyWindow's UIWindowScene on all iOS versions >= 14
// While slightly complex, other implementations found online crash on earlier versions of iOS (v14.*), or use deprecated APIs.
UIWindowScene __block *keyWindowScene;
[[UIApplication sharedApplication].connectedScenes enumerateObjectsUsingBlock:^(UIScene * _Nonnull scene, BOOL * _Nonnull stop) {
if ([scene isKindOfClass:[UIWindowScene class]]) {
UIWindowScene *windowScene = (UIWindowScene *)scene;
BOOL __block isKeyWindowScene = false;
[windowScene.windows enumerateObjectsUsingBlock:^(UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) {
if (window.isKeyWindow) {
isKeyWindowScene = true;
}
}];
if (isKeyWindowScene || keyWindowScene == nil) {
keyWindowScene = windowScene;
}
}
}];
return keyWindowScene;
}
@end
SKStoreReviewController Limitations
There are some important limits to be aware of when using SKStoreReviewController:
- The system will only display the review prompt a maximum of three times within a 365-day period, per user, per app. Note: this doesn't apply during development.
- Users have the option to disable review prompts across all apps on their device in App Store settings. If they do, calling requestReview won't show anything.
- There's no programmatic way to know if your requestReview call displayed a prompt or not.
- Similarly, there's no way to determine if the user rated your app or what rating they gave it.
- The review prompt will not appear for apps distributed via Testflight.
Apple put these limitations in place to prevent apps from misusing the system by spamming users with review requests or only unlocking in-app content for 5-star reviews.
SKStoreReviewController Alternative
An alternative to using SKStoreReviewController is deeplinking into the App
Store. Appending ?action=write-review
to your app store link will
open the App Store to the "Write a Review" screen for your app. Here's an
example for
Spotify.
While this option is available, we recommend sticking with SKStoreReviewController. It has a more streamlined UI and it allows users to remain within your app.
Increase your App Rating
Apple recommends asking users to review your app “when users are most likely to feel satisfaction with your app, such as when they've completed an action, level, or task” [1]. However, the details of timing are left up to you.
Our comprehensive guide helps you perfect the timing of your App Store review prompts, to target the right users at the right moment. By doing so, you can significantly boost your average app rating!
Our guide covers essential topics, including:
- Timing review prompts after users have had sufficient time to familiarize themselves with your app, and immediately following significant interactions
- Avoiding negative conditions, such as:
- Low battery or no network connection
- User distractions (e.g., being on a call or driving)
- Unengaged users (e.g., device lying flat on a table)
- Excluding users who:
- Run old or buggy releases of your app
- Using an interface languages not supported by your app's UI
- Pausing review prompts after major UX changes to give users time to adjust
- Avoiding users who have blocked permissions crucial to your app
- And many more valuable insights!
By following our guide, you'll be well on your way to optimizing your review prompts and improving your app's overall rating. Our developer guide will walk you through implementing all of these approaches in your app in about 30 minutes!
Prevent Negative Reviews with a Strategic Pre-Prompt
You can also improve your app rating with a better user experience.
Interestingly, many dissatisfied reviewers mistakenly use reviews as a means of obtaining customer support. In reality, they would prefer to contact support or consult your help documentation rather than leaving a negative review. By designing a thoughtful UI, you can redirect users who require support to the appropriate channel, thereby minimizing the likelihood of negative reviews.
We offer a full guide for this approach, as well as a developer guide.
![review prompt with buttons for 'Rate Us' and 'Help, Feedback & Contact Us', and 'Not Now'](/_app/immutable/assets/suggested_prompt.cqM-YIH_.png)
Easier Reviews, Better Ratings: About Our SDK
Our SDK makes implementing app review prompts easier than ever, including over 20 advanced optimizations designed to boost your App Store rating.
The benefits of our SDK include:
- Targeted prompts: Use our engagement history queries to target users at the perfect moment, increasing the likelihood of positive reviews.
- Avoid negative states: Our built-in optimizations ensure that you avoid asking users for reviews during unfavorable conditions, such as low battery, no network connection, or on older builds, all without requiring custom code.
- Dynamic targeting: Update your targeting strategy anytime, over the air, to adjust to changing circumstances, such as buggy releases or AB testing targeting approaches.
- Flexible messaging: Update your messaging in real-time, without requiring app updates, to ensure your prompts remain relevant and effective.
- Low-code integration: After you integrate, easily add app prompts, pre-prompts, targeting or filters to your app without writing any additional code.
By leveraging our SDK, you can simplify the process of collecting app reviews and improve your overall App Store rating. Read our review app review developer guide for how to get started.
Get Started: SDK Method
We hope that you found this guide informative! If you're ready to take your app reviews to the next level with Critical Moments SDK, we invite you to explore our comprehensive Developer Guide.
Dive in to learn more about how our SDK can help you optimize your app reviews and improve your overall App Store rating.
Other Articles about App Reviews
Want to learn more about how Critical Moments can improve your app reviews? We have several additional resources that will help you improve your app's rating:
- Improve Your App's Rating: A Practical Guide to App Review Prompts - Tips for targeting app review prompts to increase your App Store rating.
- Confronting Deceptive Patterns in App Reviews (and How To Fix Them) - Learn to request app reviews without resorting to deceptive design, and simultaneously boost your app rating.
- How to A/B Test Your App Store Review Prompt
Further Reading:
- [1] Apple: Ratings, Reviews, and Responses
- [2] StoreKit Docs: Requesting App Store reviews