Somewhere this month, a small business owner paid for a SaaS tool they stopped using in March. A gym membership they forgot to cancel. A domain that auto-renewed for three years at a price they didn't check.
I saw this exact pain thread on r/smallbusiness: "I just found out I've been paying $189/month for software we haven't opened since February. Any tool that catches this?" The comments were a graveyard of the same story — every reply was a different forgotten subscription.
The problem isn't that people are careless. It's that calendar reminders don't understand contracts. "Renewal on Sept 1" and "cancel by Aug 2 to avoid it" are two different dates, and most of us only write down one of them.
Why calendar reminders fail
A renewal contract has at least four moving parts:
- Start date — when the term begins
- Term length — 1 month, 12 months, auto-renewing
- Auto-renew switch — is it on by default? (Almost always yes)
- Cancellation window — "notify 30 days before renewal" means the real deadline is before the deadline
Most people track only the renewal date. If you track "renewal = Sept 1" but the contract requires 30 days notice, your calendar pings you on Sept 1 — the exact day you can no longer cancel. The reminder is a trap.
The fix is to track the cancellation deadline, not the renewal date, and to compute it automatically.
The spreadsheet that stops it
Here's the setup I built (and it runs on Google Sheets or Excel, zero cost):
Sheet 1: Contracts. One row per contract:
| Contract | Vendor | Monthly $ | Term | Auto-renew | Renewal date | Cancel by | Status |
|---|---|---|---|---|---|---|---|
| CNT-001 | Zoho | 12 | 12mo | Yes | 2026-09-01 | 2026-08-02 | ⚠ RENEW NOW |
The key formulas (Excel/Sheets compatible):
// Renewal date: start date + term
=EDATE(C2, D2)
// Cancellation deadline: renewal minus notice window (e.g. 30 days)
=EDATE(F2, -1)
// Status: automatic four-state judgment
=IF(TODAY() > F2, "EXPIRED",
IF(TODAY() >= G2, "⚠ RENEW NOW",
IF(TODAY() >= EDATE(G2, -1), "Renew soon", "Active")))
With conditional formatting (red/yellow/green), the sheet becomes a dashboard you can read in two seconds: green = fine, yellow = decide this week, red = act today.
Step 2: email alerts (the part that actually saves money)
A spreadsheet only works if someone opens it. The reliable version sends you an email before the cancellation window opens — that's the Google Apps Script part:
// Runs daily via time trigger; checks each contract
function dailyCheck() {
const sheet = SpreadsheetApp.getActive().getSheetByName("Contracts");
const rows = sheet.getDataRange().getValues();
const today = new Date();
for (let i = 1; i < rows.length; i++) {
const [name, , , , , , cancelBy, status] = rows[i];
const daysLeft = Math.round((new Date(cancelBy) - today) / 86400000);
if (daysLeft >= 0 && daysLeft <= 30) {
MailApp.sendEmail(Session.getActiveUser().getEmail(),
`⚠ ${name} renewal in ${daysLeft} days`,
`Cancel by ${cancelBy} or you're locked in for another term.`);
}
}
}
Set a daily trigger, and now the sheet chases you instead of the other way around. One email a day, only for contracts that actually need a decision.
The audit that pays for itself
The first run of this template usually finds something. In my test data, CNT-001 (a 12-month contract at $12/mo with a 30-day notice clause) had already passed its cancellation deadline — status correctly flagged RENEW NOW, 30 days before renewal. That single catch pays for years of spreadsheet maintenance.
For a solo founder or small team, the math is brutally simple: one missed cancellation = one month (or one year) of a bill you didn't want. The spreadsheet takes 15 minutes to set up and the only ongoing cost is reading one email per day.
I wrote up the full template (contracts table, formulas, the Apps Script with a test run, plus a version that works in plain Excel for people who avoid Google) — it's part of the small-business template pack I document at AgentChip. The blog posts there are free; the templates are cheap one-time downloads. Your future self will thank you when September rolls around.
Originally published on the AgentChip blog.
Top comments (0)