A Ruby script that monitors a Shopify store for product price/availability changes and collection updates, running on a schedule via GitHub Actions. Notifications are sent to Telegram.
Built on top of the showroom gem for unauthenticated access to Shopify's public JSON API.
- Product monitoring — track a list of products by handle, get notified when price or availability changes
- Collection monitoring — track a collection, get notified when products are added/removed or when price/availability changes
- Similar products — weekly digest of similar products for each tracked handle
- Telegram bot commands — add products or inspect config directly from Telegram without touching the repo
- State persistence — stores a JSON report as a GitHub Actions artifact, compared against the next run to detect changes
- Rate limiting — configurable delay between API requests to avoid hitting Shopify's rate limits
- Telegram notifications — Markdown-formatted messages with product details, price diffs, and availability changes
- Ruby >= 3.3
- A Telegram bot token (create one via BotFather)
- A Telegram chat ID to send notifications to
git clone https://github.com/01max/shopify_shelf_monitor.git
cd shopify_shelf_monitor
bundle install
cp .env.example .env # fill in Telegram credentials
cp config.yml.example config.yml # fill in your watchesRun the product check:
bundle exec ruby check.rbForce a notification even if nothing changed:
FORCE_NOTIFY=true bundle exec ruby check.rb- Push the repository to GitHub
- Add the following secrets in Settings → Secrets and variables → Actions:
| Secret | Description |
|---|---|
TELEGRAM_BOT_TOKEN |
Your Telegram bot token |
TELEGRAM_DEFAULT_CHAT_ID |
Default chat ID for notifications and authorized command source |
SHELF_MONITOR_CONFIG |
Contents of your config.yml (used as fallback if no artifact exists) |
Four workflows run on schedule:
| Workflow | Schedule | What it does |
|---|---|---|
check.yml |
Every 4 hours | Checks product watches for price/availability changes |
check_collections.yml |
Mondays at 6 UTC | Checks collection watches |
check_similar.yml |
Tuesdays at 6 UTC | Sends a similar-products digest for each product watch |
user_command.yml |
On repository_dispatch |
Processes Telegram bot commands via webhook (instant) |
All workflows can also be triggered manually from the Actions tab. Product and collection checks accept a force_notify flag.
Each workflow auto-disables after 3 consecutive failures to avoid silent breakage.
Config persistence: when a /add command modifies config.yml, the updated file is uploaded as a config artifact (from check.yml). Subsequent workflow runs restore it before falling back to the SHELF_MONITOR_CONFIG secret.
Commands are sent from the authorized chat and processed instantly via a Cloudflare Worker webhook. See 01max/telegram-gh-action-dispatcher for deployment and setup of the worker.
Sends the current config.yml back as a code block.
Extracts the product handle from a Shopify product URL and appends it to a products watch.
/add https://my-store.myshopify.com/products/air-max-95
If your config has more than one products watch, pass the key explicitly:
/add https://my-store.myshopify.com/products/air-max-95 favorite_sneakers
Each top-level key in config.yml defines a watch. Two types are supported:
Monitors individual products by handle. Also used for the similar-products digest.
favorite_sneakers:
type: products
store: my-store.myshopify.com
handles:
- air-max-90
- ultraboost-22
rate_limit_ms: 500 # optional, default 500ms between API calls
telegram_chat_id: "123456789" # optional, overrides TELEGRAM_DEFAULT_CHAT_IDMonitors all products in a collection. Detects new/removed products in addition to price and availability changes.
new_arrivals:
type: collection
store: my-store.myshopify.com
handle: new-arrivals
rate_limit_ms: 600Run the tests:
bundle exec rspecRun the linter:
bundle exec rubocopThis project is licensed under GPL-3.0-or-later.