How to Build a Subscription Renewal Calendar for SaaS
By SimpleCalendarJS Team
Every SaaS product eventually needs a subscription renewal calendar. Once you're managing more than a handful of customers, a database table of renewal dates isn't enough — your team needs a visual timeline showing which subscriptions renew this week, which trials expire next month, and which accounts are at risk of churning. Spreadsheets break. SaaS management platforms cost thousands per month. A custom subscription renewal calendar built into your own dashboard is the middle path that scales.
The build-vs-buy decision
The obvious first move is to adopt a subscription management platform. Chargebee starts free but jumps to $599/month on the Performance plan — and real-world costs reach $3,000–$8,000/month once you factor in overage fees (0.75% of billing volume) and add-ons like revenue recognition. Recurly charges $249+/month. CloudEagle.ai and Zluri handle renewal tracking but are built for IT procurement teams managing vendor subscriptions, not for SaaS companies tracking their own customers.
These platforms earn their price when you need full billing automation, dunning workflows, and multi-currency invoicing. But if your goal is narrower — show upcoming renewals on a calendar, let customer success reps click into accounts, and trigger reminders at key intervals — you don't need a $7,000/year platform. You need a calendar component wired to your existing subscription data.
| Concern | SaaS platform (Chargebee, Recurly) | Custom calendar |
|---|---|---|
| Cost | $599–$8,000+/month | One-time library cost or free |
| Data ownership | Subscription data synced to third party | Everything stays in your database |
| Customisation | Limited to vendor UI and webhooks | Full control over views and behaviour |
| Integration | API sync with your app (often fragile) | Direct database queries |
| Time to ship | Days (if it fits your model) | Hours to days |
| Billing automation | Built-in dunning, invoicing, retries | You handle billing separately |
If billing automation is the priority, use Chargebee or Recurly. If visibility into renewal timelines is the priority, build the calendar.
Choosing a calendar library
SaaS dashboards already carry auth, analytics, charts, and navigation. Adding a heavy calendar library compounds the load. Here's how the options compare for embedding a renewal calendar:
| Library | Bundle Size (gzip) | License | Month/Week/Day Views | Dashboard Fit |
|---|---|---|---|---|
| FullCalendar | ~500 KB (full) | Free core / paid premium | Yes | Feature-rich but heavy |
| DayPilot Pro | ~100 KB+ | Per-developer ($849+) | Yes | Commercial license required |
| React Big Calendar | ~50 KB (+ React) | MIT | Yes | React-only |
| SimpleCalendarJS | ~18 KB | Free personal / license req. commercial | Yes | Lightweight, framework-agnostic |
For a dashboard widget whose job is to render coloured dots on dates and respond to clicks, ~18 KB beats ~500 KB — especially when your dashboard already loads React, a charting library, and your app bundle.
Building the renewal calendar
Step 1: Model the subscription-to-event mapping
Your database stores subscriptions. The calendar displays events. The mapping converts each subscription into something the calendar can render:
function subscriptionsToEvents(subscriptions) { const statusColors = { active: '#10b981', expiring_soon: '#f59e0b', trial: '#3b82f6', churned: '#ef4444', paused: '#6b7280', }; return subscriptions.map((sub) => ({ id: sub.id, title: `${sub.customerName} — ${sub.planName}`, start: new Date(sub.renewalDate), end: new Date(sub.renewalDate), color: statusColors[sub.status] || '#6b7280', })); }
Active subscriptions show in green, expiring-soon in amber, trials in blue, churned in red, and paused in grey. A quick glance at the calendar tells your team exactly where attention is needed — a cluster of amber dots on a single week means a wave of renewals is approaching.
Step 2: Mount the calendar in your dashboard
npm install simple-calendar-js
import SimpleCalendarJs from 'simple-calendar-js'; import 'simple-calendar-js/dist/simple-calendar-js.min.css'; const calendar = new SimpleCalendarJs('#renewal-calendar', { defaultView: 'month', locale: 'en-US', enabledViews: ['month', 'week'], fetchEvents: async (start, end) => { const res = await fetch( `/api/subscriptions?from=${start.toISOString()}&to=${end.toISOString()}` ); const subscriptions = await res.json(); return subscriptionsToEvents(subscriptions); }, onEventClick: (event) => { window.location.href = `/dashboard/customers/${event.id}`; }, onSlotClick: (date) => { console.log('No renewals on', date.toLocaleDateString()); }, });
Clicking a subscription opens the customer detail page. The fetchEvents callback fires on every calendar navigation, so the view always reflects live data. Month view gives the high-level timeline; week view zooms into busy renewal periods.
Step 3: Build the API endpoint
Your backend needs to return subscriptions within a date range. Here's a Node.js example with a SQL database:
app.get('/api/subscriptions', async (req, res) => { const { from, to } = req.query; const result = await db.query( `SELECT s.id, c.name AS customer_name, p.name AS plan_name, s.status, s.renewal_date, s.mrr FROM subscriptions s JOIN customers c ON c.id = s.customer_id JOIN plans p ON p.id = s.plan_id WHERE s.renewal_date BETWEEN $1 AND $2 ORDER BY s.renewal_date`, [from, to] ); res.json( result.rows.map((row) => ({ id: row.id, customerName: row.customer_name, planName: row.plan_name, status: row.status, renewalDate: row.renewal_date, mrr: row.mrr, })) ); });
Step 4: Flag expiring-soon subscriptions
The calendar is more useful when it proactively highlights subscriptions approaching renewal. A daily cron job (or a query in your fetchEvents callback) can flag subscriptions as expiring_soon when they enter the 30-day window:
async function flagExpiringSoon() { await db.query( `UPDATE subscriptions SET status = 'expiring_soon' WHERE status = 'active' AND renewal_date <= NOW() + INTERVAL '30 days' AND renewal_date > NOW()` ); }
This turns those calendar dots from green to amber 30 days before renewal, giving your customer success team a visual early warning. Combine this with email or Slack notifications at T-90, T-60, and T-30 days for a full renewal reminder pipeline — research shows that multi-touch reminder sequences at these intervals significantly reduce involuntary churn.
Step 5: Add MRR context to the calendar
A renewal date alone doesn't tell you the stakes. A $49/month subscription and a $4,900/month enterprise contract both show as a dot on the calendar. Add MRR to the event title so your team can prioritise:
function subscriptionsToEvents(subscriptions) { const statusColors = { active: '#10b981', expiring_soon: '#f59e0b', trial: '#3b82f6', churned: '#ef4444', paused: '#6b7280', }; return subscriptions.map((sub) => ({ id: sub.id, title: `$${sub.mrr}/mo — ${sub.customerName}`, start: new Date(sub.renewalDate), end: new Date(sub.renewalDate), color: statusColors[sub.status] || '#6b7280', })); }
Now the calendar reads like a revenue forecast. A week showing $12,400 in amber dots demands more attention than one showing $180.
Step 6: Theme the calendar for your dashboard
SaaS dashboards typically run a dark or neutral theme. Match the calendar to your existing design system with CSS custom properties:
#renewal-calendar .uc-calendar { --uc-primary: #6366f1; --uc-bg: #0f172a; --uc-border: #1e293b; --uc-text: #e2e8f0; --uc-radius: 8px; font-family: 'Inter', -apple-system, sans-serif; }
When SaaS platforms make more sense
A custom renewal calendar covers visibility — seeing what's coming and clicking into it. SaaS billing platforms cover automation — the things that happen without human intervention:
- Dunning and payment retries: About 50% of customers will need to update their payment info at some point. Chargebee and Recurly automatically retry failed charges, send card-expiration emails, and recover revenue that would otherwise churn silently
- Revenue recognition: If you need ASC 606-compliant revenue reporting, platforms like Maxio (formerly SaaSOptics + Chargify) handle deferred revenue calculations
- Multi-currency invoicing: Global SaaS products need localised invoicing, tax calculation, and currency conversion — billing platforms handle this out of the box
If your renewal calendar is the first step toward a full billing overhaul, start with the calendar to prove the concept, then evaluate whether a platform's automation features justify the $7,000+/year cost.
Summary
- SaaS billing platforms like Chargebee ($599+/month) and Recurly ($249+/month) solve billing automation but are overkill if you only need renewal visibility
- Your subscription database already has the data a calendar needs — customer name, plan, status, and renewal date — the missing piece is the visual layer
- FullCalendar (~500 KB) adds unnecessary weight to an already-heavy SaaS dashboard; SimpleCalendarJS renders the same month/week views at ~18 KB gzipped
- Colour-code subscriptions by status (active, expiring, trial, churned) and include MRR in event titles so the calendar doubles as a revenue forecast
- Add a daily job to flag subscriptions entering the 30-day renewal window and trigger multi-touch reminders at T-90, T-60, and T-30 to reduce involuntary churn
Sources & Further Reading
Research & References
- Stay Ahead with a Smarter SaaS Calendar for Renewals — CloudEagle.ai
- 9 Best Subscription Management Tools in 2026 to Cut SaaS Waste — CloudEagle.ai
- Chargebee Pricing 2026: Plans, Overage Fees, and Real Monthly Costs — Swell
- 12 Subscription Management Tools Worth Comparing in 2026 — Zluri
- 5 Proven Ways to Reduce Churn During SaaS Renewals — Ratio
- Subscription Renewal Reminder Emails: The Complete Guide — Sequenzy
- SaaS Renewal Best Practices: A Complete Guide — HubiFi
- Renewal Tracking Software for Subscriptions, Contracts & SaaS — KnowRenewals
Image Credits
- Cover: A Laptop Showing Graphs — Pexels
All images free to use under the Pexels License.
Frequently Asked Questions
What is a subscription renewal calendar?
A subscription renewal calendar is a visual dashboard component that plots every customer subscription on a timeline by its renewal date. It gives SaaS teams a scannable view of upcoming renewals, expiring trials, and at-risk accounts — replacing spreadsheets and manual tracking with an interactive calendar UI.
Should I build a custom renewal calendar or use a SaaS management platform?
If your app already stores subscription data (plan, status, renewal date) and you want the calendar embedded in your own admin dashboard, building a custom calendar with a lightweight JavaScript library is cheaper and gives you full control. Platforms like Chargebee ($599+/month) or CloudEagle make sense when you need billing automation, dunning, and revenue recognition across dozens of vendors.
How do I colour-code subscriptions by status on a calendar?
Map each subscription status to a colour when converting subscription records to calendar events. For example, active subscriptions in green, expiring-soon in amber, churned in red, and trial accounts in blue. Pass the colour as part of each event object so the calendar renders them visually distinct.
Can I add renewal reminders at 90, 60, and 30 days before expiry?
Yes. Query your subscriptions database for records whose renewal date falls within each reminder window, then create calendar events (or trigger emails and Slack notifications) at those intervals. A scheduled job running daily can check for subscriptions entering each window and fire the appropriate reminder.
What JavaScript calendar library is best for a SaaS subscription dashboard?
It depends on your stack and performance budget. FullCalendar (~500 KB full bundle) has the most features but adds significant weight to an already-heavy SaaS dashboard. SimpleCalendarJS (~18 KB gzipped) provides month, week, and day views with event rendering and click handlers — enough for a renewal calendar without the overhead.
Add a calendar to your app today
Free for personal projects. $49/year or $199 lifetime per commercial project.
