Features.Vote - Build profitable features from user feedback | Product Hunt
iOS · SwiftUI · Apple-compliant

How to Reduce Negative App Store Reviews

Most one-star reviews are unhappy users with nowhere else to go. Give them an in-app outlet first — and nudge your happy users toward the App Store. Here's how to do it the right way, without breaking Apple's rules.

"Shout out to FeaturesVote! Integration was done in under a minute"

Alexandre Negrel,

Founder at Prisme Analytics

First, the rule that matters

This is about routing feedback, not gating ratings. Apple requires you to use the native rating API and never to block or discourage users from rating you. Everyone — including the "Not really" crowd — must still be able to leave a review. Done that way, you're helping users reach the right place, which is allowed. Withholding the prompt as a gate is not.

1

Ask a simple satisfaction question

At a positive moment, ask 'Enjoying the app?' with two paths. This isn't a rating — it's a fork that sends each user to the most useful next step.

import SwiftUI // Ask after a WIN — a completed task, a few good sessions — // never on cold launch or mid-flow. struct SatisfactionPrompt: View { @Environment(\.requestReview) private var requestReview // iOS 16+ @State private var showFeedback = false var body: some View { VStack(spacing: 20) { Text("Enjoying MyApp so far?") .font(.title3.bold()) HStack(spacing: 12) { Button("Not really") { // Route to feedback — see Step 2. showFeedback = true } .buttonStyle(.bordered) Button("Love it!") { // Route to Apple's NATIVE rating prompt — see Step 3. requestReview() } .buttonStyle(.borderedProminent) } } .padding() .sheet(isPresented: $showFeedback) { FeedbackForm() } } }
2

Send unhappy users to private feedback

If someone isn't happy, open an in-app feedback form. You learn about the problem privately and get a chance to fix it — far better than reading about it in a public review.

// Unhappy path: capture the problem privately so you can // fix it — instead of it becoming a public 1-star review. struct FeedbackForm: View { @Environment(\.dismiss) private var dismiss @State private var message = "" var body: some View { NavigationStack { Form { Section("What went wrong?") { TextEditor(text: $message).frame(minHeight: 120) } } .navigationTitle("Tell us more") .toolbar { ToolbarItem(placement: .confirmationAction) { Button("Send") { /* POST to your feedback channel */ ; dismiss() } } } } } }
3

Send happy users to Apple's native prompt

If someone is happy, call requestReview() so the system shows its native rating sheet. You never draw your own stars or submit a rating yourself — Apple owns that UI and rate-limits it.

import StoreKit // Happy path: ask the system to show the native review prompt. // You DON'T draw your own stars — Apple controls the UI and // limits how often it appears (a few times/year). @Environment(\.requestReview) private var requestReview func askForReview() { requestReview() } // UIKit equivalent if you're not in SwiftUI: // if let scene = UIApplication.shared.connectedScenes // .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene { // SKStoreReviewController.requestReview(in: scene) // }

Stay compliant: 5 rules

  • Always use Apple's native API (requestReview / SKStoreReviewController). Never build a custom star UI that submits a rating for the user.

  • Never withhold the ability to rate. Users can always rate you — even from the 'Not really' path. Don't make a good review a precondition.

  • Don't beg or incentivize. Offering rewards for ratings violates App Store guidelines.

  • Ask sparingly and in context. The system prompt only shows a few times per year; don't waste it on a cold launch.

  • When in doubt, read Apple's Human Interface Guidelines on Ratings and Reviews — and stay on the right side of them.

Give the unhappy path somewhere to land

The strategy only works if the "Not really" tap leads somewhere you'll act on. Features.Vote turns it into a tracked, votable item on a native board — so you can prioritize the fix and notify the user when it ships. A complaint becomes a closed loop.

import SwiftUI import FeaturesVote // Give the "Not really" path somewhere real to land: // a native board where the issue becomes a tracked, // votable item you can resolve and follow up on. struct FeedbackScreen: View { var body: some View { FeaturesVote.VotingBoardView() } }

Frequently Asked Questions

Still not convinced?

Here's a full price comparison with all top competitors

Okay, okay! Sign me up!

Start building the right features today ⚡️