Skip to main content

Discogs Alert

GitHub GitHub GitHub GitHub

Customised, real-time alerting for your hard-to-find wantlist items.

vinyl icon discogs-alert enables you to configure ~real-time alerts that notify you the moment a hard-to-find release goes on sale. The project is designed to require as little effort as possible: you customise your preference once, upfront, and then sit back and wait for a notification.

vinyl icon discogs-alert enables both global and fine-grained customisation of your preferences (including price thresholds, minimum seller rating, minimum media / sleeve conditions, and countries from which you either do or don't want to receive alerts). You'll only ever get notified if a record goes on sale that really matches what you're looking for.

vinyl icon If you have suggestions or ideas, please reach out! So far I've bought more than 50 records thanks to discogs_alert and I'd love to make it useful as possible for others.

Requirements

  • Python >= 3.10

Installation & Setup

Four install paths, pick one:

Python (via pip / uv / pipx)

pip install discogs-alert

or, as an isolated command-line tool:

uv tool install discogs-alert     # or: pipx install discogs-alert

Either way you get a discogs_alert command (equivalent to python -m discogs_alert).

macOS .app (drag-install, no Python required)

Download the latest .dmg from Releases, open it, drag discogs_alert.app into /Applications. The app self-updates via Sparkle whenever a new version is published.

On first launch, macOS Gatekeeper may say "discogs_alert can't be opened because Apple cannot check it for malicious software." Right-click the app → Open → confirm; you only have to do this once.

Docker

docker pull miggleball/discogs_alert:latest
docker run -d --env-file .env miggleball/discogs_alert:latest

The container runs python -m discogs_alert as its entrypoint; pass your config via env vars (DA_DISCOGS_TOKEN, DA_LIST_ID, …) in your .env file.

From source

git clone https://github.com/michaelhball/discogs_alert
cd discogs_alert
pip install -e .

For development you'll also want pip install -e '.[menubar]' if you're on a Mac and want the menu-bar app, plus poetry install to get the dev deps (pytest, ruff, tox, etc.).

Setup

Before you can use this project, there are a few more things that need to be setup.

Discogs access token

A Discogs access token allows discogs_alert to send requests to the discogs API on your behalf, and in particular it increases the rate at which you're allowed to make requests. This token can only be used to access the music database features of the Discogs API, not the marketplace, so there is no risk that you're accidentally granting control over the buying or selling of records. You can find more information here.

To create an access token, go to your Discogs settings and click on the Developer tab. There is a button on this page to generate a new token. For now, just copy this token to your computer.

Creating your wantlist

There are two different ways you can create a wantlist: 1) by connecting to one of your existing Discogs lists, or 2) by creating a local JSON file. The first option is easier, faster, and fits within your regular Discogs workflow. Both options support the same per-release filters (price threshold, media / sleeve condition); see below for the syntax in each case.

Discogs List

Using one of your existing Discogs lists only requires that you specify the ID of the list at runtime, the process for which is outlined in the usage section below. Ideally you should set up a list specifically for this purpose, as you'll be notified the moment any of the releases in your list go on sale. This approach makes it incredibly easy to add new releases to your wantlist: simply add a release to the specified list and discogs_alert will automatically identify this and add that release to those it's searching for on the next iteration.

Per-release filters in list comments

You can put @key=value directives in a list item's comment field to set per-release filters. Any other text in the comment is ignored. Recognised keys:

  • @max=N (or @price=N) — maximum total price (in your --currency).
  • @media=... — minimum media condition (e.g. VG+, NM, M-, VERY_GOOD_PLUS).
  • @sleeve=... — minimum sleeve condition (same vocabulary).

Examples (each one is a valid comment on a list item):

@max=500
Hot one! @max=300 @media=NM
@media=VG+ @sleeve=NM @max=80

Unknown keys are ignored; malformed values are dropped with a warning so a typo on one item won't break the rest of the loop.

Local JSON

Here is an example wantlist.json file:

