Five product decisions that doubled Photo AI Studio retention

What actually moved the needle on Photo AI Studio's D7 retention. Pricing, onboarding, model choice, refund flow, and a push notification we almost shipped wrong.

Five product decisions that doubled Photo AI Studio retention
KEY TAKEAWAYS
  • Showing the first generation before paywall beat showing pricing first, by a lot.
  • Switching from a single FLUX model to a router across three models cut complaints about face accuracy in half.
  • A 48-hour delayed refund flow, fully automated through RevenueCat, killed almost all chargebacks.
  • The push notification that worked was about their photo being ready, not about us missing them.
  • Weekly themed packs gave people a reason to come back that wasn't 'try our app again.'

Photo AI Studio shipped in early 2024 as a fairly generic headshot generator. By July it was leaking users badly. D7 retention sat around 8%, which for a paid photo app is not catastrophic but also not a business. By the end of 2024 D7 was at 17%. Nothing magic happened. Five product decisions did most of the work, and I want to walk through each one because the lessons generalize to any AI-first product, not just photo apps.

This is the boring middle of building an AI product. Not the launch, not the pivot. The part where you stop guessing and start changing one thing at a time.

1. Generate first, paywall second

The original onboarding asked for 10 selfies, then showed the pricing screen, then trained the model. Conversion to paid was 3.1%. The thinking was reasonable: qualify the user, get the commitment, then do the expensive compute.

We flipped it. Upload selfies, train immediately (which takes about 4 minutes on FAL), show the user their first 4 generated images, then ask for money to unlock the rest of the pack and download in high resolution.

Conversion went to 6.8%. More importantly, D1 retention went from 22% to 41%, because people who didn’t pay still came back to look at their free previews. Some of them paid on day 2 or 3. The training cost per non-paying user went up, sure. We were paying around $0.40 per LoRA training on FAL at the time. But the lifetime value of a converted user dwarfed it, and the people who didn’t convert often told friends, which we tracked through a referral code field at signup.

The lesson: in AI products, the model output is the product demo. Holding it hostage behind a paywall is the same mistake as a SaaS app that won’t let you see the dashboard until you give a credit card.

2. Stop pretending one model fits everyone

We started on a single fine-tuned FLUX.1-dev pipeline. It was fine. It was also visibly worse on darker skin tones, and it struggled with anyone over about 55. Support tickets were dominated by two complaints: “this doesn’t look like me” and “why does my face look plastic.”

We built a router. Three models, picked based on a quick classifier we ran on the uploaded selfies:

async function pickModel(selfies: Selfie[]): Promise<ModelId> {
  const features = await classifySelfies(selfies);
  if (features.skinToneBucket >= 4) return "flux-portrait-v2";
  if (features.estimatedAge >= 50) return "flux-mature-v1";
  return "flux-base-tuned";
}

The classifier is not fancy. It’s a small Replicate model we wrap in a Cloudflare Worker. The point is not that the routing logic is clever. The point is that we stopped treating “the model” as a fixed thing and started treating it as a parameter.

Face accuracy complaints dropped from roughly 14% of generations getting a thumbs-down to about 6%. We did not announce this change. Users just noticed the app got better.

3. The 48-hour automatic refund

App Store refunds are a brutal feedback loop. Apple takes the refund, the user is gone, and you eat the FAL compute cost. Our refund rate was 9% in May 2024. Most of them came in within the first two days.

We added a screen, accessible from settings, called “not happy with your results.” If the user taps it within 48 hours of their first purchase, we offer a full refund through RevenueCat’s customer support API, and we retrain their model for free with new selfies. About 60% of people who tap that screen accept the retrain instead of the refund.

if (hoursSincePurchase < 48 && !user.hasUsedSecondChance) {
  await offerSecondChance(user, {
    refundAvailable: true,
    retrainCredits: 1,
  });
}

Refund rate dropped to 3.2%. Chargebacks, which Apple penalizes you for separately, basically went to zero. The user gets a path that isn’t “complain to Apple,” and we get a chance to fix the actual problem, which is almost always bad input selfies.

