Skip to content
Swift IdeasStart a build
Swift Ideas
Start a build
Back to the work

Creator economy SaaS

Holdrate

See which paying members went quiet, and what that costs.

Holdrate landing page: 'Give them a reason to stay.' with Run free audit and See it in action buttons above a sample inactivity overview.

Editorial type and a coral accent, set on warm paper. The product preview is labelled sample data on the page itself.

Project facts

Problem
Creators on Whop only see churn after a paying member has already cancelled.
Approach
A retention tool that flags quiet paying members, shows the plan value at risk and prepares a personal check-in.
Result
Live at holdrate.app. Every paid flow was proven in Whop's payment test environment before a real card was charged.
Client
Holdrate (own product)
Where
London
Year
2026
Status
Live
Work
Web platforms, Real-time data

Our role

  • Product definition
  • Brand and interface design
  • Next.js build
  • Whop OAuth and API integration
  • Security engineering
  • Billing and webhooks
  • Transactional email
  • Test harness and sandbox verification

Built with

Next.js 16 (App Router), React 19, TypeScript (strict), PostgreSQL (Neon, London), Whop OAuth and Members API, Whop checkout and webhooks, Resend, jose, Zod 4, Vercel (lhr1) with Vercel Cron, Playwright, node:test + pg-mem

The problem

Creators on Whop see churn after it happens: a cancelled membership, a lost payment. The warning sign comes earlier, when a paying member stops opening the content. That signal exists in Whop's API but not on a creator's screen.

The product asks a creator for access to their member list, so trust is the first feature. Read-only access, encrypted keys and plainly written data rules matter more to this buyer than another chart.

It also had to be honest about money. Revenue at risk is an estimate built from plan prices, currencies and ended memberships. A number that overstates exposure would erode the trust the product depends on.

What we did

We defined the data before the interface. Inactivity is measured from the last time Whop recorded a member opening the creator's content. Never-accessed members count from their join date. Missing evidence is shown as unknown, never guessed.

The app is built in Next.js 16 and hosted in London, with a PostgreSQL database and a small set of tested modules for Whop, retention maths, encryption and email. A free audit needs only read access. Paid actions (prepared messages, return tracking and weekly digests) check the subscription with Whop on every request.

Verification ran in three layers: fast tests of the core rules against a stand-in database, a browser test lab that runs made-up communities through the real app, and Whop's payment test environment for checkout, trials, 3-D Secure card checks, refunds and first renewals.

What we considered

The decisions behind the build, with the reasoning and the evidence for each.

DataDefinitions a creator can check

Every number on the dashboard has a written rule. The rules are deliberately narrow so a creator can reconcile them with Whop without trusting us.

  • 7 days without content access is at risk; 14 days is critical; ended memberships are excluded from exposure
  • Recurring plan prices normalised to monthly; one-time and ended plans contribute nothing
  • Currencies stay separate, and discounts and tax are excluded rather than estimated
  • A manual 'returned' mark is its own record; the original Whop timestamp is preserved
  • Measures Whop content access only, not Discord or Telegram activity, and the product says so
SecuritySign-in with the fewest possible permissions

Signing in with Whop runs every standard security check on our server, and the browser never holds a Whop access token. The account key a creator connects can read members and plans, nothing else.

  • PKCE (S256) plus state and nonce checks; the signed identity token is verified with jose
  • Only an opaque session in a Secure, HttpOnly __Host- cookie reaches the browser
  • Account key scopes: member:basic:read and plan:basic:read; no wallet or balance permissions
  • Keys encrypted with AES-256-GCM, with additional authenticated data bound to the workspace
SecurityA strict rule on which scripts may run, without breaking the app

Next.js writes a few start-up scripts into the page itself, which usually pushes teams to switch that browser protection off (unsafe-inline). Holdrate generates a nonce per request instead, so only the framework's own scripts run.

  • script-src 'self' 'nonce-…' 'strict-dynamic'; object-src 'none'; frame-ancestors 'none'
  • Pages render at request time so each response carries its own nonce
  • Route handlers keep CSRF and Origin checks, request size limits, no-store responses and rate limits
  • Tenant-scoped queries throughout, with cross-account responses covered by tests
InfrastructureRefreshes that never lose the last good report

An import can fail halfway through a large community. A half-written report would show wrong numbers with confidence, so the saved report is replaced only by a complete sync.

  • Atomic report replacement; failed or superseded refreshes keep the last successful report
  • A failed refresh leaves a persistent stale-report warning until a retry succeeds
  • Hourly Vercel cron, pinned to lhr1 beside the London database, refreshes subscribed workspaces in bounded batches
  • Whop requests pin Api-Version-Date 2026-09-15