[
  {
    "id": 1061046,
    "display_title": "Deep² — Sphere",
    "min_media_condition": "VERY_GOOD"
  },
  {
    "id": 2247646,
    "display_title": "Charanjit Singh — Ten Ragas to a Disco Beat",
    "price_threshold": 500 
  }
]

The wantlist is a list of objects, each object representing a release. The only essential attributes are the id field, which can be found on each release's Discogs page, and the display_title, which is the name you give the release s.t. you will recognise it when you're notified.

There are a number of optional attributes that can be included for each release. The combination of all attributes applied to a given release are used as a filter, so you will only be notified if all conditions are met for a given listing item. In the above case, the user is looking for any VERY_GOOD or higher copies of the Deep² release, with no maximum price (e.g. an example scenario here is that there are currently no copies on the market, and the user wants to be notified as soon as one goes on sale). For the Charanjit Singh release, the user is looking for any copies on sale for less than €500. NB: the currency is determined later, at runtime. This is outlined in the usage section below.

Remember that all criteria for restricting your alerts also have global values, the setting of which is discussed in usage). This means that if you want the same filters for most releases you do not need to specify them for every single release in your wantlist.json. You can set the values once globally (when you run the program), and then set only those per-release values that differ from the global settings. Any filters specified in your wantlist.json will override the global values.

The possible optional filters are as follows:

  • price_threshold: maximum allowable price (excluding shipping)
  • min_media_condition: minimum allowable media condition (one of 'POOR', 'FAIR', 'GOOD', 'GOOD_PLUS', 'VERY_GOOD', 'VERY_GOOD_PLUS', 'NEAR_MINT', or 'MINT')
  • min_sleeve_condition: minimum allowable sleeve condition (one of 'POOR', 'FAIR', 'GOOD', 'GOOD_PLUS', 'VERY_GOOD', 'VERY_GOOD_PLUS', 'NEAR_MINT', or 'MINT')

Alerting

discogs_alert ships with three built-in alerters. Pick the one whose setup matches what you have on your phone — they all do the same job (one notification per matching listing). ntfy.sh is the recommended default because it has the least setup and no account dependencies.

Configuration goes in ~/.discogs_alert/config.toml (see examples/config.example.toml for the full schema). The [alerter] section selects which one and provides its credentials.

ntfy.sh (recommended — no account, no token)

ntfy.sh is the easiest alerter to set up. Pick a random hard-to-guess topic name (anyone with the topic name can read your notifications) and subscribe to that topic from the iOS, Android, desktop, or web app. Then in your config.toml:

[alerter]
type = "NTFY"
[alerter.ntfy]
topic = "your-secret-topic-here"

For privacy / reliability you can self-host ntfy: add server = "https://ntfy.example.com" (and optionally token = "..." if your server requires auth).

Pushbullet

Create an account at pushbullet.com and install the app on the device(s) where you want notifications. Then create an access token from your settings page. Configure:

[alerter]
type = "PUSHBULLET"
[alerter.pushbullet]
token = "..."

⚠️ Open the Pushbullet app at least once a month. If you don't, Pushbullet's API silently 401s requests because it considers the account dormant — your alerts will go nowhere with no error visible from discogs_alert's side.

Telegram

To use Telegram you first need to create a custom bot. Easiest path is via @BotFather:

  1. Open Telegram on your phone, search for @BotFather, send /start then /newbot. Pick a name + username. BotFather replies with a bot token (looks like 123456789:ABC-…).
  2. Search for your new bot (by the username you chose) and send it /start (any message works).
  3. In a browser, open https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates. Find the "chat":{"id": …} field — that number is your chat_id.

Then configure:

[alerter]
type = "TELEGRAM"
[alerter.telegram]
token = "..."
chat_id = "..."

Gmail

