◉RORK LABJP
●EXPO — EAS Observe now records native crashes (Oct 7). On SDK 57, update to 57.0.21 or later●RORK — GPT-6.1 Sol (Sep 29) and Claude Sonnet 5.5 (Sep 28) are now in the model menu●RN 0.88 — The stable release was still unpublished on its Oct 12 target. rc.4 (Oct 7) is the newest; 0.87.1 is Latest●Q&A — Readers report expo-widgets showing a black widget in production builds only●WINDOWS — A walkthrough shows how to ship an iPhone app from Windows only, with no Mac●NEW — Three checks to run first when notifications stop arriving in Expo Go●EXPO — EAS Observe now records native crashes (Oct 7). On SDK 57, update to 57.0.21 or later●RORK — GPT-6.1 Sol (Sep 29) and Claude Sonnet 5.5 (Sep 28) are now in the model menu●RN 0.88 — The stable release was still unpublished on its Oct 12 target. rc.4 (Oct 7) is the newest; 0.87.1 is Latest●Q&A — Readers report expo-widgets showing a black widget in production builds only●WINDOWS — A walkthrough shows how to ship an iPhone app from Windows only, with no Mac●NEW — Three checks to run first when notifications stop arriving in Expo Go
Articles/Business
⟐ Business/2026-04-29Advanced

Designing a Rork App That Doesn't Get Deleted — A Solo Developer's Playbook for the First Week

Most Rork apps die in the first three days. Starting with where deletion data actually comes from (not Firebase, on iOS), here is a first-week design for D0, D1, D3 and D7 — with the code that makes each stage measurable.

Rork577Retention13Solo Development3App Operations6Onboarding8

App Store Connect has a metric called Deletions. It sits right next to installs in App Analytics, and for a long time I looked past it.

The first day I actually read it, I noticed that none of the numbers I had been tracking — star rating, crash-free rate, DAU — explained it. The rating was fine. Nothing was crashing. People were leaving quietly anyway.

Deletion is not a slow process. Apps that die, die within three days, sometimes one week. Rork makes it easy to get an app live, which is exactly why the first week tends to get skipped on the way to the next build. Shipping fast and losing them just as fast is the least satisfying way to lose in solo development.

Reducing deletions turned out not to be about adding features. It was about deciding, before launch, what the app shows during those first seven days and in what order. Starting with how to measure it.

Watch deletion timing, not the star rating

Most operations advice points at star ratings and crash rates. They are not wrong, but for a solo developer the most useful KPI is "when did the user delete the app?" Star ratings come from people who stayed. Deleters leave silently. A four-star app with no daily active users almost always has a deletion-timing problem nobody is looking at.

For the first month after launch I check three numbers every morning.

D0 deletion rate — deleted on install day (target: under 5%)
D1 deletion rate — deleted by the next day (target: under 15%)
D7 deletion rate — deleted within a week (target: under 40%)

Industry averages are much harsher than this. These are realistic thresholds for a solo developer running zero paid acquisition. If you are above these, the problem is almost never the feature set. It is the first-week design.

You cannot get deletion rate from Firebase

A quick detour into measurement reality, because plenty of write-ups say "track deletions in Firebase" and that is not accurate. The app_remove event Firebase Analytics collects automatically is Android only, and it only fires for Play Store installs. There is no iOS equivalent. No amount of digging through the dashboard will surface an iOS deletion.

In practice you approximate it from four sources:

SourceWhat you getGranularity and caveats
App Store Connect / App AnalyticsDeletionsDaily, by country and device. Only covers users who opted into sharing diagnostics, so read it as a trend line rather than a headcount
Google Play ConsoleUninstallsDaily. Not bucketed by install-date cohort, so it does not map cleanly onto D0/D1/D7
Firebase Analyticsapp_remove (Android only)Never fires on iOS. The one path to real deletion timing on Android
FCM / APNs send resultsToken invalidationA UNREGISTERED / NotRegistered response means that token is dead. A lagging deletion signal

To get something D0/D1/D7-shaped on iOS, I approximate. Store the install date locally, emit your own daily-active event, then compute "share of an install-date cohort that has not opened the app since day N" and overlay that on the daily Deletions trend from App Store Connect.

// Pin the install date on first launch and reuse it for cohort math
const INSTALL_KEY = "installed_at_iso";
 
export async function resolveInstallCohort(storage: Storage, now = new Date()) {
  let iso = await storage.getItem(INSTALL_KEY);
  if (!iso) {
    iso = now.toISOString();
    await storage.setItem(INSTALL_KEY, iso);
  }
  const installedAt = new Date(iso);
  const days = Math.floor((now.getTime() - installedAt.getTime()) / 864e5);
  return { installedAt, dayIndex: days, cohort: iso.slice(0, 10) };
}

