Get the FREE Ultimate OpenClaw Setup Guide →

subscription-detection

npx machina-cli add skill peerjakobsen/smartspender/subscription-detection --openclaw
Files (1)
SKILL.md
6.2 KB

Subscription Detection

Purpose

Provides rules for detecting recurring charges (subscriptions) from categorized transaction data. Identifies services the user pays for on a regular basis.

Before Detection — Check Learnings

Before applying automatic detection, read learnings/subscriptions.md:

  1. Confirmed Subscriptions — If a merchant is listed here, always flag it as a subscription (skip automatic detection)
  2. Not Subscriptions — If a merchant is listed here, never flag it as a subscription (even if it appears recurring)

Only proceed with automatic detection for merchants not found in either list.

Detection Criteria

A series of transactions qualifies as a subscription when all five criteria are met:

#CriterionRule
1Same merchantNormalized merchant name matches across transactions
2Regular frequencyConsistent interval between charges (monthly, yearly, weekly)
3Amount toleranceAmounts within ±5% of each other
4Minimum occurrencesAt least 3 transactions matching the pattern
5RecencyMost recent occurrence within the expected interval + 7 days

Frequency Detection

Determine the frequency by measuring the average interval between transactions:

FrequencyExpected IntervalTolerance
weekly7 days±2 days
monthly28–31 days±5 days
quarterly85–95 days±10 days
yearly355–375 days±15 days

If the interval doesn't match any frequency, the charges may be irregular purchases rather than a subscription.

Amount Tolerance

Allow ±5% variation in the recurring amount to account for:

  • Price adjustments
  • Currency conversion fluctuations
  • Tax changes
  • Service tier changes

Calculate: |amount_new - amount_avg| / amount_avg <= 0.05

If the amount changes by more than 5%, flag it as a potential price increase rather than disqualifying it as a subscription.

Annual Cost Calculation

Once a subscription is detected:

  • Monthly: amount × 12
  • Quarterly: amount × 4
  • Yearly: amount × 1
  • Weekly: amount × 52

Store in the annual_cost field of subscriptions.csv.

Subscription Status

StatusMeaning
activeRecurring charges detected within expected interval
pausedNo charge in the last expected interval, but not confirmed cancelled
cancelledUser explicitly cancelled via /smartspender:cancel

Examples

Netflix Detection

Given these transactions in categorized.csv:

2025-11-01  Netflix  -149.00  Abonnementer
2025-12-01  Netflix  -149.00  Abonnementer
2026-01-01  Netflix  -149.00  Abonnementer

Step 1: Group by merchant

  • Merchant "Netflix" has 3 transactions

Step 2: Check minimum occurrences

  • 3 occurrences ≥ 3 minimum — passes

Step 3: Measure intervals

  • Nov 1 → Dec 1 = 30 days
  • Dec 1 → Jan 1 = 31 days
  • Average = 30.5 days — matches monthly (28–31 days ±5 days)

Step 4: Check amount tolerance

  • All amounts are -149.00 — 0% variance — passes

Step 5: Check recency (assuming today is Feb 1, 2026)

  • Last charge: Jan 1, 2026
  • Expected next: ~Feb 1, 2026
  • Within expected interval + 7 days — passes

Result:

subscription_id: "sub-netflix-001"
merchant: Netflix
category: Streaming
amount: 149.00
frequency: monthly
annual_cost: 1788.00
first_seen: 2025-11-01
last_seen: 2026-01-01
status: active

Edge Cases

Variable Subscription Amounts

Some services (e.g., electricity, phone bills) have variable amounts:

  • If the merchant is a known subscription (from the categorization skill) AND has regular frequency, detect it even if amounts vary more than 5%
  • Store the most recent amount, not the average

Free Trial Conversions

A single charge from a service with no prior history is not a subscription yet. Wait for the minimum 3 occurrences before detecting.

Annual Subscriptions

Annual subscriptions may only have 1 occurrence within the data window. If the merchant is a known subscription service (e.g., Adobe CC annual plan), flag it as a potential subscription with frequency: yearly even with fewer than 3 occurrences.

