Skip to content
Back to archipelago.banuacoder.com

Feature SDKs

How to ask for app ratings at the right time in Flutter ​

Free Reference for rating_review_sdk: every variable, option and package it generates. Command: archipelago generate rating_review_sdk

Generate the Rating & Review SDK, set the five prompt gates at runtime, record sessions and key events, and read why prompts were skipped.

What you'll learn ​

  • Generating the Rating & Review SDK
  • Configuring the five-gate prompt evaluation system at runtime
  • Recording sessions and key events to drive the rating prompt
  • Using the analytics-friendly decision API to track why prompts were skipped
  • Understanding platform availability constraints on iOS and Android

Prerequisites ​

Step 1: Generate the Rating & Review SDK ​

bash
archipelago generate rating_review_sdk

The brick has no generation variables. All configuration happens at runtime through RatingPromptConfig in your DI module.

The brick generates storage_sdk and package_info_provider for you if they are missing. It saves counters through StorageProvider under the rating_review namespace. A logout does not clear them.

Step 2: Understand the Generated Structure ​

The Rating & Review SDK uses the API/Impl split pattern:

text
features/
└── rating_review/
    ├── rating_review_api/      # RatingReviewSDK contract + RatingPromptConfig + decision types
    └── rating_review_impl/     # Gate evaluation, persistence, and platform review request
        └── lib/src/
            ├── rating_review_sdk_impl.dart
            ├── data/           # Local storage for session/event counts
            ├── di/             # RatingReviewImplPackageModule
            └── domain/         # Gate evaluation logic

Features that trigger the rating prompt depend only on rating_review_api.

The post-generation hook registers RatingReviewImplPackageModule in lib/di/injector.dart. The SDK is a lazy singleton. Nothing runs at boot.

Step 3: Configure the Prompt Gates ​

Provide RatingPromptConfig in your app DI module before RatingReviewImplPackageModule runs:

dart
// apps/<appName>/lib/di/app_di_module.dart
@module
abstract class AppDIModule {
  @lazySingleton
  RatingPromptConfig get ratingPromptConfig => const RatingPromptConfig(
    minSessions: 3,         // Minimum app launches before showing the prompt
    minKeyEvents: 2,        // Minimum positive moments before showing the prompt
    cooldownDays: 30,       // Days to wait before asking again after a dismissal
    askOncePerVersion: true, // Reset gates when the app version changes
    iosAppStoreId: 'YOUR_APP_STORE_ID', // Required for openStoreListing() on iOS
  );
}

The five gates are evaluated in order on each shouldRequestReview() call:

  1. Platform availability: in_app_review is supported on this device/OS version
  2. Session threshold: recorded sessions ≥ minSessions
  3. Key event threshold: recorded key events ≥ minKeyEvents
  4. Cooldown: enough days have passed since the last prompt
  5. Per-version gate: not yet shown in this app version (when askOncePerVersion is true)

All five must pass for the prompt to show.

Step 4: Record Sessions and Key Events ​

Call recordSession() once per app launch, early in your post-launch phase:

dart
// In a post-launch initializer
await ratingSDK.recordSession();

Call recordKeyEvent() after a meaningful positive moment, such as a finished checkout or a successful upload:

dart
// In your order confirmation screen or usecase
await getIt<RatingReviewSDK>().recordKeyEvent('checkout_completed');
await getIt<RatingReviewSDK>().recordKeyEvent('photo_shared');

Key event names are free-form strings. Use them to tell event types apart in your analytics.

Step 5: Show the Rating Prompt ​

Check the gates and show the prompt after a positive moment:

dart
final ratingSDK = getIt<RatingReviewSDK>();

await ratingSDK.recordKeyEvent('subscription_activated');

if (await ratingSDK.shouldRequestReview()) {
  await ratingSDK.requestReview();
}

requestReview() delegates to the platform's native in-app review UI. On iOS this is SKStoreReviewController. On Android it is the Google Play In-App Review API. The OS decides whether the dialog appears. Calling requestReview() is a request, not a guarantee.

Step 6: Use the Decision API for Analytics ​

evaluatePromptDecision() returns a typed decision instead of a boolean, which lets you track skip reasons without duplicating the gate logic:

dart
final ratingSDK = getIt<RatingReviewSDK>();
final decision = await ratingSDK.evaluatePromptDecision();

switch (decision) {
  case RatingPromptDecisionShow():
    await ratingSDK.requestReview();
    analytics.track('rating_prompt_shown');

  case RatingPromptDecisionSkip(:final reason):
    analytics.track('rating_prompt_skipped', {'reason': reason.name});
    // reason.name is one of: 'platformUnavailable', 'sessionThreshold',
    // 'keyEventThreshold', 'cooldown', 'perVersionGate'
}

Use this to measure how often each gate suppresses the prompt.

After a positive review or to let users rate manually from a settings screen:

dart
// Opens App Store (iOS) or Play Store (Android) listing
await getIt<RatingReviewSDK>().openStoreListing();

On iOS, iosAppStoreId must be set in RatingPromptConfig for this to work. On Android, the Play Store app page is derived from the app's package name automatically.

Platform Notes ​

PlatformAvailability
iOSAvailable when iosAppStoreId is set and the app is on the App Store
AndroidRequires the app to be published (internal testing track is sufficient)
Debug buildsisAvailable() returns false on Android. The Play Store API needs a production or testing track build
iOS simulatorReview requests are silently ignored by the OS

If isAvailable() returns false, shouldRequestReview() will also return false via the platform availability gate, so your feature code needs no special handling.

Common Customizations ​

GoalWhat to do
Lower threshold for testingSet minSessions: 1, minKeyEvents: 1 in a debug DI override
Disable per-version gatingSet askOncePerVersion: false
Show prompt after a specific screen onlyCall shouldRequestReview() in that screen's initState or onResume
Reset all countersCall ratingSDK.reset() (useful for QA)
Surface the prompt after onboardingRecord a 'onboarding_completed' key event at the end of onboarding

Next Steps ​