This is not a growth hack. It’s just respecting the user enough to admit the first try might not have worked.

4. The push notification I almost got wrong

We ran a small test in September with two notification copies for users who hadn’t opened the app in 5 days:

A: “We miss you! Come back and try a new style.”

B: “Your headshots are ready to remix into 4 new styles this week.”

A got a 2.1% open rate. B got 11.4%. A felt like a needy ex. B was about the user’s stuff, not ours. The actual styles were the same weekly themed pack everyone got, but the framing as “your headshots” instead of “our app” changed everything.

I bring this up because the temptation with AI products is to lean on the AI as the hook. “New model just dropped, come try it.” Almost no one cares. They care about the artifact they already made and what they can do with it next.

5. Weekly themed packs

This is the dumbest one and it worked the best. Every Monday we drop a new themed pack: linkedin executive, 90s yearbook, ski trip, that kind of thing. Same underlying model, different prompt templates and negative prompts, sometimes a different LoRA for style transfer.

Production-wise, each pack is a JSON file:

{
  "id": "ski-trip-2024-12",
  "name": "Apres Ski",
  "prompts": [
    "cinematic portrait of {SUBJECT} in a wool sweater, mountain lodge background, golden hour",
    "{SUBJECT} on a chairlift, snow falling, soft natural light"
  ],
  "negative": "plastic skin, extra fingers, watermark",
  "styleLora": "film-grain-v3"
}

A designer writes the prompts. The engineering work is approximately zero. But it gives existing users a reason to open the app every Monday that isn’t “we hope you remember us.” D30 retention for users who tried at least 3 weekly packs is 38%. For users who never tried one it’s 11%.

This is the closest thing to a content cadence that a generative app can have. You’re not asking the user to be creative. You’re being creative for them, on a schedule.

What I would still change

The router in decision 2 is rule-based and we know it’s leaving quality on the table. We have not figured out a clean way to learn from thumbs-up data without making the pipeline a nightmare to debug. The refund flow works but I am not sure it scales to 10x the volume without a human in the loop somewhere. Push notification fatigue is real, and B will stop working at some point.

None of this is finished. It rarely is.

If you’re building an AI product and want a second pair of eyes on the retention math, or you want help shipping the boring middle, say hi.

FREQUENTLY ASKED

Common questions

How do you justify the cost of training a model for users who don't pay?

At roughly $0.40 per LoRA training on FAL, the math works as long as your paid conversion stays above about 2% and your average revenue per paying user is in the $15-30 range. We track unit economics weekly. If FAL pricing changed or conversion dropped, we would revisit. The free preview is also a referral driver, which is hard to attribute cleanly but shows up in our signup source field.

Why route between models instead of just fine-tuning one better model?

We tried. A single model that performs well across skin tones, ages, and face shapes is a much harder training problem than three specialized models. Routing also lets us swap one model out without retraining the others. When FLUX.1-dev got a better base checkpoint, we updated one branch of the router and shipped that day. Specialization is cheaper than generalization at our scale.

Did the 48-hour refund offer get abused?

Barely. About 0.4% of users took the refund and immediately repurchased later, which we treat as a normal pattern. We do gate the offer to one use per account, tied to the original Apple receipt. The retrain option is more popular than the refund by roughly 60/40, which tells us most unhappy users have a fixable input problem, not a fundamental product objection.

What tools do you use for push notification testing?

RevenueCat for the user segments, OneSignal for delivery and A/B splits. Nothing fancy. The hard part is not the tooling, it's writing copy that does not sound like every other app's reactivation push. We write notifications in the user's voice about their content, not in our voice about our product.

How long does it take to produce a weekly themed pack?

A designer spends maybe 3 hours writing and testing prompts. We generate sample outputs across 5 reference faces, tweak the negative prompts, and ship. The JSON config goes through a normal PR review. The whole thing is cheaper than one paid acquisition campaign and the retention lift is significantly bigger.

Related posts