Skip to content
Conduit

skill

skill-price-tracker

Open-source Agent Skill: track product page prices and stock, alert on drops/rises/sold-out, export CSV/JSON price curves.

samjia12/skill-price-trackercommunitylistedunreviewed

Set up

Skills are installed by placing their folder where your agent loads skills.

The download comes from github.com/samjia12/skill-price-tracker itself, not from our server, so what you get is exactly what its author published.

Install instructions come from the README

Skills do not use an MCP config. Follow the steps in the README below.

README

synced Oct 23, 2026

skill-price-tracker

Agent Skill that watches product page URLs, records price and stock snapshots, and alerts on drops, rises, and sold-out events. History can be exported as CSV or JSON price-curve data.

Use it from a CLI, from python -m price_tracker, or as a Grok / Codex-style skill via SKILL.md.

Features

  • Fetch many product URLs with per-host rate limiting, retries, and a response size cap
  • Extract price / currency / stock from JSON-LD (Product / Offer), Open Graph meta tags, and optional per-site regex selectors
  • SQLite snapshot history with successful-vs-failed fetch tracking
  • Alerts: price_drop, price_rise, sold_out, back_in_stock
  • Drop / rise thresholds by percent and / or absolute amount
  • Concurrent checks with stable URL order in the result
  • Export price curves to CSV or JSON
  • Zero runtime dependencies (Python 3.9+ standard library)

Install

git clone https://github.com/samjia12/skill-price-tracker.git
cd skill-price-tracker
python3 -m pip install -e ".[dev]"   # optional; pytest is the only extra

You can skip the install and call python3 scripts/price_tracker.py from the repo root. That script puts src/ on sys.path.

Quick start

# 1) Write a default config
python3 scripts/price_tracker.py init-config -o tracker.json

# 2) Check URLs once (creates ./price_tracker.db)
python3 scripts/price_tracker.py check \
  --url "https://shop.example/p/widget" \
  --config tracker.json \
  --format json

# 3) Poll on an interval (Ctrl+C to stop, or bound it)
python3 scripts/price_tracker.py watch -i examples/urls.txt --interval 3600 --max-runs 1

# 4) Export the curve
python3 scripts/price_tracker.py export --format json -o curve.json

Offline (no network) demos:

python3 examples/offline_check.py
python3 examples/threshold_alerts.py
python3 examples/export_price_curve.py

Usage examples

1. First check then a price drop

Input (from examples/offline_check.py, two local HTML fixtures):

https://shop.example/p/widget   # JSON-LD Offer price 19.99 USD, InStock
https://shop.example/p/mug      # og:price 12.50 EUR, instock
# second poll: widget HTML price rewritten to 14.99

Output (second run, abbreviated):

{
  "snapshots": [
    {
      "url": "https://shop.example/p/widget",
      "title": "Widget Pro",
      "price": "14.99",
      "currency": "USD",
      "in_stock": true,
      "error": null
    }
  ],
  "alerts": [
    {
      "kind": "price_drop",
      "message": "Price dropped from 19.99 USD to 14.99 USD for Widget Pro",
      "percent_change": -25.0125,
      "amount_change": "-5.00"
    }
  ],
  "rejected": []
}

2. Thresholds filter noise

Input (python3 examples/threshold_alerts.py): previous price 100.00, new price 97.00 vs 80.00, then stock flips to sold out.

Output:

any-change config, -$3: price_drop
10% and $5 config, -$3: (none)
10% and $5 config, -$20: price_drop
sold out: sold_out

A 3% dip is ignored when drop_threshold_percent is 10 and drop_threshold_amount is 5.00. A $20 / 20% drop clears both gates. Stock changes are independent of price thresholds.

3. Export a four-point curve

Input (python3 examples/export_price_curve.py): four snapshots over four days — 29.99 in stock, 27.50 in stock, 27.50 sold out, 24.00 back in stock.

Output (CSV excerpt):

url,fetched_at,title,price,currency,in_stock,http_status,error
https://shop.example/p/widget,2026-08-20T12:00:00+00:00,Widget Pro,29.99,USD,true,,
https://shop.example/p/widget,2026-08-21T12:00:00+00:00,Widget Pro,27.50,USD,true,,
https://shop.example/p/widget,2026-08-22T12:00:00+00:00,Widget Pro,27.50,USD,false,,
https://shop.example/p/widget,2026-08-23T12:00:00+00:00,Widget Pro,24.00,USD,true,,

