Usage
lebensmittel — a CLI for the official lebensmittelwarnung.de product-warning RSS
feeds. This is the use-case-driven cookbook; for the option reference see the
README, and for domain terms the Glossary. No API
key is required.
lebensmittel [global options] <command>
Global options
| Option | Description |
|---|---|
--base-url <url> |
API base URL (only http:/https: accepted) |
--timeout <ms> |
time limit per request in ms, whole response included (0 = no timeout; at most 2147483647) |
--user-agent <ua> |
User-Agent header value |
--max-retries <n> |
retries for transient 429/503 responses (0..10) |
--max-response-bytes <n> |
cap the response body size in bytes (0 = unlimited; default 100 MiB) |
--compact |
print JSON on a single line (for piping to jq) |
-o, --output <file> |
write output to a file instead of stdout |
-V, --version / -h, --help |
version / help |
warnings — current product recalls
The heart of the tool: the portal’s currently active warnings, each with its reason, manufacturer, affected Länder, lot numbers and best-before dates.
lebensmittel warnings
[
{
"title": "ja! Beerenmischung, tiefgefroren, 750 Gramm Beutel",
"link": "https://www.lebensmittelwarnung.de/.../Meldung.html",
"pubDate": "Wed, 8 Jul 2026 16:00:00 +0200",
"published": "2026-07-08T14:00:00.000Z",
"reason": "Krankheitserreger",
"manufacturer": "Eurogroup España Frutas y Verduras S.A.U., …",
"affectedStates": ["Nordrhein-Westfalen", "Bayern", "…"],
"lotNumbers": "L-26085",
"bestBefore": "Mindesthaltbarkeitsdatum: 15.03.2028",
"packaging": "750 Gramm",
"imageUrls": ["https://www.lebensmittelwarnung.de/.../Bild.jpg?__blob=normal&v=1"],
"fields": { "…": "…" },
"rawDescription": "<img …/><br/><b>Grund der Meldung:</b> …"
}
]
# One line per recall: date (German time, from pubDate), product, reason
lebensmittel warnings | jq -r '.[] | "\(.pubDate | split(" ")[1:4] | join(" "))\t\(.title)\t\(.reason // "?")"'
# How many warnings does the portal list? (not only recent ones: the feed goes back years)
lebensmittel warnings | jq length
# Every product-photo URL
lebensmittel warnings | jq -r '.[].imageUrls[]?'
Narrow by federal state
lebensmittel warnings --state bayern
lebensmittel warnings --state nordrheinwestfalen | jq length
--state selects the warnings distributed in that Land (server-side): the ones
whose affectedStates list names it, whoever issued them. Run
lebensmittel states for the sixteen valid slugs; an unknown slug is a usage error
(exit 2), never a silent full-feed fallback.
The feed has no field for the issuing Land. The notice URL carries it as a Land code in the folder name (
…/260904_03_BW_diverse_Kaesesorten/…,BVLfor the federal office), a naming convention rather than data:lebensmittel warnings | jq -r '.[] | select(.link | test("/\\d{6,8}(_\\d+)?_BY_")) | .title'
Narrow by product type
lebensmittel warnings --type lebensmittel # food only
lebensmittel warnings --type kosmetischemittel # cosmetics
lebensmittel warnings --type babyundkinderprodukte # baby & kids products
Run lebensmittel types for the five valid slugs. --state and --type compose:
lebensmittel warnings --state bayern --type lebensmittel | jq length
Narrow by date, title, and count (client-side)
# Only recalls published on or after a date
lebensmittel warnings --since 2026-07-01
# Only recalls whose product name contains a term (case-insensitive)
lebensmittel warnings --search schokolade | jq -r '.[].title'
# The 5 most recent
lebensmittel warnings --limit 5
# Combine everything
lebensmittel warnings --type lebensmittel --since 2026-07-01 --search bio --limit 10
--since takes a YYYY-MM-DD date and keeps warnings whose publication day, in
German time (Europe/Berlin), is that day or later. A malformed date (2026-13-40,
10.07.2026) is a usage error (exit 2).
published is the same instant in UTC, so its first ten characters give the day
before for notices published in the first one or two hours after midnight German
time (many are stamped 00:00:00 +0200). For a date to show, take it from pubDate, which is in
German time: .pubDate | split(" ")[1:4] | join(" ") gives 4 Sep 2026.
--search/--since that match nothing return [] (not the full feed).
states — the valid Bundesland slugs
lebensmittel states
[
{ "slug": "badenwuerttemberg", "name": "Baden-Württemberg" },
{ "slug": "bayern", "name": "Bayern" }
]
Offline (no request). Use it to discover the exact --state slugs:
lebensmittel states | jq -r '.[].slug'
types — the valid product-type slugs
lebensmittel types
[
{ "slug": "lebensmittel", "name": "Lebensmittel" },
{ "slug": "kosmetischemittel", "name": "Kosmetische Mittel" }
]
Offline (no request).
Recipes
# Reasons across all listed warnings, counted (a warning can carry several, joined with ", ")
lebensmittel warnings | jq -r '[.[] | (.reason // "?") | split(", ")[]] | group_by(.)[] | "\(.[0]): \(length)"'
# A daily "anything new in Bavaria?" check (exit 0 with rows, or empty)
lebensmittel warnings --state bayern --since "$(date -v-1d +%F 2>/dev/null || date -d yesterday +%F)" \
| jq -r '.[] | "\(.title) — \(.reason)"'
# Look up a specific batch across all recalls
lebensmittel warnings | jq -r --arg lot "L-26085" \
'.[] | select(.lotNumbers // "" | test($lot)) | .title'
# Save today's full snapshot to a file
lebensmittel warnings -o warnings-$(date +%F).json
Exit codes
| Code | Meaning |
|---|---|
0 |
Success (also --help / --version) |
2 |
Bad usage / invalid argument (unknown --state/--type, bad --since/--limit) |
4 |
Not found (404) |
6 |
Network / transport failure (DNS, connection, timeout, size cap) |
1 |
Any other error — non-RSS HTML shell, empty body, or a 3xx redirect |
Notes
- Attribution required. The warnings are copyright-protected; if you republish any of them, do so unaltered, in full, and with the prescribed citation. See DATA_LICENSE.md.
- Feed freshness. The channel advertises
ttl 60(minutes). The data is live and changes without notice; a warning can be withdrawn upstream.