Attach dayIndex and cohort to your active-session events and you can later ask "of the people who installed on April 29, how many were still opening it on day three?" Strictly speaking that is a churn rate, not a deletion rate — people who kept the app but stopped opening it are mixed in. But if its shape tracks the Deletions line, it is more than enough to locate where in the first week people are falling off.

One warning: wire this in before launch. Install dates cannot be reconstructed after the fact, so bolting it on later marks every existing user as unknown. I forgot once and lost three weeks of cohorts outright.

Make deletion visible before trying to reduce it. That ordering is the one thing I no longer let slip on a new app.

Count dead push tokens to catch iOS deletions — late, but real

The fourth row in that table, token invalidation, is the closest I have come to actually observing an iOS deletion. Once the app is removed, the next send to that device's APNs token comes back invalid. Through FCM, firebase-admin reports it as the error code messaging/registration-token-not-registered.

The point is to use a silent send for counting, not for reaching anyone. Once a week I push a background notification carrying nothing but content-available to every stored token, then group the errors by install-date cohort.

// Count dead tokens per install cohort with firebase-admin (weekly batch)
import { getMessaging } from "firebase-admin/messaging";
 
type TokenRow = { token: string; cohort: string }; // cohort = install date "2026-04-29"
 
export async function countDeadTokensByCohort(rows: TokenRow[]) {
  const dead = new Map<string, number>();
  const total = new Map<string, number>();
 
  for (let i = 0; i < rows.length; i += 500) { // multicast accepts at most 500 tokens per call
    const chunk = rows.slice(i, i + 500);
    const res = await getMessaging().sendEachForMulticast({
      tokens: chunk.map((r) => r.token),
      apns: {
        headers: { "apns-priority": "5", "apns-push-type": "background" },
        payload: { aps: { "content-available": 1 } },
      },
    });
    res.responses.forEach((r, idx) => {
      const c = chunk[idx].cohort;
      total.set(c, (total.get(c) ?? 0) + 1);
      if (!r.success && r.error?.code === "messaging/registration-token-not-registered") {
        dead.set(c, (dead.get(c) ?? 0) + 1);
      }
    });
  }
 
  return [...total.keys()].sort().map((c) => ({
    cohort: c,
    deadRate: Math.round(((dead.get(c) ?? 0) / total.get(c)!) * 1000) / 10, // percent
  }));
}

What this yields is not a deletion rate in the strict sense. A dead token also covers people who switched phones or restored from a backup. But it is the only signal where iOS itself says "this device no longer has the app," and when I lay it next to the cohort churn curve from the previous section, the gap between the two lines is the group who stopped opening the app yet never deleted it — a different problem, and a gentler one.

If you send through Expo's push service rather than FCM directly, the equivalent is a DeviceNotRegistered error in the push receipts. The bookkeeping is identical.

Whether this plumbing is worth it depends on the size of the app; I may be over-engineering for a brand-new one. While the user base is still small, the Deletions trend line in App Store Connect is usually enough to locate the first-week problem. I started adding this weekly batch from the second app where I had cohort tracking in place.

D0: deliver "this is for me" within 60 seconds

Apps that die on day zero share one trait — the user never had a moment in the first minute where they thought "this was made for me." Rork apps usually ship with a sharp concept, so this should be a strength. But many founders fill the first screens with feature explanations, and the user cools off.

For day zero I aim to finish three things within sixty seconds of first launch:

1. Ask exactly one question that says "I want to know about you"
2. Reflect that answer immediately on the home screen
3. Make it visible: "This is your version of the app"

The trick is one question, not three. Forms with multiple steps signal a "high effort" app and the swipe-to-delete happens within thirty seconds. One question, with the answer visibly changing the home screen, is what builds the "this is mine" moment. For a wallpaper app, ask which mood the user prefers, then open straight into a curated set in that mood.

Rork's default onboarding tends to expand into multi-step forms. That is the single biggest D0 killer. I always trim the onboarding back to one question.

Worth noting that what carries those sixty seconds is feel more than copy. Transition speed, haptics and animation timing get their own treatment in The Three Implementation Details That Decide First-Touch Feel in Rork Apps.

D1: build a reason to be remembered

Day-one deleters are people who could not find a reason to open the app again. The reason has to be designed in advance.

The temptation is to send a push notification. In my experience, push at D1 backfires. A notification on day one feels like spam to many users and triggers the delete tap. The better lever is to make the app itself look different the next day — without any notification.

For one of my apps, the first evening shows one set of screens, and the morning of the next day shows another. When the user opens the app the next morning, they instantly notice the change. Recognition is a powerful retention force; it stops the finger that was about to swipe.

// Switch the home surface based on time since install and time of day
function getMorningSurfaceForDay1(installedAt: Date, now: Date) {
  const hours = (now.getTime() - installedAt.getTime()) / 36e5;
  if (hours >= 12 && hours <= 36 && now.getHours() < 12) {
    return "morning_after_first_day";
  }
  if (hours < 12) {
    return "first_evening";
  }
  return "regular_home";
}

