Scan a user's Gmail to find upcoming subscription renewals, recurring payments, and billing deadlines. Use this skill whenever the user asks about their subscriptions, recurring charges, upcoming renewals, payment schedules, billing timelines, or wants to audit what services they're paying for. Also trigger when users say things like 'what am I subscribed to', 'when is my next bill', 'show me my recurring payments', 'subscription audit', 'what's renewing soon', 'am I still paying for X', or any variation involving tracking, managing, or reviewing subscription costs from their email. This skill requires the Gmail MCP connector to be enabled.
Surface upcoming subscription renewals and payment timelines by scanning the user's Gmail inbox.
This skill searches Gmail for subscription-related emails (receipts, renewal notices, payment confirmations, trial expiry alerts, billing reminders) from the last 30 days, extracts structured data, and presents it as an interactive React artifact with a downloadable spreadsheet.
The primary goal is to surface upcoming renewals and payment timelines — what's due soon and what the user needs to act on. Renewals projected far into the future (3–12 months out) are still shown but visually deprioritized so the user's attention goes to what's imminent.
Run multiple targeted Gmail searches to catch different types of subscription communications. Use with these queries, scoped to the last 30 days using (calculate 30 days before today's date):
Gmail:gmail_search_messagesafter:YYYY/M/DRun all of these searches (each with maxResults: 50):
"subscription renewal" OR "subscription confirmed" OR "your subscription" after:YYYY/M/D"payment receipt" OR "payment confirmation" OR "payment processed" after:YYYY/M/D"billing statement" OR "invoice" OR "your bill is ready" after:YYYY/M/D"trial ending" OR "trial expires" OR "trial will end" OR "free trial" after:YYYY/M/D"auto-renewal" OR "auto-renew" OR "will be charged" OR "upcoming charge" after:YYYY/M/D"membership renewal" OR "plan renewal" OR "renews on" after:YYYY/M/Dsubject:(receipt OR invoice OR payment OR renewal OR subscription) after:YYYY/M/DDeduplicate results by messageId across all searches before proceeding.
False positive filtering: Before reading the full message, do a quick triage on the snippet and sender:
This filtering step is important because broad keyword searches will return many false positives from newsletters and marketing emails. Focus on emails where a financial transaction actually occurred or is about to occur.
For each unique message found, use Gmail:gmail_read_message to get the full content. Important: Some billing emails (especially from Razorpay, Stripe) have rich data in the snippet field but a minimal plain-text body. Always check BOTH the snippet and body for data extraction — the snippet often contains the most useful structured information (amounts, dates, plan names) that may be stripped from the body. Extract the following fields from each email:
| Field | What to look for |
|---|---|
| Service Name | Sender name, brand name in subject/body (e.g., "Netflix", "Spotify", "Adobe Creative Cloud") |
| Amount | Dollar/currency amounts near keywords like "total", "charged", "amount due", "price" — include currency symbol |
| Renewal / Payment Date | Dates near "renews on", "next billing date", "due date", "will be charged on", "payment date" |
| Plan / Tier | Plan names like "Premium", "Pro", "Family", "Enterprise", "Basic", billing cycle (monthly/annual/quarterly) |
| Billing Cycle | "monthly", "annually", "yearly", "quarterly", "weekly" — infer from amount patterns if not stated |
| Cancellation Deadline | Dates near "cancel before", "cancellation deadline", "to avoid being charged", "trial ends" |
| Payment Link | URLs near "pay now", "view invoice", "manage subscription", "update payment", "view bill" — extract the href |
| Has Invoice Attachment | Note if the email has a PDF attachment (invoice, receipt) — flag it as "Invoice attached" so the user knows to check |
| Email Date | The date the email was received |
| Status | Classify as one of: upcoming, paid, trial_ending, past_due, cancelled, one_time based on email content |
Additionally, for each subscription compute and store:
days_until_renewal: integer — number of days from today to the next renewal date (negative if past due, null if unknown)urgency_tier: one of urgent (≤7 days), soon (8–30 days), upcoming (31–90 days), later (91–365 days), unknown — derived from days_until_renewalParsing guidance:
null — don't guess or hallucinate valuesYYYY-MM-DDAfter parsing all emails:
| Tier | Window | Visual Treatment |
|---|---|---|
| 🔴 Urgent | Within 7 days | Red accent, top of list, bold row |
| 🟠 Soon | 8–30 days | Orange accent, prominent placement |
| 🟡 Upcoming | 31–90 days | Yellow/amber accent, standard row |
| ⚪ Later | 91–365 days | Muted/gray text, collapsed or bottom section |
Build the output as a React (.jsx) artifact saved to /mnt/user-data/outputs/subscription-tracker.jsx.
The artifact should include:
The table should be organized into urgency sections with clear visual separation:
Section headers: "Due This Week", "Due This Month", "Next 3 Months", "Later This Year" — each section only appears if it has entries. Empty sections are hidden.
Columns (all sortable by clicking headers):
Include a "Download as Spreadsheet" button that triggers generation of the .xlsx file by calling sendPrompt('Generate the subscription spreadsheet for download').
When the user clicks "Download as Spreadsheet" or asks for a spreadsheet export, create an .xlsx file using the script at scripts/generate_xlsx.py.
Run the script with the subscription data as JSON input:
echo '<JSON_DATA>' | python3 /path/to/subscription-tracker/scripts/generate_xlsx.py /mnt/user-data/outputs/subscription-renewals.xlsx
The script expects a JSON array of subscription objects piped to stdin and outputs a formatted .xlsx file.
Then present the file to the user with present_files.