At some point, keeping up with app reviews manually stops being feasible. Running a portfolio of apps with over 50 million cumulative downloads as a solo developer, I regularly receive reviews in Japanese, English, German, French, Spanish, and Korean. Trying to reply to each review in its original language by hand was consuming close to an hour a day.
Around 2025, I started semi-automating review replies using Gemini API. What I didn't expect was hitting an undocumented behavior in App Store Connect's API — an implicit rate limit that I ended up calling the "8-second rule." This is a record of that implementation, including the parts that weren't in any documentation.
Why I Wanted to Automate Review Replies
The apps I build — Beautiful HD Wallpapers (iOS/Android), Ukiyo-e Wallpapers, Relaxing Healing, and a few others — collectively serve about 3 million monthly active users. App store review response rates affect rankings on both platforms, so replying promptly matters beyond just user goodwill.
The friction was multilingual replies. A German user leaving a thoughtful one-star review deserves a response in German. Running that through translation tools, verifying it reads naturally, then posting — it adds up across a review queue that runs to hundreds each month.
Gemini's automatic language detection made it a natural fit for this workflow: pass the review text in, get back a reply in the same language.
The Core Implementation
The setup is Python-based: pull review data from the Google Play Developer API and App Store Connect API, generate replies with Gemini, then post them back.
Here's the reply generation function:
import google.generativeai as genai
import time
genai.configure(api_key="YOUR_GEMINI_API_KEY")
model = genai.GenerativeModel("gemini-2.5-flash")
def generate_reply(review_text: str, app_name: str, rating: int) -> str:
"""
Generate a review reply in the same language as the review.
Adjusts tone based on star rating.
"""
prompt = f"""Write a reply to the following app review.
App name: {app_name}
Rating: {rating} stars
Review:
{review_text}
Requirements:
- Reply in the same language as the review
- Natural, human tone — not a form letter
- High rating (4-5 stars): express genuine thanks, welcome continued use
- Low rating (1-3 stars): acknowledge the issue, briefly describe improvement intent
- Keep it under 150 characters
- Reference specific content from the review rather than giving a generic response
Output only the reply text."""
response = model.generate_content(prompt)
return response.text.strip()This works well across languages. In terms of reply quality for short-form multilingual text, Gemini 2.5 Flash is comparable to Claude and GPT-4o, while being faster and cheaper at scale.
The Problem I Didn't See Coming: App Store's 8-Second Rule
Google Play worked smoothly from the start. App Store Connect was different.
After the first successful batch run, I started getting 403 errors or silent failures after roughly 30–40 replies within a single session. The replies appeared to post, but the responses weren't showing up in App Store Connect. Increasing delays between requests eventually resolved it — but it took some trial and error to find the threshold.
After testing, I landed on 8 seconds between requests as the reliable interval. Apple doesn't document this anywhere that I could find. Here's how I structured the batch posting function to handle it:
def post_reply_to_app_store(review_id: str, reply_text: str, auth_token: str) -> bool:
"""
Post a reply via App Store Connect API.
⚠️ Must wait 8+ seconds between calls to avoid silent failures.
"""
import requests
url = "https://api.appstoreconnect.apple.com/v1/customerReviewResponses"
headers = {
"Authorization": f"Bearer {auth_token}",
"Content-Type": "application/json"
}
payload = {
"data": {
"type": "customerReviewResponses",
"attributes": {"body": reply_text},
"relationships": {
"review": {
"data": {"type": "customerReviews", "id": review_id}
}
}
}
}
response = requests.post(url, json=payload, headers=headers)
return response.status_code == 201
def batch_reply_app_store(reviews: list, replies: list, auth_token: str):
"""
Post replies in sequence with enforced wait between each.
Caps at 35 per session as a safety margin.
"""
WAIT_SECONDS = 8 # Undocumented App Store rate limit threshold
MAX_PER_SESSION = 35
for i, (review_id, reply_text) in enumerate(zip(reviews, replies)):
if i >= MAX_PER_SESSION:
print(f"Session cap reached ({MAX_PER_SESSION}). Continue in next session.")
break
success = post_reply_to_app_store(review_id, reply_text, auth_token)
label = "✅" if success else "❌"
print(f"{label} [{i+1}/{min(len(reviews), MAX_PER_SESSION)}] {review_id[:8]}...")
if i < min(len(reviews), MAX_PER_SESSION) - 1:
time.sleep(WAIT_SECONDS)Setting WAIT_SECONDS = 8 and MAX_PER_SESSION = 35 eliminated the failures completely. When I pushed below 6 seconds, failures reappeared in the 30+ range.
Language Quality Varies — and You Can Nudge It
One thing I noticed after running this for a few months: Gemini's reply quality isn't uniform across languages. English, Japanese, and Spanish feel natural. German and French responses occasionally sound slightly stiff or over-apologetic, especially when handling low-rating reviews.
Adding language-specific instructions in the prompt helps significantly:
LANGUAGE_HINTS = {
"de": "Schreiben Sie auf natürlichem Deutsch, das klingt, als wäre es von einem echten Entwickler geschrieben. Vermeiden Sie übermäßige Entschuldigungen.",
"fr": "Répondez en français naturel et chaleureux. Évitez le style trop formel.",
"ko": "자연스러운 한국어로 답변해 주세요. 지나치게 공식적인 표현은 피해주세요.",
}
def generate_reply_with_hint(
review_text: str,
app_name: str,
rating: int,
detected_lang: str
) -> str:
hint = LANGUAGE_HINTS.get(detected_lang, "")
hint_section = f"\nAdditional instruction: {hint}" if hint else ""
prompt = f"""...(base prompt)...{hint_section}"""
return model.generate_content(prompt).text.strip()For most languages, the base prompt is enough. The hints are a targeted fix for the languages where the default output felt mechanical.
Why Gemini API Rather Than the Alternatives
I tested Claude Haiku and GPT-4o Mini for this same task. Reply quality across all three was close enough that it wasn't a deciding factor. Gemini 2.5 Flash edges out on speed for short outputs, and at the volume I'm running — a few thousand review replies per month across my app portfolio — the cost difference adds up.
My monthly Gemini API cost for this workflow stays well under a few hundred yen. For comparison, running the same volume through GPT-4o Mini came out roughly 2–3x higher. For a solo developer optimizing per-app economics, that margin matters.
For handling Gemini API rate limits in general, see Gemini API Rate Limit Errors: Practical Patterns to Avoid Them.
What Changed After Automating This
The time spent on review replies dropped from close to an hour a day to about 30 minutes per week. I still read every generated reply before posting — quality control stays human. But the time previously spent on translation and drafting is gone, which means the checking step actually gets the attention it deserves.
The workflow that works for me: Gemini generates, I verify, then the batch posting script handles the actual submission with the timing logic built in. It's not fully automated, and I'm not sure it should be — but it's made a real difference in how much of my week goes toward keeping users happy across a dozen countries.
If you're running multilingual apps and considering a similar setup, the 8-second wait for App Store replies is the one thing I wish someone had documented before I ran into it.