Sends each alert as a plain-text email via Gmail SMTP. Setup:

  1. Make sure 2-Step Verification is on for your Google account (https://myaccount.google.com/security). Gmail SMTP requires it.
  2. Generate an app password at https://myaccount.google.com/apppasswords — give it a name like discogs_alert, copy the 16-character value.

Then configure:

[alerter]
type = "GMAIL"
[alerter.gmail]
user = "you@gmail.com"           # also the From: address
app_password = "xxxx xxxx xxxx xxxx"
to = "you@gmail.com"             # where alerts get delivered

⚠️ App password, not your regular Gmail password. Gmail stopped accepting the latter for SMTP in 2022.

Adding more alerters

New alerters go in-tree as a PR: subclass discogs_alert.alert.base.Alerter, implement send_alert(title, body) -> bool, drop a file under discogs_alert/alert/, register it in both _BUILTIN_ALERTERS (in alert/__init__.py) and [tool.poetry.plugins."discogs_alert.alerters"] (in pyproject.toml). The built-in alerters are short — copy the closest one to whatever you're shipping (e.g. start from ntfy.py for a plain HTTP POST, or gmail.py for SMTP).

Usage

discogs_alert can be run as a Python process or as a Docker container. Either way, the service polls your wantlist on a schedule, checks each release on the Discogs marketplace, and sends you a notification if any release (satisfying your filters) is for sale. Leave it running to be most effective.

Configuration lives in ~/.discogs_alert/config.toml (or wherever --config points). See examples/config.example.toml for the full schema. Any field can be overridden by a DA_* environment variable — handy for Docker / launchd / CI without committing secrets.

Python

$ cp examples/config.example.toml ~/.discogs_alert/config.toml
$ $EDITOR ~/.discogs_alert/config.toml   # fill in your token, list_id, alerter
$ discogs_alert                          # or: python -m discogs_alert

A few CLI helpers exist for debugging:

  • -c/--config <path> — point at a non-default config file.
  • -O/--once — run the loop once and exit (use with cron / launchd / systemd-timer).
  • -V/--verbose — DEBUG-level logs.
  • -l/--log-level=<DEBUG|INFO|WARNING|ERROR> — explicit log-level override.
  • --log-format=<text|json> — text (default) is timestamped and human-readable; json is one object per line for jq / log shippers.
  • --log-file=<path> — also append logs to a file, rotated by size (runtime.log_max_bytes, default 10 MiB × runtime.log_backup_count, default 5). stderr still gets everything unless runtime.log_stderr = false.
  • --status — health check: print the last iteration's heartbeat and alert counts; exit 0 healthy, 1 failed or stale, 2 never ran (see Monitoring).
  • --validate-config — load the config, print a one-line summary, exit.
  • --print-config — load the config, dump the resolved values as JSON, exit.
  • --version

Run discogs_alert --help for the full list.

Docker

$ docker run -d --env-file .env miggleball/discogs_alert:latest

Your .env file should set the required DA_* variables. Minimal example:

DA_DISCOGS_TOKEN=<discogs_access_token>
DA_LIST_ID=<discogs_list_id>
DA_ALERTER_TYPE=NTFY
DA_NTFY_TOPIC=<your-ntfy-topic>

The -d flag detaches the container so it runs in the background.

Extras

You can add to or change your wantlist (Discogs list or local JSON) while the service is running; updates are picked up on the next iteration.

Logs

Every line carries a timestamp, level, and the id of the loop iteration it belongs to ([3f9a1c2e]), so the interleaved output of concurrent per-release work can be grouped and a cron / launchd --once run can be matched to its summary:

2026-09-07 05:40:12 INFO    [3f9a1c2e] discogs_alert.loop: Now For Sale: Artist - Title (€34.00) — Listing available: https://www.discogs.com/sell/item/…

Every iteration ends with one summary line that accounts for every release and listing it touched — grep for iteration finished:

2026-09-07 05:41:02 INFO    [3f9a1c2e] discogs_alert.loop: iteration finished in 22.1s (ok); 344 releases; gate skipped 290 (no_listings=280, above_threshold=10); scraped 54 (ok=40, http_403=14); listings 612, filtered 608 (conditions=500, already_alerted=58, price=30, unavailable=20); alerts sent 4, failed 0; api rate limit 52/60 remaining

If a large share of scrapes come back 403, a WARNING names it for what it is (Cloudflare bot detection on your IP — common on VPN exits) and reminds you those releases were not checked. A failed wantlist fetch (bad token, rate limit, outage) is one ERROR line, not a traceback. Per-listing decisions (why each listing was or wasn't alerted) are at DEBUG, so --verbose shows the full story. Per-request HTTP chatter from httpx / curl_cffi is hidden unless you pass --verbose. --log-format json (or runtime.log_format = "json") switches to one JSON object per line with the same fields plus any structured extras.

Monitoring

After every iteration the CLI (and the menu-bar app) writes last_run.json next to the state DB (runtime.heartbeat_path / DA_HEARTBEAT_PATH to move it): version, timestamps, duration, outcome, the full iteration counters, and the summary line — atomically, so a reader never sees a torn file. discogs_alert --status turns that into a verdict:

$ discogs_alert --status
discogs_alert 0.1.2 — HEALTHY
last run:     2026-09-07T05:41:02+00:00 (4m 12s ago), took 22.1s, alerter NTFY
summary:      iteration finished in 22.1s (ok); 344 releases; gate skipped 290 (…); alerts sent 4, failed 0; api rate limit 52/60 remaining
alerts sent:  4 in 24h, 11 in 7d, 663 total
heartbeat:    /Users/me/.discogs_alert/last_run.json

Exit codes: 0 healthy, 1 the last iteration failed or is stale (older than 2× the interval, minimum 15 minutes), 2 no heartbeat yet. Point a cron job, a launchd watchdog, or a monitoring probe at it; --status --log-format json prints the raw heartbeat + counts as JSON instead.

Each matching listing produces one notification — title is the release's display title, body is the listing URL. Deduplication is local: discogs_alert records every successful alert in ~/.discogs_alert/state.db (configurable via runtime.state_path in config.toml) and won't re-alert across iterations.

The full set of knobs lives in examples/config.example.toml — global filters (seller rating, media / sleeve condition, country whitelist / blacklist), runtime tuning (max_concurrency, prune_after_days, stats_gate), and per-alerter config. Per-release overrides go in your wantlist JSON or as @key=value directives in Discogs list comments (see above).

Full Example

A realistic ~/.discogs_alert/config.toml for a user driven by a Discogs list, who wants verbose logs, no minimum seller rating, a global minimum media condition of VERY_GOOD, and who doesn't want to consider sellers from the UK or US:

discogs_token = "<discogs_access_token>"

[wantlist]
list_id = <list_id>

[seller]
min_rating = 0   # turn off the seller-rating gate

[record]
min_media_condition = "VERY_GOOD"

[country_filters]
blacklist = ["UK", "US"]

[alerter]
type = "NTFY"
[alerter.ntfy]
topic = "<your-secret-topic>"

[runtime]
verbose = true

Running as a cron job

For low-effort always-on use, run discogs_alert as a cron job — set up your config.toml once and let cron schedule the iterations. Run crontab -e and add:

*/10 * * * * source ~/.bash_profile; python -m discogs_alert --once >> <path_to_log_file>.log 2>&1

discogs_alert runs every 10 minutes and logs to the specified file. tail -f <path_to_log_file>.log to follow.

See here for more on cron / crontab.

Running as a macOS launchd daemon

On macOS, the cleanest "always-on" path is a launchd agent — survives logout, doesn't need a terminal open, integrates with macOS power management. A starter template lives at docker/launchd/com.discogsalert.plist.template. Replace the placeholder paths, drop the file at ~/Library/LaunchAgents/com.discogsalert.plist, and launchctl bootstrap gui/$UID it. docs/deployment.md is the full recipe (layout, first run, upgrading, day-to-day checks) as used for the maintainer's own always-on instance.

launchd timers pause while the Mac sleeps; for true 24/7 monitoring, run discogs_alert on an always-on box (Raspberry Pi, NAS, home server) instead.

macOS menu-bar app

For a lightweight GUI with status, "check now", and quick links to your config + state files, install the menu-bar extra and launch the app:

$ pip install 'discogs_alert[menubar]'
$ python -m discogs_alert.menubar

The menu-bar app is not the always-on path — closing it stops the loop. Use it interactively while at your Mac; pair it with launchd (above) for 24/7 monitoring.

Building a standalone .app / .dmg

If you'd rather drag-install a .app than pip install the package, the project ships a Makefile that wraps py2app and hdiutil:

$ make app    # build dist/discogs_alert.app
$ make dmg    # build dist/discogs_alert-X.Y.Z.dmg (the user-facing artifact)

The build uses a clean throwaway venv at .build-venv/ so unrelated packages on your outer Python don't pollute the bundle. End users only need to drag the .app from the DMG into /Applications — no Python install required.

Code signing: the .app is unsigned by default. macOS Gatekeeper will prompt the user to right-click → Open on first launch. Code signing requires an Apple Developer ID ($99/yr); see Apple's notarization docs for the recipe.

Contributing

  1. Fork (https://github.com/michaelhball/discogs_alert/fork)
  2. Create your feature branch (git checkout -b feature/fooBar)
  3. Commit your changes (git commit -am 'Add some fooBar')
  4. Push to the branch (git push origin feature/fooBar)
  5. Create a new Pull Request

Setting up the dev environment

Ideally, you should work inside a virtual environment set up for this project. Once that's the case, simply run the following two commands to install all dependencies:

  • $ pip install --user poetry
  • $ poetry install

And that's it! Until you want to propose your changes as a new PR. When that's the case you need to run the tests to make sure nothing has broken, which you can do simply by running $ tox in the project's root directory.

Cutting a release

Tag-triggered: bump version in pyproject.toml + _FALLBACK_VERSION in discogs_alert/__init__.py, commit, tag vX.Y.Z, push with --follow-tags. CI builds + signs + publishes everything (PyPI, DockerHub, GitHub Release with .app + DMG, Sparkle appcast PR). See docs/release.md for the full recipe.

Author

mhsb

License

This project is licensed under the MIT License - see the LICENSE file for details.

Housekeeping

vinyl icon made by Those Icons on www.flaticon.com

Metadata

Release files for discogs-alert 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for discogs-alert 0.1.3
File Size Uploaded
discogs_alert-0.1.3.tar.gz 68.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for discogs-alert 0.1.3
File Interpreter ABI Platform
discogs_alert-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 140.7 kB

Release files / discogs_alert-0.1.3.tar.gz

Download URL discogs_alert-0.1.3.tar.gz
Size 68.3 kB
Tags Source
SHA-256 checksum
How to use checksums
9fe02b6a6f2fa3dd0c1f96f84677a6bd9e80fd651f741bc2ade0fba69d088813
BLAKE2b-256 checksum
How to use checksums
ac6d0b75bed90ecb7fdd88cbabee44b3223bace20a178f9e6dde9c43936a32a2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.

Transparency log

Release files / discogs_alert-0.1.3-py3-none-any.whl

Download URL discogs_alert-0.1.3-py3-none-any.whl
Size 72.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
48ccb9597032ad2ede4b8dbe01b46ace3a0dbea0c771785841525a2c9a243901
BLAKE2b-256 checksum
How to use checksums
4ed64fe2a68a3d26a97129d5f98962c7a4502b8d25020f7f3dda8fd5fec39958
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.17

2 release files

0.0.16

2 release files

0.0.15

2 release files

0.0.14

2 release files

0.0.13

2 release files

0.0.12

2 release files

0.0.11

2 release files

0.0.10

1 release file

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page