Share via

How can I ask users for ratings and reviews in my iOS game?

Kim Strasser 2,596 Reputation points
2026-06-02T15:27:46.8833333+00:00

I want that the standardized prompt gets displayed in my game on iOS devices after the user finished a level in my game. How can I display the standardized prompt in my game and is it necessary that I check if the prompt was already displayed three times in a 365-day period? In addition, is it necessary to check if the user has already added a rating or a review?

Should I store the timestamp on a server when the prompt was displayed the last time in my game so that my game knows that the prompt doesn´t need to be displayed after each level in my game?

I only want to display the prompt in certain time intervals because I don´t want to display it too often. And it´s possible that the user plays my game on iOS and Android devices.

https://developer.apple.com/app-store/ratings-and-reviews/

Screenshot 2026-06-02 173556

Developer technologies | .NET | .NET Multi-platform App UI
0 comments No comments

2 answers

Sort by: Most helpful
  1. Nancy Vo (WICLOUD CORPORATION) 4,765 Reputation points Microsoft External Staff Moderator
    2026-06-03T04:37:03.8966667+00:00

    Hello @Kim Strasser ,

    Thanks for your question.

    I recommend using the community-created Plugin.Maui.AppRating, which has gained over 57,000 downloads. It wraps Apple's native SKStoreReviewController under the hood, so the popup your players see is the exact same standardized iOS prompt Apple provides. For more information, you can refer to this usage and code example.

    1. Install the NuGet package
    dotnet add package Plugin.Maui.AppRating
    
    1. Register in MauiProgram.cs
    using Plugin.Maui.AppRating;
    
    public static class MauiProgram
    {
        public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                });
    
            builder.Services.AddTransient<MainPage>();
            builder.Services.AddSingleton<IAppRating>(AppRating.Default);
    
            return builder.Build();
        }
    }
    
    1. Code example in your game page
    using Plugin.Maui.AppRating;
    
    public partial class GamePage : ContentPage
    {
        private readonly IAppRating _appRating;
    
        private const string IOSApplicationId   = "idYOURAPPID";
        private const string AndroidPackageName = "com.yourcompany.yourgame";
    
        public GamePage(IAppRating appRating)
        {
            InitializeComponent();
            _appRating = appRating;
            _appRating.ThrowErrors = false;
        }
    
        public async Task OnLevelCompleted()
        {
            int levelsCompleted = Preferences.Get("levels_completed", 0) + 1;
            Preferences.Set("levels_completed", levelsCompleted);
    
            if (levelsCompleted % 5 == 0)
            {
                await CheckAndShowReviewPrompt();
            }
        }
    
        private async Task CheckAndShowReviewPrompt()
        {
            if (Preferences.Get("app_rated", false))
                return;
    
            var lastShownStr = Preferences.Get("last_review_shown", string.Empty);
            if (!string.IsNullOrEmpty(lastShownStr))
            {
                var lastShown = DateTime.Parse(lastShownStr);
                var daysPassed = (DateTime.UtcNow - lastShown).TotalDays;
    
                if (daysPassed < 30)
                    return;
            }
    
            await MainThread.InvokeOnMainThreadAsync(async () =>
            {
                bool wantsToRate = await DisplayAlert(
                    "Enjoying the game?",
                    "Would you like to leave a quick review? It really helps us!",
                    "Sure!", "Maybe later"
                );
    
                if (!wantsToRate)
                {
                    Preferences.Set("levels_completed", 0);
                    return;
                }
    
                await ShowNativeReviewPopup();
            });
        }
    
        private async Task ShowNativeReviewPopup()
        {
            await MainThread.InvokeOnMainThreadAsync(async () =>
            {
                await _appRating.PerformInAppRateAsync();
            });
    
            Preferences.Set("last_review_shown", DateTime.UtcNow.ToString());
            Preferences.Set("app_rated", true);
        }
    
        private async void OnRateUsButtonClicked(object sender, EventArgs e)
        {
            if (Preferences.Get("app_rated", false))
                return;
    
            await MainThread.InvokeOnMainThreadAsync(async () =>
            {
                try
                {
                    await _appRating.PerformRatingOnStoreAsync(
                        applicationId: IOSApplicationId,
                        packageName:   AndroidPackageName
                    );
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine($"Rating error: {ex.Message}");
                }
            });
    
            Preferences.Set("app_rated", true);
        }
    }
    

    Is it necessary to check if the prompt was already displayed three times in a 365-day period?

    No, you do not need to check or count this yourself. Apple handles it automatically.

    Unlike Android where Google does not publish their exact quota, Apple is transparent and officially documents the limit. Here is what Apple officially says:

    "Be aware that the system displays the review prompt to a user a maximum of three times within a 365-day period"

    However, it is still good practice - and highly recommended by Apple to add your own minimum interval so you are not calling the API after every single level. The 30-day check in the code above does exactly that.

    The other points follow the same idea as discussed in the Android thread.

    While these links are non-Microsoft links, they are official Github, Nuget and Android documentations and are safe to visit.

    I hope this addresses your question. If this response was helpful, please consider following the guidance to provide feedback.

    Was this answer helpful?


  2. AI answer

    2026-06-02T15:28:02.6266667+00:00

    Use the platform‑provided review APIs and let the store handle limits; add your own app‑side throttling only for user experience.

    1. Displaying the standardized prompt on iOS (.NET / .NET MAUI)

    On iOS, use StoreKit’s in‑app review APIs exposed in .NET:

    • StoreKit.SKStoreReviewController.RequestReview()
    • or StoreKit.AppStore.RequestReview(UIWindowScene) when a scene is available

    Example (C#):

    using StoreKit;
    
    // Call this after the player finishes a level, at a moment that feels natural
    SKStoreReviewController.RequestReview();
    

    Or, if using scenes:

    using StoreKit;
    using UIKit;
    
    var windowScene = UIApplication.SharedApplication
                                     .ConnectedScenes
                                     .OfType<UIWindowScene>()
                                     .FirstOrDefault();
    if (windowScene != null)
    {
        AppStore.RequestReview(windowScene);
    }
    

    Apple decides whether the system review dialog is actually shown; the call is only a request.

    1. Need to track the “3 times in 365 days” limit?

    No. The system enforces its own frequency limits. The app should not try to replicate Apple’s internal counters. Calling RequestReview more often than allowed will simply result in no dialog being shown.

    1. Need to check if the user already rated/reviewed?

    No. The API is designed so the app does not need to know whether the user has already rated or reviewed. The store decides what to show (or not show) based on the user’s history and policy.

    1. App‑side throttling and intervals

    Even though the system enforces global limits, it is still important to:

    • Call the prompt only at positive, natural moments (for example, after finishing a level or achieving a milestone).
    • Avoid calling it after every level.

    A common pattern is to track, in app storage, when the prompt was last requested and/or how many levels have been completed since the last request, and only call RequestReview when a threshold is met (for example, every N levels or after a certain time interval). This is purely for user experience; the system will still enforce its own limits.

    Because the user may play on multiple devices/platforms, storing a timestamp on a backend can help coordinate how often the app requests a review across devices. However, this is optional and independent of the store’s own enforcement.

    1. Android

    On Android, use the Google Play in‑app review API. Its usage and limits are separate from iOS. The same UX principles apply: request at positive moments and avoid frequent prompts.

    1. Strategic timing guidance

    Prompts should be shown:

    • After completing a significant task or milestone (for example, finishing a level).
    • After using a valuable feature.
    • After a major update, once users have experienced the changes.

    Avoid repeated requests that interrupt gameplay, as this can lead to negative reviews.


    References:

    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.