Usage — `dwd`
Use-case-driven examples for the dwd CLI, a read-only client for the open
DWD Warnwetter app API (warnwetter.de): station
forecasts/observations and the published weather-warning feeds (nowcast,
municipality/Gemeinde, coastal) plus crowd-sourced reports. Every command prints
pretty JSON to stdout, so it composes cleanly with jq.
Install
npm i -g @maschinenlesbar.org/dwd-cli
This installs the dwd binary. Without a global install you can run it straight
from a built checkout:
node apps/cli/dist/src/cli/index.js --help
All examples below use the installed bin name dwd.
Use cases
1. Forecast/observation for a single station
Pull the current forecast/observation payload for one DWD station (e.g.
München-Stadt, id 10865).
dwd station-overview --id 10865
Output is a JSON object keyed by station id. Each value carries the raw DWD
fields (forecast1, forecast2, days, warnings, threeHourSummaries) as scaled
integers (tenths of the unit, see GLOSSARY.md). The one change: the API’s
missing-value marker 32767 is printed as null — expect null inside the arrays
(today’s past hours at some stations, every surfacePressure value at mountain
stations), and skip it in sums and averages.
Add --decode for real units — °C, %, hPa, km/h, degrees, mm, minutes of sun — instead of
tenths; nothing else changes (timestamps, icon codes, array lengths and alignment):
dwd --compact station-overview --id 10865 --decode | jq '."10865".days[0] | {temperatureMin, temperatureMax, precipitation}'
2. Compare several stations in one call
Fetch multiple stations at once by repeating --id — handy for a small dashboard
or a city-vs-city comparison.
dwd station-overview --id 10865 --id 10147
The result is keyed per station, so you can address each independently:
jq '."10865"'. An id the API doesn’t know is left out of the answer (exit 0); the CLI
names it on stderr, an INFO record of dwd.api: … INFO [dwd.api] no data for station id 99999 — the API answers an unknown id with
nothing, not an error.
3. List which monitored stations currently have active warnings
--compact keeps it to one line for scripts; jq surfaces only the stations
whose payload contains warnings.
dwd --compact station-overview --id 10865 --id 10147 \
| jq 'to_entries | map(select(.value.warnings != null and (.value.warnings | length) > 0)) | from_entries'
4. Current nationwide nowcast (short-term) warnings
The nowcast feed is the short-fuse warning layer (e.g. imminent thunderstorms).
dwd warnings nowcast
The feed envelope has a time (publish timestamp) and a warnings array. The CLI adds
staleFeed to every warning feed it prints: true when time is more than 60 minutes old
(DWD republishes every few minutes, so warnings issued since are missing), with a note
on stderr (an INFO record of dwd.api); false otherwise. Count the active entries:
dwd --compact warnings nowcast | jq '.warnings | length'
5. Nowcast warnings in English for a quick triage table
Switch the feed language with --lang en, then flatten event + severity level +
description into a compact table with jq. (The feed has no headline/regionName
fields; in --lang en only event/descriptionText are translated.)
dwd warnings nowcast --lang en \
| jq -r '.warnings[] | [.event, .level, .descriptionText] | @tsv'
--lang accepts de (default) or en.
6. Municipality-level (Gemeinde) warnings
The Gemeinde feed resolves warnings down to municipality granularity — the layer the app uses when you select your home town.
dwd warnings gemeinde --lang de
Same envelope shape as nowcast (time + warnings[]). Warnings carry no
regionName field (only regions[] geometry), so to find ones mentioning a
specific town, search the headline/description text:
dwd --compact warnings gemeinde \
| jq '.warnings[] | select(((.headLine // "") + " " + (.descriptionText // "")) | test("München"))'
7. Coastal warnings by zone
Coastal warnings (gale/storm-surge style) for boating and the coast. Here the
warnings field is an object keyed by coastal zone rather than a flat array.
dwd warnings coast
List the zones that currently carry a warning:
dwd --compact warnings coast | jq '.warnings | keys'
8. Crowd-sourced weather reports overview
The crowd feed is the user-submitted reports overview (meldungen), useful as a
ground-truth cross-check against the official warnings.
dwd crowd
Count the submitted reports:
dwd --compact crowd | jq '.meldungen | length'
9. Snapshot a feed to a timestamped file (cron-friendly)
--compact plus a redirect gives you an archivable one-line snapshot per run.
dwd --compact warnings nowcast > "nowcast-$(date +%Y%m%dT%H%M).json"
10. Harden a call behind a flaky network
Tighten the timeout, cap the response size, and identify yourself politely — all global options that apply to any command.
dwd --timeout 10000 --max-retries 3 --user-agent "my-monitor/1.0" \
--max-response-bytes 5242880 \
warnings gemeinde
--timeout bounds each attempt, not the whole command: with --max-retries 3 a run can take up
to four timeouts plus the waits between them. Bound the whole run from outside if you need to
(for example with coreutils: timeout 60 dwd …).
Global options recap
Global options may be given before or after the command — both
dwd --compact warnings nowcast and dwd warnings nowcast --compact work.
| Option | Description |
|---|---|
-V, --version |
Output the version number |
--base-url <url> |
Live web-service base URL, without /v30 (default https://app-prod-ws.warnwetter.de) — used by station-overview |
--static-base-url <url> |
Static (S3) bucket base URL, without /v16 (default https://s3.eu-central-1.amazonaws.com/app-prod-static.warnwetter.de) — used by the warnings and crowd feeds |
--timeout <ms> |
Time limit per request attempt in milliseconds, reading the whole response included (default 30000; 0 = no timeout; at most 2147483647). Each retry gets the full limit again |
--user-agent <ua> |
User-Agent header value |
--max-retries <n> |
Retries for transient 429/503 responses and reset connections (0–10, default 2; each backs off linearly from 200 ms, or longer if the server’s Retry-After asks, up to 30 s; each retry logs one WARN record of dwd.http before it waits) |
--max-response-bytes <n> |
Cap response body size in bytes (0 = unlimited; default 104857600 / 100 MiB) |
--compact |
Print JSON on a single line instead of pretty-printed |
--log-format <format> |
How errors, warnings and notes are written to stderr: text (default; log4j style, 2026-10-09T14:03:12.481Z WARN [dwd.http] …) or jsonl (one JSON object per line: ts, level, topic, msg). stdout is not affected |
-h, --help |
Display help for a command |
A base URL on plain http: to a remote host (not localhost, 127.0.0.0/8 or ::1) gets one
warning on stderr, a WARN record of dwd.http (… sent unencrypted to <host> (http:, not https:)), before the command’s
request; stdout and the exit code are unchanged. Only the base URL the command uses is checked.
Command flags
| Command | Flag | Notes |
|---|---|---|
station-overview |
--id <stationId> |
Required, repeatable; 5-digit DWD station id |
station-overview |
--decode |
Real units (°C, %, hPa, km/h, °, mm, minutes of sun) instead of tenths |
warnings nowcast |
--lang <lang> |
de (default) or en |
warnings gemeinde |
--lang <lang> |
de (default) or en |
warnings coast |
--lang <lang> |
de (default) or en |
crowd |
— | No flags beyond globals |