Tiny logic like this is what makes the app feel alive without ever pushing a notification. I prefer that approach. Notifications buy attention; experience earns it.

If you do want a notification at D1, provisional authorization lets you deliver quietly to the notification centre without ever showing a permission dialog. There is a catch — the standard Expo snippet silently undoes the provisional setting — which I wrote up in Shipping Notifications Without Asking First.

D3: surface the sense of accumulation

Day-three deleters are people who have started to feel "I've seen what this is." The countermeasure is showing the user the small things they have already built up, gently.

Pick whichever metric fits the app — wallpapers saved, minutes meditated, sketches drawn — and show it on a quiet corner of the home screen. The number itself does not matter. What matters is that the user can see it adding up.

// A soft accumulation badge — not a leaderboard, not a streak
function buildStreakBadge(actionCount: number) {
  if (actionCount === 0) return null;
  if (actionCount < 10) return { label: `${actionCount} starts`, tone: "soft" };
  if (actionCount < 50) return { label: `${actionCount} kept going`, tone: "warm" };
  return { label: `${actionCount} stacking up`, tone: "deep" };
}

Avoid gamified prompts here. "Reach level 3 in two more sessions!" tends to clash with the calm, considered tone most Rork apps aim for. Soft acknowledgement of effort is enough.

D7: announce that the real version starts now

Users who survive to day seven are no longer prospects — they are nearly your real users. Most apps do nothing here, just keep serving the same feature set. I would argue this is the moment to flip a small switch labelled "the real app starts now."

Concretely: a feature, theme, or setting that becomes available only after a week of use. Frame it as an unlock — "you are no longer a new user; this is yours" — rather than as a power-user feature.

function getUnlockedFeatures(daysSinceInstall: number) {
  const features = ["basic"];
  if (daysSinceInstall >= 1) features.push("personal");
  if (daysSinceInstall >= 3) features.push("history");
  if (daysSinceInstall >= 7) features.push("advanced_filters");
  if (daysSinceInstall >= 30) features.push("custom_themes");
  return features;
}

Two benefits come out of progressive disclosure. First, the cognitive load of the first session drops sharply. Second, the app keeps feeling like it is responding to the user as time passes. Rork apps usually carry a lean feature set, which actually pairs perfectly with a paced unlock.

Catch the signals that come before deletion

Users almost never delete without warning. There are three signals worth wiring up:

First, a sudden drop in launch frequency — for example, "five of the last seven days, then two days of nothing." That is a precursor.

Second, a spike in time spent on the settings screen. People who linger in settings are looking for the "delete data" or "turn off notifications" controls.

Third, an uptick in opening the in-app help or contact form. Something is wrong, and they are deciding whether to put up with it.

Wire these as Firebase events and, if the threshold is crossed, show a quiet in-app thank-you message. Not a notification — only the user who is currently in the app sees it. I have seen this pattern shave a few percentage points off deletion in the right circumstances.

Don't try to win deleters back

A principle I hold strongly as a solo developer: do not chase users who already deleted the app, with email or retargeting ads or anything else. The arithmetic does not work.

Two reasons. First, deleters made a judgement that this app was not for them, and most of the time that judgement was sound. Second, win-back budget is better spent on organic improvements that bring new users who actually fit the product.

Reducing deletions is the inverse of chasing churn. Polish the experience for the people still here. That, more than any clever re-engagement campaign, is what compounds for a solo developer.

Growing the value of the users who did stay is a separate problem from the first week. For the long-tail side — Day 1 onward retention and LTV — see User Retention & LTV Maximization for Rork Apps.

The smallest next step

Tomorrow, uninstall your own app and reinstall it from the store. Notice what the app shows you in the first sixty seconds, the next morning, and the third morning. Did "this is for me" land within a minute? Did the app feel different on day two? Did the third day acknowledge anything you had built up? Wherever the answer is no — that is where users are deleting.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $15 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⟐ Business2026-04-25
How I Push a Rork-Built App Toward $700/Month — A Field Guide to Pricing Tests, Retention, and Churn Defense
A premium playbook for taking a Rork-built app to roughly $700/month in revenue, focused on pricing tests, retention engineering, and churn defense. Distilled from 12 years of running indie apps in parallel — what actually moved revenue, what didn't, with realistic numbers and code.
⟐ Business2026-04-25
Rork AI App Builder Review 2026: What 30+ Apps Taught Me About Where It Wins and Where It Doesn't
Rork is less flashy than the marketing videos suggest, but more dependable than I expected. After building 30+ apps with it as a solo developer, here is an honest take on the territory it owns and the territory you should still write yourself.
⟐ Business2026-04-22
Operating Rork Apps for Monthly Recurring Revenue: Updates, Churn, and Lineup Strategy
An iOS app cannot intercept the moment a user cancels. Detecting auto-renew-off, killing involuntary churn with billing grace periods, and measuring cohort retention the same way every month — the operations work behind monthly revenue in a Rork app.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links