TGTG Scanner: a notification service for Too Good To Go Magic Bags
Scanner for Too Good To Go Notifications
At a glance
- What is it?
- TGTG Scanner watches your favourite Too Good To Go stores for Magic Bags and notifies you when stock appears, over mail, Telegram, Discord, ntfy, PushSafer, Apprise or a webhook. The interesting engineering is the notification matrix and the HTTP server, and the interesting caveat is that the platform it polls explicitly forbids the practice.
- Who is it for?
- Adopt TGTG Scanner if you want to be told when a specific Too Good To Go store has bags again and you are prepared to run a small container on hardware that runs 24 hours a day, accepting that the platform can block you at any time. Do not adopt it expecting a supported service, because the project is not affiliated with Too Good To Go and the README quotes the terms forbidding the scraping this tool performs.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 72 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What it watches and what it tells you
TGTG Scanner observes your favorite TGTG Magic Bags for newly available items and notifies you via mail, IFTTT, Ntfy, Telegram, PushSafer, Apprise or any other WebHook.
The trigger condition is the part that makes it useful rather than noisy. Notifications will be sent when the available amount of Magic Bags rises from zero to something. A store that always shows four bags is not a store you need telling about, and a scanner that fired on every poll would be unusable within a day. The zero-to-something transition is the event.
There is a second output. The currently available amounts can be provided via an HTTP server, and running in a Docker container the scanner can be integrated with OpenHab, Prometheus, and other automation, notification, and visualization services.
So the design is two output channels from one polling loop. The notification path handles the event, the moment stock appears, and the HTTP path handles the state, the current count per store, so that a dashboard can show the same information without a notification layer. Exposing the counts as metrics is what makes it usable from Home Assistant or a Grafana board rather than only from your phone.
The software is provided as is without warranty of any kind, and the README asks you to check the FAQ before creating an issue. The primary language is Python, the licence is GPL-3.0-or-later, the default branch is main, and the last push was on 2026-08-12, with v1.26.0 released the same day, after v1.25.0 in January 2026 and v1.24.2 in November 2025.
The disclaimer is the most important paragraph in the README
The project is explicit about its legal position, and it is not the usual boilerplate.
This project is not affiliated, associated, authorized, endorsed by, or in any way officially connected with Too Good To Go, or any of its subsidiaries or its affiliates.
Then the sentence that matters. Too Good To Go explicitly forbids the use of their platform the way this tool does if you use it. In their Terms and Conditions it says: The Consumer must not misuse the Platform, including hacking or scraping.
The consequence is spelled out plainly. If you use this tool you do it at your own risk. Too Good To Go may stop you from doing so by temporarily blocking your access and may even delete your account.
So this is a tool whose author has read the terms of the service it polls and written down that using it may cost you the account. That honesty is worth more than a disclaimer that said nothing, and it changes how you should deploy it: it is a personal convenience, not infrastructure, and it is a thing that can stop working on a Tuesday.
The related operational symptom has its own section. If you see the Error 403 in your logs, the README points at a FAQ entry, and the 403 is the platform refusing the request rather than a bug in the scanner. The two facts are related, and a reader who sees the FAQ section on 403 without reading the disclaimer will not understand why the answer is basically that the tool may be blocked.
Four install routes, from a binary to a source checkout
The installation section gives four options, explicitly ordered by ascending complexity, and the choice comes down to the architecture you are on and how much you want to run yourself.
A prebuilt binary is the simplest. The binaries are built for latest Ubuntu, MacOS and Windows running on x64 architecture. If you are using another architecture like arm, for example Raspberry Pi or Synology, you have to run from source, compile the binary yourself or use the Docker images. The steps are to download the latest release for your OS, unzip the archive, edit config.ini as described in the wiki, and run the scanner. The executables for Windows and MacOS are not signed by Microsoft and Apple, which would be very expensive, so on MacOS you have to hold the control key while opening the file and on Windows you have to confirm the displayed dialog.
Docker is the author's preferred method for servers, NAS and Raspberry Pis, using the prebuilt multi-arch Linux images from Docker Hub, built for Linux on amd64, arm64, armv7, armv6 and i386. You copy and edit docker-compose.yml, then run docker compose up -d. The container automatically creates a volume mounting tokens where the app saves the TGTG credentials after login, and those credentials are reused at every start of the container to avoid the mail login process. To log in with a different account you have to delete the created volume or the files in it. To update the running container to the latest version of the selected tag:
docker-compose pull
docker-compose up -dInstalling as a package needs Git, Python 3.10 or newer and pip, then pip install from the git URL, create config.ini, and start the scanner with python -m tgtg_scanner.
Running from source is for advanced usage and uses poetry, with poetry install --without test,build, a config file copied from config.sample.ini, and the scanner started with poetry run scanner. You can alternatively use environment variables as described in the wiki, and the scanner will look for environment variables if no config.ini is present.
Building your own binary for your OS and architecture combination is the last option, and the Makefile does the work with poetry run pyinstaller against scanner.spec, then copies the sample config and zips the dist directory.
The login flow assumes you are not using the mobile app
The usage section describes the login, and there is a strikethrough on the old behaviour, which tells you what changed and why.
The old process, now struck out, was that similar to logging in to the TGTG app, you have to click on the link sent to you by mail. And the note added to that removed text is the important part: this will not work on your mobile phone if you have installed the TGTG app, so you have to check your mailbox on your PC.
The new login process is a web form instead. When logging in you receive a mail containing a Pin. The scanner starts a web form where you can paste the Pin, and the link to the form is printed in the console. With the Port setting you can specify a port for the webform, and the README says this is especially necessary in a Docker setup.
That last point is the whole deployment wrinkle. On a headless server or in a container, there is no browser to click a link in, so the scanner exposes a small web form, prints its URL, and you open it from wherever you are, paste the pin, and the session is established. The port has to be reachable for that to work, which is why the compose file publishes 3000 and sets PORT to 3000, and why the docker-compose example config includes PORT=3000 among its environment variables.
After a successful login, the scanner will send a test notification on all configured notifiers. If you do not receive any notifications, the advice is to check your configuration. That is a good design for a tool with this many notification backends, since it turns a silent failure into an obvious one.
Twelve notification backends and a Prometheus endpoint
The dependency list in the pyproject is where the notification matrix becomes visible, and it is a long one for a small utility.
There is apprise, which is the general purpose notification library that covers the generic webhook case. There is python-telegram-bot with the callback-data extra for Telegram, python-pushsafer for PushSafer, and the discord library for Discord. The mail path is covered by the general requests dependency rather than a dedicated client, and the topic tags in the repository also list ntfy, ifttt, mail, telegram, webhook, apprise, pushsafer, prometheus and docker.
The Prometheus side is the prometheus-client library, and the HTTP server that exposes the current counts is a separate entry point. The project scripts declare two: scanner mapped to tgtg_scanner.__main__:main, and tgtg_server mapped to tests.tgtg_server:main.
The presence of a separate server binary alongside the scanner is the interesting structural decision. The scanner polls and notifies, and the server exposes the counts over HTTP for the visualisation and home automation path. Running both means the notification path and the dashboard path are independent, and a Prometheus scrape does not depend on the notifier configuration being right.
The remaining dependencies fill in the surrounding work. The tgtg package itself is the client library for the Too Good To Go API, the cron scheduling is handled by pycron with cron-descriptor for the human readable descriptions, and there is humanize for turning counts into readable strings, googlemaps for turning store names into locations, and babel for localisation. The target library is the official client for the service.
The build and test tooling is a small project done properly
The Makefile is short and it covers the whole loop, which is a good sign for a project that people will pull onto a NAS and leave alone.
The install target runs poetry install and then installs the pre-commit hooks. The test target runs pytest with the tgtg_api marker deselected and coverage over the tgtg_scanner package, which tells you the marker exists because some tests call the real API and are excluded from the normal run. The lint target runs pre-commit over everything, and there is a tox target for the multi-version matrix.
The executable target is the one that produces a release artefact, and it does the packaging by hand rather than through a plugin. It removes the build and dist directories, runs pyinstaller against scanner.spec, copies config.sample.ini to dist/config.ini, and then zips the dist directory into scanner.zip. There is a separate scanner_win.spec for the Windows build.
The image target builds two Dockerfiles, one for the standard image and one for the Alpine variant, and the compose file uses the Alpine one by default with a comment that the locally built image and the build directive are there as alternatives.
The ruff configuration sets a line length of 130 and selects the pycodestyle, pyflakes, bugbear, isort and pyupgrade rules, and the pytest configuration registers the tgtg_api marker with a note that it can be deselected with -m not tgtg_api. The test group pulls in pytest, pytest-cov, pytest-mock and responses, and responses is the library for mocking HTTP, which is how the API calls are tested without touching the real service.
Editorial conclusion
Adopt TGTG Scanner if you want to be told when a specific Too Good To Go store has bags again and you are prepared to run a small container on hardware that runs 24 hours a day, accepting that the platform can block you at any time. Do not adopt it expecting a supported service, because the project is not affiliated with Too Good To Go and the README quotes the terms forbidding the scraping this tool performs. Before you set it up, read the Error 403 entry in the FAQ, and note that the scanner will not work for an account that has the Too Good To Go app installed, because the login link goes to email and the app consumes it.
Frequently asked questions
What does the TGTG Scanner do?
It observes your favourite Too Good To Go Magic Bags for newly available items and notifies you when the available amount rises from zero to something, over mail, IFTTT, ntfy, Telegram, PushSafer, Apprise or a webhook. The currently available amounts are also exposed over an HTTP server for use with OpenHab, Prometheus and similar services.
Is using TGTG Scanner against the Too Good To Go terms of service?
The README says Too Good To Go explicitly forbids the use of their platform the way this tool does, quoting their terms that the consumer must not misuse the platform including hacking or scraping, and warns that the platform may block your access or delete your account. The project is not affiliated with the company in any way.
How do I install TGTG Scanner?
Four routes. Use a prebuilt binary for x64 on Ubuntu, MacOS or Windows, though the Mac and Windows executables are unsigned. Use the multi-arch Docker images from Docker Hub for servers, NAS and Raspberry Pis. Install it as a pip package with `pip install git+https://github.com/Der-Henning/tgtg`. Or run it from source with poetry. You can also build your own binary with `make executable`.
Why does TGTG Scanner need a web form to log in?
The new login process sends a mail containing a Pin, and the scanner starts a web form where you paste it, with the link printed in the console. You set the Port setting to choose the port, which is especially necessary in a Docker setup because the scanner is running on a machine you may not be sitting at.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/der-henning-tgtg)Was this useful?