JSON export groups those rows into one product with a points[] array (t, price, in_stock) for charting.

4. Reject bad URLs, keep the rest

Input:

python3 scripts/price_tracker.py check \
  --url "javascript:alert(1)" \
  --url "https://shop.example/p/widget" \
  --format json

Output: rejected contains the javascript URL with reason URL scheme is not allowed: javascript. The http(s) URL is still fetched. If every URL is invalid, the process exits with code 2 (EmptyInputError).

Configuration

python3 scripts/price_tracker.py init-config -o tracker.json writes every field. Common knobs:

FieldMeaningDefault
drop_threshold_percentMinimum % drop to alert0 (any drop)
drop_threshold_amountMinimum absolute dropnull
rise_threshold_percent / rise_threshold_amountSame for rises0 / null
poll_interval_secondswatch sleep between runs3600
rate_limit_per_hostRequests per second per host1.0
max_concurrentWorker threads4
max_retriesExtra attempts on 429 / 5xx / timeout3
selectorsPer-URL-pattern regexes that override JSON-LD / meta[]
db_pathSQLite fileprice_tracker.db

Selector example (see examples/config.json):

{
  "url_pattern": "shop\\.example",
  "price_regex": "data-sale=\"([0-9.]+)\"",
  "stock_regex": "data-stock=\"([^\"]+)\""
}

url_pattern is a regular expression matched against the product URL. The first capturing group of each regex is the extracted value.

CLI

CommandPurpose
checkFetch each URL once, store snapshots, print alerts
watchRepeat check every poll_interval_seconds
export --format csv|jsonDump stored history (optional --url, --since, --until)
history --url URLPrint the timeline for one product
init-config -o FILEWrite a default JSON config

Global-ish flags: --url (repeatable), --input-file / -i, --config, --db, --format.

Exit codes: 0 ok, 1 runtime / config / I/O error, 2 empty or invalid input, 130 interrupted.

How extraction works

  1. JSON-LD Product / Offer / AggregateOffer (including @graph)
  2. product:price:amount, og:title, itemprop=price, data-*price* attributes
  3. Matching selectors from config (these win when they produce a value)

Stock maps schema.org InStock / OutOfStock / SoldOut and common phrases (sold out, in stock). Pages with neither a price nor a stock signal are stored with error set and do not generate price/stock alerts.

FAQ

Does this work on JavaScript-only storefronts?
Only if the HTML still contains JSON-LD, Open Graph tags, or a regex-able string. There is no headless browser. Add a selectors rule when the markup is stable but not structured.

Will I get banned?
The default rate limit is one request per host per second, with 429 retries honoring Retry-After. Keep max_concurrent modest and obey each site's terms. This tool is for pages you are allowed to fetch.

Why is percent_change a float?
Amounts stay Decimal (serialized as strings). Percent is only used to compare against a threshold; JSON numbers are floats.

Can I point this at Amazon / Taobao / Shopify?
Shopify product pages often expose JSON-LD and work as-is. Amazon and Taobao frequently bot-check or omit offers in the raw HTML — expect error: could not extract price or stock from page unless you supply a selector and a permitted fetch path.

Where is the database?
db_path in config, or --db. It is a regular SQLite file; .gitignore already ignores *.db.

How do I run tests?
python3 -m pip install pytest && python3 -m pytest

Contributing

  1. Fork and clone; create a branch feat/... or fix/...
  2. Keep runtime deps at zero unless the feature cannot be done in stdlib
  3. Add or extend tests under tests/ (including a boundary case if you touch validation / I/O)
  4. Run python3 -m pytest — do not submit with failures
  5. English for code comments and public docs; user-facing CLI messages stay English
  6. Open a PR with a short summary, test output, and any config/CLI flag changes

Please file issues with: the URL pattern (redact secrets), the HTML excerpt you expected to parse, config JSON, and the snapshot error string.

License

MIT — see LICENSE.

↑↓ navigate openesc close