Subscription gates, ads, and Pro tiers on a SaaS product
How LenDen balances free tier limits, Razorpay Pro subscriptions, and optional AdSense—without ads on paid workflows.
When you ship a ledger app for shopkeepers, revenue has to come from somewhere honest: subscriptions for power users, not dark patterns in the accounting flow. LenDen is built around that split—free tier for real daily use, Pro for exports and scale, and display ads only where they do not fight the job users hired the app to do.
This post is product architecture, not a pitch. It explains how we gate features, where ads belong, and why Pro subscribers should never see a banner above their khata.
Two revenue lines, one trust bar
Subscriptions answer "will this still work next month?" Ads answer "can free users subsidize hosting while we grow?" Both can coexist if you draw hard boundaries:
- Pro unlocks batch entry, CSV/PDF reports, unlimited parties, and the workflows distributors actually pay for.
- Free keeps core Given/Received entry honest—no artificial caps on recording money that already moved.
- Ads stay on marketing surfaces and optional low-intrusion placements for free accounts—not on checkout, exports, or party detail during reconciliation.
If a paying user sees an ad while fixing a wrong entry, you have already lost more than the CPM.
Feature gates belong in one context
LenDen centralizes tier logic in a subscription context derived from the user profile: tier === "pro" drives canExport, canUseBatchEntry, canAddParty past the free cap, and canUseReports. UI components ask the context; they do not re-fetch profile flags ad hoc.
That pattern keeps upgrade prompts consistent. The reports menu, batch modal, and party FAB all surface the same upgrade copy when a gate fails—users learn the rules once.
const isPro = profile?.tier === "pro";
canExport: isPro,
canAddParty: (count) => isPro || count < MAX_FREE_PARTIES,
Server routes that matter—export spans, Razorpay verification—must re-check tier. Client gates are UX; API gates are security.
Where ads load (and where they do not)
Public routes are fair game after AdSense site approval: landing, pricing, legal. The landing page already uses deferred script loading so first paint stays product-first.
Inside the authenticated app, we treat ads as optional for free users only:
- A small banner slot in the app shell—not blocking modals, not covering the keypad.
- No AdSense script on Pro sessions when we can avoid it (layout split or conditional loader).
- Never on Razorpay checkout, password reset, or onboarding migration—those are high-trust moments.
Google's policies also care about valuable content on the hostname you register. LenDen's marketing story lives on the landing page; the app is tooling. Approving lenden.satanilabs.com is a separate site review from satanilabs.com—plan accordingly.
Free tier limits that feel fair
Capping parties at five is visible early; users understand "I need Pro for more shops." Blocking exports on free is clearer than slowing the UI. We avoid bait-and-switch: free users can run today's ledger; they cannot run the distributor's month-end PDF—that is a job worth paying for.
Upgrade prompts link to pricing with Razorpay subscription plans (monthly and multi-month). Copy states what unlocks, not fear. "Pro reports" beats "Go premium now!!!" in a market where trust is the product.
Privacy and ads together
If you run GA4 and AdSense, say so in privacy policy before scripts load in production. LenDen's policy must mention Razorpay payment data and ad cookies on public pages. Portfolio site (satanilabs.com) and product site (lenden.satanilabs.com) should each describe what that hostname collects—do not copy-paste one blurb across both.
Lessons for other founder-led apps
- Pick a primary monetization. For LenDen, it is Pro. Ads are secondary weather, not the business model.
- Gate in one module, enforce on server for exports and payments.
- Map ad slots to emotional temperature—marketing cool, reconciliation hot; keep hot paths clean.
- Register each hostname in AdSense and only enable units after approval; unfilled slots are fine temporarily with on-brand placeholders.
Shipping both subscriptions and ads is not greedy if users can predict exactly what they get at each tier. Clarity is the monetization feature.