ContentEmail that cannot send twice

Weekly digests are opt-in and go only to the owner's verified address. Retries are safe by construction rather than by luck.

  • Delivery records plus deterministic Resend Idempotency-Key headers
  • Sent on Sundays after 09:00 UTC; ambiguous deliveries outside the deduplication window go to review
  • A saved report is never retried to a superseded recipient address
  • One-click unsubscribe with a confirmation step
ShowHide the other 5 decisions
ReleaseBilling checked against the real provider

Paid access does not depend on a background notice from Whop arriving. Each paid mutation asks Whop directly, and only active or trialing memberships pass. Webhooks only invalidate caches.

  • Sandbox verified: success card, decline, seven-day trial, 3-D Secure challenge and full refund
  • First renewals after one-day trials: a success card renewed as active; a failing card went past_due, which the entitlement check refuses
  • Signed webhooks accepted in both Whop payload shapes, with replays deduplicated in a webhook_events ledger
  • Sandbox receiver deployed as a separate Vercel project with its own database; production was never touched
TestingA test lab with made-up communities

Real creator data was not available for testing, so we built a lab that runs made-up Whop data through the real client, pagination, import logic, API and React UI.

  • Datasets of 0, 24, 500 or 2,500 members, backed by in-memory PostgreSQL
  • Injected failures: permissions, rate limits, interrupted pages, cursor loops, missing plans and cross-account responses
  • 38 automated tests, including five Playwright journeys that run in about 16 seconds
  • A 2,500-member import produces 25 pages with correct global totals; the 320px layout has no overflow
DesignEditorial, warm and deliberately unlike a dashboard template

The buyer is a community owner, not an analyst. Warm paper, navy ink and a single coral action colour keep the product calm. Charts are plain HTML and SVG with visible values.

  • Paper #f7f6f2, ink #171c34, coral #ef593e for primary actions; lavender #ddd0f0 and mint #dcebcd for data states
  • Georgia for display, Arial for UI: no web-font requests, which suits a CSP of font-src 'self'
  • No charting library; every chart uses the same filtered totals as the tables beside it
  • Below 640px, member tables become cards and the side sheet fills the width
AccessibilityMotion with a firm off switch

Transitions explain state changes, then get out of the way. The reduced-motion preference removes them completely.

  • 140 ms hover, 220 ms content swap, 320 ms drawer and data transitions
  • prefers-reduced-motion disables all animation and smooth scrolling
  • Native dialog elements for focus trapping, Escape and focus return; live-region announcements for toasts
  • 2px visible focus outline with a 4px offset on every interactive element
StrategyThe demo never pretends to be the product

The public demo uses 12 fictional members and says so. The real dashboard never substitutes sample records for an empty or failed response, even when that makes a first run look sparse.

  • Demo state lives in the browser only and syncs across open tabs; it never touches production APIs or billing
  • Every marketing preview is marked 'Sample data' or 'Interactive demo' on the page
  • No invented savings, growth figures or customer endorsements anywhere in the product

Colour and type

  • Paper#F7F6F2Page background
  • Ink#171C34Text, headings and the dark report section
  • Coral#EF593EPrimary actions and the wordmark
  • Coral soft#F7C8B6At-risk value panels and the closing band
  • Lavender#DDD0F0Chart emphasis and text selection
  • Mint#DCEBCDEngaged and returned states
  • Muted#656675Secondary copy
  • Give them a reason to stay.

    GeorgiaDisplay and wordmark

    A system serif set tight at display sizes. It gives the product an editorial voice with zero font downloads.

  • Inactive 14+ days · 28 members · $1,840 estimated monthly revenue

    ArialInterface

    12 to 16px UI copy with tabular figures for metrics. Chosen for legibility at small sizes and for a strict CSP.

By the numbers

From first commit to production and verified sandbox renewals
2 days
Source: The project's commit history, 22 to 23 September 2026
Automated tests, including five full browser journeys
38
Source: Our own count of the tests in the project's test suite, September 2026
Whop sandbox payment scenarios verified end to end
7
Source: Our written record of each test payment in Whop's test environment
Members in the largest verified import, 25 pages
2,500
Source: Our recorded test results, 22 September 2026

Where it landed

Holdrate is live at holdrate.app. Sign-in, the free audit, encrypted account connection and the hourly refresh run in production, and paid flows were proven in Whop's payment test environment before any real card was charged.

The first production audit, on a Whop account with no customer members, returned zeros and said so. That is the behaviour we designed for: an empty truth over a full fiction.

The pattern transfers to any integration product: the narrowest access, written data rules, saves that complete fully or not at all, and a test-environment pass on every billing path before launch.

Start a build like this