Merged Households

If a service appears from multiple accounts (e.g., both lønkonto and budgetkonto), treat each account's charges separately. Don't merge cross-account charges into one subscription.

Stopped Subscriptions

If a previously detected subscription has no charge in the last expected interval + 7 days:

  • Change status to paused
  • Do not delete the row — the user may want to see it was detected

Learning from Corrections

When a user corrects subscription detection, record the correction in learnings/subscriptions.md:

If user says something IS a subscription (false negative):

  1. Open learnings/subscriptions.md
  2. Add a row to the "Confirmed Subscriptions" table:
    • Date: Today's date (YYYY-MM-DD)
    • Pattern: Normalized merchant pattern (e.g., *MERCHANT*)
    • Merchant: Normalized merchant name
    • Frequency: Expected frequency (monthly, yearly, etc.)
    • Note: Why this is a subscription

If user says something is NOT a subscription (false positive):

  1. Open learnings/subscriptions.md
  2. Add a row to the "Not Subscriptions" table:
    • Date: Today's date (YYYY-MM-DD)
    • Pattern: Normalized merchant pattern
    • Merchant: Normalized merchant name
    • Reason: Why this isn't a subscription (e.g., "one-time purchase", "irregular spending")

Example corrections:

## Confirmed Subscriptions
| 2026-01-15 | *HEADSPACE* | Headspace | monthly | User confirmed meditation app subscription |

## Not Subscriptions
| 2026-01-15 | *AMAZON* | Amazon | Regular purchases, not a subscription |

Related Skills

  • See skills/categorization/SKILL.md for how merchants are identified
  • See skills/data-schemas/SKILL.md for the subscriptions.csv structure
  • See learnings/subscriptions.md for user corrections to subscription detection

Source

git clone https://github.com/peerjakobsen/smartspender/blob/main/skills/subscription-detection/SKILL.mdView on GitHub

Overview

subscription-detection identifies subscriptions by analyzing categorized transactions. It uses a five-criterion rule set to flag recurring charges, assigns a status, and computes annual costs to help users understand regular payments.

How This Skill Works

Before automatic detection, check the learnings lists for confirmed and not-subscriptions. The detector then groups transactions by normalized merchant, applies five criteria (same merchant, regular frequency, amount tolerance within ±5%, minimum 3 occurrences, and recency within interval + 7 days), and assigns a frequency and status. If a merchant isn’t on the learnings lists, automatic detection proceeds and yields fields like subscription_id, merchant, frequency, amount, annual_cost, first_seen, last_seen, and status.

When to Use It

  • You want to identify services you regularly pay for from your categorized transactions
  • A merchant appears multiple times with similar amounts at regular intervals
  • You’re evaluating merchants not listed in the learnings (confirmed/not subscriptions) for automatic detection
  • You need to compute the annual_cost once a subscription is detected
  • You want to determine the subscription status (active, paused, cancelled)

Quick Start

  1. Step 1: Group transactions by normalized merchant name
  2. Step 2: Exclude merchants listed as confirmed or not-subscriptions in learnings
  3. Step 3: Run the detection to produce subscription_id, merchant, frequency, amount, annual_cost, first_seen, last_seen, and status

Best Practices

  • Normalize merchant names before attempting matches
  • Apply all five criteria: same merchant, regular frequency, amount tolerance, minimum occurrences, recency
  • Determine frequency using the average interval and map to weekly/monthly/quarterly/yearly with tolerance
  • Respect learnings: if a merchant is in confirmed or not-subscriptions lists, handle accordingly
  • Store and surface annual_cost and status for downstream analytics

Example Use Cases

  • Netflix — monthly subscription detected (amount 149.00, annual_cost 1788.00)
  • Spotify — monthly subscription detected (amount 9.99, annual_cost 119.88)
  • Gym membership — monthly subscription detected (amount 29.99, annual_cost 359.88)
  • Dropbox Plus — monthly subscription detected (amount 5.99, annual_cost 71.88)
  • Mobile plan — weekly charges detected (amount 12.00, annual_cost 624.00)

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers