Install
openclaw skills install @rune-philip/danish-grocery-dealsScrape Danish supermarket weekly tilbudsaviser (Lidl, Rema 1000, Netto, Meny, 365 discount) from the Tjek API and push filtered wow deals to ntfy.sh
openclaw skills install @rune-philip/danish-grocery-dealsWeekly scraper for Danish supermarket tilbudsaviser (Lidl, Rema 1000, Netto, Meny, 365 discount) that pushes only the genuinely cheap "wow" deals to your phone via ntfy.sh, plus a full organized deal list as a file attachment.
scripts/tilbudsavis.py scraper (Tjek API, metrics, wow filter, full list)scripts/notify.py publisher (runs scraper, pushes to ntfy.sh)templates/config.json stores, interests, wow thresholds, ntfy settingstemplates/deals-notify.service / .timer systemd weekly scheduletemplates/config.json next to the two scripts (same directory).api_key: Tjek API browser key (see "Tjek API notes" below)ntfy.topic: your ntfy.sh topic (use a random suffix for privacy)stores: dealer ids for chains (defaults cover the 5 Danish chains)interests: keyword lists, exclude lists, and wow thresholdspython3 tilbudsavis.py prints the summary between markerspython3 notify.py runs the scraper and pushes to ntfy.sh0 9 * * 0 cron{
"api_key": "YOUR_TJEK_API_KEY",
"api_base": "https://squid-api.tjek.com",
"ntfy": { "url": "https://ntfy.sh", "topic": "tilbudsavis-RANDOM", "token": "" },
"stores": [
{ "id": "71c90", "name": "Lidl", "avis_url": "https://etilbudsavis.dk/Lidl" },
{ "id": "11deC", "name": "Rema 1000", "avis_url": "https://etilbudsavis.dk/REMA-1000" },
{ "id": "9ba51", "name": "Netto", "avis_url": "https://etilbudsavis.dk/Netto" },
{ "id": "267e1m", "name": "Meny", "avis_url": "https://etilbudsavis.dk/MENY" },
{ "id": "DWZE1w", "name": "365 discount", "avis_url": "https://etilbudsavis.dk/365discount" }
],
"interests": [
{
"category": "Oksekod",
"emoji": "🥩",
"keywords": ["oksekod", "bøf", "steak", "mørbrad", ...],
"exclude": ["steak fries", "pommes"],
"wow": { "max_price_per_kg": 60, "min_discount_pct": 40 }
}
]
}
max_price_per_kg / max_price_per_l / max_price_per_piece: keep deal if
unit price is at or below this barmin_discount_pct: keep deal if discount vs "før" price is >= thisMAX_WOW_ITEMS = 18, MAX_PER_INTEREST = 4 (edit in tilbudsavis.py)GET /v2/catalogs?dealer_id=<id> (camelCase retailerId is IGNORED)GET /v2/offers?catalog_id=<id>&limit=100&offset=<n> (max limit 100,
paginate by offset; filter results client-side by catalog_id)71c90, Rema 1000 11deC, Netto 9ba51,
Meny 267e1m, 365 discount DWZE1w. Discover others via
GET /v2/dealers?country=DK&limit=200&page=Nassets/entry-client-*.js, look for apiKey:{browser:...}); it is a
public read key, no account needednotify.py chunks longer text automatically
(titles get " (1/2)" suffixes)https://ntfy.sh/<topic> with a
Filename: header; posting to the root path fails with 413ntfy.token to a ntfy.sh
access token and the script adds an Authorization headerHTTP 400 on catalogs: you used retailerId instead of dealer_idHTTP 400/500 on offers: limit > 100, or catalogId (camelCase) instead of
catalog_idHTTP 413 on attachment: file > ntfy.sh limit, or wrong URL pathmax_price_per_kg or lower
min_discount_pct), or the week has no standout deals