Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ShelfSignal

Watch the BoardGameGeek marketplace for the games on your wishlist and get a push notification the moment an offer drops below the price you set.

Runs entirely on GitHub — Pages for the UI, Actions for the checks, your repository for the data. Or entirely on your own machine with one command. No server, no database, no paid service.

Deutsche Anleitung: README.de.md

BGG wishlists ──▶ GitHub Actions (every 3 h) ──▶ marketplace check ──▶ ntfy push
                          │
                          └──▶ data/*.json ──▶ GitHub Pages UI (set your limits)

What it does

  • Several BGG accounts side by side, each with its own ntfy topic.
  • Public wishlists are reloaded automatically and diffed — games added since the last refresh are marked NEW in the UI and can trigger a notification.
  • One price limit per game and per user — the same game can have a different limit for each account.
  • BGG wishlist plus your own list. Add any game by pasting its BGG link, and hide wishlist games you do not care about. Both kinds behave identically: price limit, alarm toggle, best price, notification. Your BGG wishlist itself is never touched — the XML API can only read.
  • Marketplace checks on a schedule (every 3 hours by default) and on demand via the Check now button.
  • No duplicate alerts: every marketplace listing is remembered by its BGG product id, so you hear about each offer exactly once.
  • Multi-currency: offers are converted to your base currency with live rates (frankfurter.app, no key needed) before they are compared to your limit.
  • UI in 8 languages (DE, EN, FR, ES, IT, NL, PL, PT) — notifications too.
  • Dark mode by default, light theme included, works on phones.

Quick start

Everything below needs Python 3.9+ and nothing else — no pip install, no build step, no account except the ones you already have.

python scripts/run.py setup     # asks 4 questions, writes the config
python scripts/serve.py --open  # the UI, on your machine
python scripts/run.py github    # optional: put it on GitHub, fully configured

setup collects your BGG token, your BGG account names, a currency and a language, and generates unguessable ntfy topics for you. github creates the repository, switches on the workflow permissions and GitHub Pages, uploads the secrets and starts the first run — it needs the GitHub CLI and asks before it creates anything.

The web UI has a setup panel that tells you what is still missing, and the Check now button runs the same job the schedule runs.

Doing it by hand on GitHub

  1. Get a BGG application token. The BGG XML API is no longer anonymous — every request needs an Authorization: Bearer … header, and without it the API answers 401 Unauthorized.

    • Go to https://boardgamegeek.com/applications (logged in) and create an application. A non-commercial licence is free; if you keep the Ko-fi link in the footer, pick commercial / donations only instead — BGG says that one is usually free too. See LEGAL.md.
    • Approval can take a week or more. Start here, then come back.
    • Once it is approved, open the same page and click "Tokens" next to your application to create one. It looks like e3f8c3ff-9926-4efc-863c-3b92acda4d32.
    • The same page has a "Usage" link to watch your request volume.

    The token goes into the BGG_TOKEN secret in step 5. Full policy: Using the XML API.

  2. Fork this repository (or use it as a template).

  3. Settings → Actions → General → Workflow permissions: select Read and write permissions. The check workflow commits the refreshed data back into the repository.

  4. Settings → Pages → Build and deployment → Source: GitHub Actions.

  5. Add the secrets (Settings → Secrets and variables → Actions): at least BGG_TOKEN, plus one NTFY_TOPIC_<USERNAME> per account.

  6. Edit config/users.json — put your BGG usernames in and pick an ntfy topic for each one:

    {
      "users": [
        {
          "username": "your_bgg_name",
          "enabled": true,
          "color": "#7c5cff",
          "lang": "en",
          "ntfy_topic": "${NTFY_TOPIC_YOUR_BGG_NAME:-shelfsignal-pick-something-long}"
        }
      ]
    }

    A topic is a password in disguise: anyone who knows it can read your notifications. Either use a long random name, or keep it in a secret (see below) — ${NTFY_TOPIC_X:-fallback} reads the secret NTFY_TOPIC_X and only falls back to the literal value if the secret is missing.

  7. Install the ntfy app (Android / iOS / web) and subscribe to that topic.

  8. Actions → Check prices → Run workflow. The first run fills data/wishlists.json and data/market.json and deploys the page.

  9. Open https://<your-name>.github.io/<repo>/ and set your price limits.

Secrets

Settings → Secrets and variables → Actions → New repository secret

Secret Needed? What for
BGG_TOKEN required Application token for the BGG XML API. Without it every request fails with 401. Register here.
NTFY_TOPIC_<USERNAME> recommended Keeps the ntfy topic out of the public repo. Uppercase the BGG name, replace - with _.
NTFY_TOKEN only for protected topics tk_… access token for a self-hosted or reserved ntfy topic.
BGG_COOKIE almost never A BGG session cookie, if you want the API to see you as logged in.

Every repository secret is available to the config files as ${SECRET_NAME}, so you can move any value out of the repo without editing the workflow.

Editing from the published page

GitHub Pages is static, so the UI needs a token to write your limits back:

  1. Create a fine-grained personal access token with access to only this repository and these permissions: Contents: Read and write, Actions: Read and write.
  2. Open the page → gear icon → paste the token → Save.

The token is kept in your browser's localStorage and is only ever sent to api.github.com. Without a token the page still works — it is simply read-only.

Running it locally

Python 3.9+ and nothing else (standard library only).

git clone https://github.com/<you>/shelfsignal
cd shelfsignal
python scripts/serve.py --open

That serves the UI on http://127.0.0.1:8777 and writes your changes straight into config/alerts.json — no GitHub account needed. The Check now button runs the same script the workflow runs, with a live log.

You still need the BGG application token. Paste it into the settings dialog (it lands in config/secrets.local.json, which is git-ignored), or export it:

export BGG_TOKEN=your-token        # Windows: $env:BGG_TOKEN = "your-token"

Command line, same thing without the UI:

python scripts/run.py all          # refresh wishlists + check the marketplace
python scripts/run.py refresh      # wishlists only
python scripts/run.py check        # marketplace only
python scripts/run.py all --dry-run  # do everything, send nothing
python scripts/run.py doctor       # is my configuration sane?

To keep it running unattended on your own machine, put python scripts/run.py all in cron (Linux/macOS) or the Task Scheduler (Windows) — the GitHub workflow is optional.

Repository layout

config/users.json      BGG accounts + ntfy topic per account
config/settings.json   currencies, conditions, limits, rate limiting
config/alerts.json     your price limits (written by the UI)
data/wishlists.json    the fetched wishlists (+ first_seen per game)
data/market.json       the latest marketplace offers per game
data/state.json        which listings were already announced
scripts/               the whole backend, standard library only
web/                   the UI (vanilla JS modules, no build step)
.github/workflows/     check every 3 h, deploy Pages, validate

Full configuration reference: docs/CONFIG.md.

Does BoardGameGeek not do this already?

Partly, and that is worth knowing before you set this up.

  • Find My Wants (Bazaar → GeekMarket Browse) filters the marketplace by the games you flagged "want to buy". It is a page you visit, not an alert.
  • BGG's subscription system can tell you about marketplace activity for a game you subscribed to — per game, subscribed by hand, and it lands in your BGG subscription feed or an email digest.

What neither does, and what this tool is for: a price limit. BGG tells you that a copy is listed; this tells you only when one is listed below the price you set, converted into your currency, pushed to your phone, once per listing, across several accounts, for your whole wishlist at once — including games you add later.

If you only track two or three games and do not care what they cost, BGG's own subscriptions are less work. Requests for real marketplace alerts run through the BGG forums from 2012 onward, which is why this exists.

Notes and limits

  • The BGG token is not optional. python scripts/run.py doctor tells you whether one is configured, and every 401 from BGG points back at this.
  • BGG is rate limited and answers a cold collection request with "please wait" — the client backs off and retries, so a run takes a minute or two. Be gentle with the schedule; every 3 hours is already friendly.
  • The marketplace check covers up to market_max_games games per run (400 by default), games with an armed alert first.
  • The XML API does not expose the seller's country, so there is no country filter. exclude_note_keywords lets you drop offers whose note contains certain words (for example "local pickup").
  • The scheduled workflow commits data on every run. If the history ever bothers you, squash it — nothing depends on it.
  • GitHub disables scheduled workflows in repositories with no activity for 60 days. A single commit (or a manual run) re-enables them.

Adding a language

Copy web/js/locales/en.js, translate the values, add the code to LANGUAGES in web/js/i18n.js, and add the same block to CATALOGUE in scripts/messages.py for the push notifications. Pull requests welcome.

Legal

The code is MIT licensed, © papertowerstudios — see LICENSE.

The data is BoardGameGeek's and stays under the BGG XML API Terms of Use: non-commercial use only (the Ko-fi link in the footer makes this a donations-only commercial registration — see LEGAL.md), BoardGameGeek must be credited as the source, the linked "Powered by BGG" logo must be shown, the data must not be modified, and it must never be used to train AI/LLM systems. This app ships the credit and the badge in its footer — please leave them in, they are a condition of using the API. Drop BGG's official artwork into web/assets/powered-by-bgg.png to replace the text badge.

Every installation registers its own token; none ships with this repo.

Not affiliated with, endorsed by, or sponsored by BoardGameGeek. The full picture, including what a public repository actually publishes: LEGAL.md.

About

Price alerts for the BoardGameGeek marketplace - set a limit per wishlist game, get a push when an offer drops below it.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages