{"id":49332390,"url":"https://github.com/patbaumgartner/swiss-coupon-booster","last_synced_at":"2026-06-05T20:00:29.879Z","repository":{"id":310474149,"uuid":"1039988089","full_name":"patbaumgartner/swiss-coupon-booster","owner":"patbaumgartner","description":"A Spring Boot application that helps you automatically activate all available digital coupons from Switzerland's leading retailers, Migros (Cumulus) and Coop (SuperCard).","archived":false,"fork":false,"pushed_at":"2026-06-05T14:01:36.000Z","size":586,"stargazers_count":1,"open_issues_count":0,"forks_count":4,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-05T14:18:55.645Z","etag":null,"topics":["automation","coop","coupons","cumulus","java","migros","spring-boot","supercard"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/patbaumgartner.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-18T09:37:59.000Z","updated_at":"2026-06-05T14:02:02.000Z","dependencies_parsed_at":"2026-01-02T23:04:06.796Z","dependency_job_id":null,"html_url":"https://github.com/patbaumgartner/swiss-coupon-booster","commit_stats":null,"previous_names":["patbaumgartner/migros-coupon-booster","patbaumgartner/swiss-coupon-booster"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/patbaumgartner/swiss-coupon-booster","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patbaumgartner%2Fswiss-coupon-booster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patbaumgartner%2Fswiss-coupon-booster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patbaumgartner%2Fswiss-coupon-booster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patbaumgartner%2Fswiss-coupon-booster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/patbaumgartner","download_url":"https://codeload.github.com/patbaumgartner/swiss-coupon-booster/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patbaumgartner%2Fswiss-coupon-booster/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33957499,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-05T02:00:06.157Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","coop","coupons","cumulus","java","migros","spring-boot","supercard"],"created_at":"2026-04-26T23:02:37.772Z","updated_at":"2026-06-05T20:00:29.857Z","avatar_url":"https://github.com/patbaumgartner.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# 🛒 Swiss Coupon Booster\n\n**Automatically activates all available digital coupons for Migros (Cumulus) and Coop (Supercard)**\n\n[![CI](https://github.com/patbaumgartner/swiss-coupon-booster/actions/workflows/ci.yml/badge.svg)](https://github.com/patbaumgartner/swiss-coupon-booster/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Java 25](https://img.shields.io/badge/Java-25-blue?logo=openjdk)](https://openjdk.org/projects/jdk/25/)\n[![Python 3.14](https://img.shields.io/badge/Python-3.14-blue?logo=python)](https://www.python.org/downloads/release/python-3140/)\n[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-4.x-brightgreen?logo=springboot)](https://spring.io/projects/spring-boot)\n[![Docker Hub – coupon-booster](https://img.shields.io/docker/v/patbaumgartner/coupon-booster?label=coupon-booster\u0026logo=docker\u0026color=blue)](https://hub.docker.com/r/patbaumgartner/coupon-booster)\n[![Docker Hub – stealth-service](https://img.shields.io/docker/v/patbaumgartner/stealth-service?label=stealth-service\u0026logo=docker\u0026color=blue)](https://hub.docker.com/r/patbaumgartner/stealth-service)\n\n\u003c/div\u003e\n\n---\n\n## Table of Contents\n\n- [Why this project?](#why-this-project)\n- [How it works](#how-it-works)\n- [Project structure](#project-structure)\n- [Prerequisites](#prerequisites)\n- [Quick start — Docker Hub](#quick-start--docker-hub-recommended)\n- [Building from source](#building-from-source)\n- [Scheduling](#scheduling)\n- [Local development](#local-development)\n- [Configuration reference](#configuration-reference)\n- [Debug artifacts](#debug-artifacts)\n- [FAQ](#faq)\n- [Contributing](#contributing)\n- [License](#license)\n\n---\n\n## Why this project?\n\nBoth Migros and Coop publish dozens of digital discount coupons every week. Activating them\nmanually one by one across their apps or websites is tedious — and easy to forget. This project\nautomates the entire process: it logs in, discovers every available coupon, and activates them\nall in a single run. Set it up once on your home server or NAS and let it run on a schedule.\n\n---\n\n## How it works\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                      docker compose up                          │\n│                                                                 │\n│  ┌────────────────────────┐      ┌───────────────────────────┐  │\n│  │    stealth-service     │      │      coupon-booster       │  │\n│  │  (Python 3.14/FastAPI) │◄─────│    (Java 25/Spring Boot)  │  │\n│  │                        │      │                           │  │\n│  │  POST /login/coop      │      │  1. Authenticate via      │  │\n│  │  POST /login/migros    │      │     stealth-service       │  │\n│  │                        │      │  2. Fetch available       │  │\n│  │  Patchright + Xvfb     │      │     coupons via REST API  │  │\n│  │  → bypasses DataDome   │      │  3. Activate all coupons  │  │\n│  └────────────────────────┘      └───────────────────────────┘  │\n└─────────────────────────────────────────────────────────────────┘\n```\n\n**Why a sidecar?**  \nCoops protect their login pages with [DataDome](https://datadome.co) bot\ndetection. A standard headless browser is instantly flagged. The **stealth-service** sidecar\nuses [Patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright) — a patched build of\nChromium that removes all automation fingerprints at the C++ level — running inside a virtual\nXvfb display. From DataDome's perspective this is indistinguishable from a real user.\n\n\u003e **Home network beats everything.** Swiss residential IPs are treated very differently from\n\u003e cloud or datacenter addresses. Running this on your home server or NAS means you will\n\u003e virtually never see a DataDome challenge — no paid proxy needed.\n\n---\n\n## Project structure\n\n```\nswiss-coupon-booster/\n├── coupon-booster/          # Spring Boot application (Java 25 / Maven)\n│   ├── src/\n│   │   ├── main/java/       # Application sources\n│   │   └── test/java/       # Unit + integration tests\n│   ├── pom.xml\n│   └── Dockerfile           # Build context: repo root (needs .git for git info)\n├── stealth-service/         # Patchright login sidecar (Python 3.14 / FastAPI)\n│   ├── main.py              # FastAPI app — POST /login/coop, POST /login/migros, GET /health\n│   ├── test_*.py            # pytest test suite\n│   ├── entrypoint.sh        # Starts Xvfb and uvicorn\n│   ├── pyproject.toml       # uv dependency source + pytest config\n│   ├── uv.lock              # Locked Python dependencies for reproducible installs\n│   └── Dockerfile\n├── docker-compose.yml        # Production — pulls images from Docker Hub\n├── docker-compose.build.yml  # Development — builds images from source\n├── docker-compose.sidecar.yml # Local dev — Spring Boot auto-starts stealth-service only\n├── .env.example              # Configuration template — copy to .env\n└── .github/\n    ├── workflows/\n    │   ├── ci.yml           # On push / PR: test Java + Python, validate Docker builds\n    │   └── release.yml      # On tag: build, test, push to Docker Hub, publish release\n    └── dependabot.yml       # Automated dependency updates (Maven, pip, Actions)\n```\n\n---\n\n## Prerequisites\n\n| Tool | Version | Notes |\n|---|---|---|\n| Docker | 24+ | With Compose v2 (comes bundled with Docker Desktop) |\n| Git | any | For cloning the repository |\n| Java 25 | JDK 25 | Only for local development without Docker |\n| Python 3.14 | 3.14+ | Only for local development without Docker |\n\n---\n\n## Quick start — Docker Hub (recommended)\n\n```sh\n# 1. Clone the repository\ngit clone https://github.com/patbaumgartner/swiss-coupon-booster.git\ncd swiss-coupon-booster\n\n# 2. Create and fill in your configuration\ncp .env.example .env\n$EDITOR .env   # set MIGROS_USER_EMAIL, MIGROS_USER_PASSWORD, COOP_USER_EMAIL, COOP_USER_PASSWORD\n\n# 3. Pull the pre-built images and run\ndocker compose pull\ndocker compose up\n```\n\n`stealth-service` starts first and waits until its health check passes (up to 40 s). Then\n`coupon-booster` authenticates, activates all available coupons, and exits cleanly.\n\n**Pinning a specific release:**\n\n```sh\nVERSION=1.2.0 docker compose up\n```\n\n---\n\n## Building from source\n\nUse `docker-compose.build.yml` when you want to run from local sources (e.g. after making\nchanges):\n\n```sh\n# Build both images and start\ndocker compose -f docker-compose.build.yml up --build\n\n# Build without starting\ndocker compose -f docker-compose.build.yml build\n```\n\n---\n\n## Scheduling\n\nYou have two options for automatic activation.\n\n### Option 1: Built-in Spring scheduler (long-running server)\n\nRun coupon-booster as a long-running Spring app with profile `server`.\n\n```sh\ncd coupon-booster\n\n# Profile enables Spring MVC mode + @Scheduled jobs\nSPRING_PROFILES_ACTIVE=server mvn spring-boot:run\n```\n\nDefault schedule (server profile):\n\n- Coop daily at 06:00 Europe/Zurich\n- Migros daily at 06:10 Europe/Zurich\n\nStartup runners are disabled by default in server profile to avoid duplicate runs.\nEnable one-time boot run explicitly with:\n\n- COOP_STARTUP_RUN_ENABLED=true\n- MIGROS_STARTUP_RUN_ENABLED=true\n\nOverride via `.env` or environment variables:\n\n- `COOP_SCHEDULER_CRON`\n- `MIGROS_SCHEDULER_CRON`\n- `COUPONBOOSTER_SCHEDULER_ZONE`\n- `COOP_SCHEDULER_ENABLED`\n- `MIGROS_SCHEDULER_ENABLED`\n\n### Option 2: External cron (Linux/NAS)\n\nFor containerized one-shot runs, keep using host cron.\n\n```sh\n# Run every Monday at 07:00\n0 7 * * 1 cd /path/to/swiss-coupon-booster \u0026\u0026 docker compose pull -q \u0026\u0026 docker compose up --no-color \u003e\u003e /var/log/coupon-booster.log 2\u003e\u00261\n```\n\n### Docker restart policy note\n\nThe one-shot app exits with code `0` when done. Using `restart: on-failure` will not cause it\nto loop. For one-shot container mode, a cron job calling `docker compose up` is the\nrecommended approach.\n\n---\n\n## Local development\n\n### stealth-service (Python)\n\n```sh\ncd stealth-service\n\n# Install uv (if not already installed)\n# https://docs.astral.sh/uv/getting-started/installation/\n\n# Create/update .venv from lockfile (production + dev/test groups)\nuv sync --frozen --all-groups\n\n# Install the Patchright Chromium build\nuv run python -m patchright install chromium\n\n# Run the sidecar (a real display is enough on a desktop machine)\nCOOP_USER_DATA_DIR=./coop-user-data \\\nMIGROS_USER_DATA_DIR=./migros-user-data \\\n  uv run uvicorn main:app --reload --port 8000\n\n# Run the test suite\nuv run pytest -v --tb=short\n```\n\n### coupon-booster (Java)\n\n```sh\ncd coupon-booster\n\n# First-time: install Playwright Chromium (used by the browser auth fallback)\nmvn exec:java -e \\\n  -Dexec.mainClass=\"com.microsoft.playwright.CLI\" \\\n  -Dexec.args=\"install --with-deps\"\n\n# Run the application\n# The ../.env file at the repo root is loaded automatically via spring.config.import\n# When COOP_AUTH_MODE=sidecar and/or MIGROS_AUTH_MODE=sidecar, Spring Boot\n# auto-starts docker-compose.sidecar.yml (stealth-service only).\nmvn spring-boot:run\n\n# Unit tests only\nmvn test\n\n# Full verify: formatting, unit + integration tests, SpotBugs, JaCoCo coverage\nmvn verify\n```\n\n---\n\n## Configuration reference\n\nCopy `.env.example` to `.env` and fill in the required values.\n\n### Required\n\n| Variable | Description |\n|---|---|\n| `MIGROS_USER_EMAIL` | Migros / Cumulus account e-mail |\n| `MIGROS_USER_PASSWORD` | Migros / Cumulus account password |\n| `COOP_USER_EMAIL` | Coop / Supercard e-mail |\n| `COOP_USER_PASSWORD` | Coop / Supercard password |\n\n### Optional\n\n| Variable | Default | Description |\n|---|---|---|\n| `COOP_AUTH_MODE` | `browser` | `browser` (local dev) or `sidecar` (Docker / production) |\n| `MIGROS_AUTH_MODE` | `browser` | `browser` (local dev) or `sidecar` (Docker / production) |\n| `COOP_STARTUP_RUN_ENABLED` | `true` | Run Coop once at application startup |\n| `MIGROS_STARTUP_RUN_ENABLED` | `true` | Run Migros once at application startup |\n| `VERSION` | `latest` | Docker Hub image tag to pull |\n| `STEALTH_SLOW_MO_MS` | `500` | Milliseconds between browser actions |\n| `STEALTH_TIMEOUT_MS` | `25000` | Browser element wait timeout (ms) |\n| `STEALTH_LOG_LEVEL` | `info` | Sidecar log level (`debug` for verbose output) |\n| `PROXY_URL` | _(none)_ | Optional HTTP or SOCKS5 residential proxy URL |\n| `JAVA_OPTS` | `-XX:+UseZGC -Xmx512m` | JVM flags for coupon-booster |\n\n### Auth modes\n\n| Mode | When to use |\n|---|---|\n| `browser` **(local dev default)** | Login via Java Playwright directly. No sidecar required. Suitable for `mvn spring-boot:run` on a developer machine. May be challenged by DataDome on non-residential IPs. |\n| `sidecar` **(Docker / production)** | Login delegated to `stealth-service`. Uses Patchright + Xvfb to bypass DataDome bot detection. Set via `COOP_AUTH_MODE=sidecar` / `MIGROS_AUTH_MODE=sidecar` — both Docker Compose files do this automatically. |\n\n---\n\n## Debug artifacts\n\nWhen a login fails, screenshots and HTML page dumps are saved automatically.\n\n```sh\n# Copy screenshots out of the running (or stopped) container\ndocker compose cp stealth-service:/data/screenshots ./debug-screenshots\nls -la ./debug-screenshots/\n```\n\nScreenshots are also preserved in the `screenshots` Docker volume between runs.\n\n---\n\n## FAQ\n\n**Q: Will this get my account banned?**  \nA: The application activates coupons exactly as a human user would through the normal web\ninterface. Both retailers explicitly publish these coupons for customers to use. There is no\nreport of any account being penalised for activating their own coupons.\n\n**Q: Do I need a Swiss IP address?**  \nA: You need a residential IP — ideally a Swiss one. DataDome assigns risk scores based on\nIP reputation. Any residential broadband or home server/NAS works well. Cloud VPS addresses\n(AWS, GCP, Hetzner, etc.) will frequently trigger challenges even with Patchright.\n\n**Q: Why does the container need `--shm-size` or similar?**  \nA: The Dockerfiles already configure the correct shared memory settings for Chromium. No\nextra flags are needed with the provided `docker-compose.yml`.\n\n**Q: Can I disable one retailer?**  \nA: Yes. Set `COOP_STARTUP_RUN_ENABLED=false` or `MIGROS_STARTUP_RUN_ENABLED=false` in your `.env`.\n\n**Q: The login fails with a screenshot showing a CAPTCHA.**  \nA: This almost always means the IP has been flagged. Try running on a different network\n(home broadband vs. VPS). If you must run in a cloud environment, configure a residential\nproxy via the `PROXY_URL` variable.\n\n---\n\n## Docker Hub images\n\n| Image | Description |\n|---|---|\n| [`patbaumgartner/stealth-service`](https://hub.docker.com/r/patbaumgartner/stealth-service) | Python 3.14 / Patchright sidecar |\n| [`patbaumgartner/coupon-booster`](https://hub.docker.com/r/patbaumgartner/coupon-booster) | Java 25 / Spring Boot application |\n\nImages are built and pushed to Docker Hub automatically on every GitHub release via the\n[release workflow](.github/workflows/release.yml).\n\n---\n\n## Contributing\n\nContributions are very welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) before\nsubmitting a pull request.\n\nQuick checklist:\n\n- All tests pass: `mvn verify` (Java) and `uv run pytest -v --tb=short` (Python)\n- Code is formatted: `mvn spring-javaformat:apply` (Java)\n- New environment variables are documented in `.env.example` and `README.md`\n\n---\n\n## License\n\nDistributed under the MIT License. See [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpatbaumgartner%2Fswiss-coupon-booster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpatbaumgartner%2Fswiss-coupon-booster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpatbaumgartner%2Fswiss-coupon-booster/lists"}