◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Expo SDK 58 is out of beta as of 10/15 (beta since 09/15). Check your dependencies before upgrading●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Expo SDK 58 is out of beta as of 10/15 (beta since 09/15). Check your dependencies before upgrading●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/Business
⟐ Business/2026-07-19Advanced

When Bumping Push to Three a Day Cut Next-Week Returns — Field Notes on Measuring Notification Frequency by D7 Retention and Opt-Out Rate

The assumption that heavier push means more returns was quietly eroding my D7 retention. These are field notes on re-measuring notification frequency by install-cohort D7 and opt-out rate, and walking from three a day back to one.

retention10push-notificationcohort-analysisD7engagement

✦ Premium Article

Returns on a study-log app I built with Rork had stalled, so I turned up the push notifications. What had been one a day became three — morning, noon, night. The logic was plain: more reminders, more comebacks.

For the first few days, push-driven opens did climb. Looking at that one number on the dashboard, I was satisfied for a while. Then two weeks later, when I lined up D7 retention (the share still returning seven days after install) week by week, the line was pointing down. The cohort from the week I raised frequency had slipped from 14.2% to 9.8% on D7.

I added notifications because I wanted people back — and those notifications were speeding their exit. These are my notes on unwinding that assumption with numbers. It's a small app I run as an indie developer, but deciding frequency by cohort instead of by feel should hold at any scale.

Push-driven opens only looked like they were rising

My first stumble was watching the wrong metric. "Times someone tapped a notification to open" naturally rises somewhat when you send three times as many. More sent means more taps in absolute terms — that isn't success.

What I actually wanted was whether a user was still coming back a week later, notification or not. I should have recorded push-driven opens and organic, self-initiated opens separately from the start.

// lib/analytics.js — record opens by their trigger
// Without this split, you overrate the notifications.
 
export function trackAppOpen({ source, userId }) {
  // source: 'push' | 'organic' | 'deeplink'
  analytics.capture('app_open', {
    userId,
    source,                          // ← the lifeline for later analysis
    ts: Date.now(),
  });
}
 
Notifications.addNotificationResponseReceivedListener(() => {
  trackAppOpen({ source: 'push', userId: currentUser.id });
});
 
if (!launchedFromNotification) {
  trackAppOpen({ source: 'organic', userId: currentUser.id });
}

Once I split by source, the picture sharpened. Push-driven opens rose about 1.9x per week, while organic opens actually dropped 12%. Users I dragged back with notifications were losing the habit of opening on their own. Summed together it wasn't a gain — it was eroding D7.

Cut cohorts by install week and line up the metrics

To claim "more push made it worse," you have to compare before and after on the same ruler. I grouped users by their install week and, per cohort, lined up D1, D7, D30, and opt-out rate.

Install weekPush frequencyD1D7D30Opt-out rate
Week 1 (baseline)1/day31.4%14.2%6.1%4.3%
Week 23/day30.9%11.6%—9.7%
Week 33/day31.1%9.8%—13.1%

D1 barely moved. Frequency doesn't touch the first-day experience, which makes sense. What moved was D7 and opt-out rate. The two heavy weeks kept sliding on D7, and the share of users who revoked notification permission jumped from 4.3% to 13.1%. Once a user opts out, they never get a notification again. I was trading immediate returns for the future return channel itself.

The cohort SQL isn't hard. As long as the event log carries source, the rest is aggregation.

-- D7 retention by install week
-- installs: user_id, install_date
-- opens:    user_id, ts, source
SELECT
  date_trunc('week', i.install_date)               AS cohort_week,
  count(distinct i.user_id)                         AS installs,
  count(distinct case
    when o.ts::date = i.install_date + interval '7 day'
    then o.user_id end)                             AS d7_returned,
  round(100.0 * count(distinct case
    when o.ts::date = i.install_date + interval '7 day'
    then o.user_id end) / count(distinct i.user_id), 1) AS d7_rate
FROM installs i
LEFT JOIN opens o ON o.user_id = i.user_id
GROUP BY 1
ORDER BY 1;
✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦How to slice install cohorts by the week you changed frequency and line up D1/D7/D30 against opt-out rate
✦How to break the illusion that push-driven opens are rising while total D7 falls, by separating push opens from organic ones
✦The measured recovery from cutting three-a-day to one, and where to draw the line on which users can take more
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
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 $10 for lifetime access
View Membership →

Related Articles

⟐ Business2026-05-11
Building Fortune & Manifestation Apps with Rork — Daily Delivery Design That Survives Day Three
Fortune apps lose most users in three days. A Rork design for daily delivery, push timing, and widgets that turns the niche into a habit.
⟐ Business2026-04-11
Retention and LTV for Rork Apps — Separating the Two Numbers I Kept Confusing
Install retention and subscription retention use different denominators. Starting from the LTV miscalculation that came from mixing them, this walks through reading Day1/Day7/Day30 correctly, costing in generation credits, and catching churn signals early — from an indie developer's desk.
⟐ Business2026-10-18
When Pasting the Submission Log Didn't Fix It, Read From the First Error, Not the Last Line
When a Rork App Store submission fails and pasting the log back to Rork keeps returning the same failure: a 40-line script that pulls out the first error, and how to match it against the four causes Rork's docs list.