Usage
Practical, use-case-driven examples for the Tagesschau CLI — a read-only
command-line client for ARD-aktuell’s open Tagesschau API
(tagesschau.de). Every command prints JSON to stdout, so it pairs naturally
with jq.
Install
npm i -g @maschinenlesbar.org/tagesschau-cli
This installs the tagesschau binary. To run from a checkout without a global
install, use node apps/cli/dist/src/cli/index.js in place of tagesschau (after
npm run build).
tagesschau --help
The API needs no key or token — it is fully open and read-only.
Use cases
1. Read the curated front page
Why: get the same editorially-selected top stories that lead tagesschau.de.
tagesschau homepage
The result has a news array (the main feed) and a regional array. To pull
just the headlines:
tagesschau homepage | jq -r '.news[].title'
2. Skim headlines with their topline and timestamp
Why: a compact “what’s happening now” digest instead of the full JSON.
tagesschau homepage | jq -r '.news[] | "\(.date[0:10]) [\(.ressort)] \(.title)"'
Each news item carries title, topline, firstSentence, date, ressort
and shareURL, so you can shape the line however you like.
3. Filter the news feed by Ressort
Why: read only one department — e.g. business or sport.
# Economy
tagesschau news --ressort wirtschaft
# Sport
tagesschau news --ressort sport
Valid Ressorts: inland, ausland, wirtschaft, sport, video,
investigativ, wissen. The API takes one Ressort per request, so --ressort given
twice is a usage error (exit 1, no request) rather than keeping only the last one;
fetch each Ressort in its own run. --date, --page-size and --result-page take one
value too. The news feed returns news, regional and (when
there are more results) a nextPage URL: the same filters plus a date=YYMMDD
cursor, e.g. https://www.tagesschau.de/api2u/news?date=260924®ions=9. Pass
that value to --date, with the same filters, to fetch the next, older page:
next=$(tagesschau --compact news --region 9 | jq -r '.nextPage | capture("date=(?<d>[0-9]{6})").d')
tagesschau news --region 9 --date "$next"
Each page is one request; the API allows about 60 an hour.
4. Get regional news for one Bundesland
Why: focus on a single federal state by its numeric region id (1–16).
When you filter by --region, the matching items come back in the news
array (each tagged with the requested regionId); the top-level regional
array is only populated on the unfiltered homepage feed.
# Niedersachsen (region id 9)
tagesschau news --region 9 | jq -r '.news[].title'
5. Regional news across several Bundesländer
Why: watch a few states at once. --region is repeatable; the client joins the
ids into a single comma-separated regions query (e.g. regions=5,9).
# Bremen (5) and Niedersachsen (9)
tagesschau news --region 5 --region 9
The feed returns one page per request, shared by all requested states, so each state gets fewer items than it would on its own.
6. A Ressort within a region
Why: e.g. domestic-politics news scoped to specific states. The API can’t do
this server-side: when ressort and regions are both sent, it applies the
Ressort and silently ignores the region (every item comes back with
regionId: 0), so the CLI refuses --ressort together with --region (exit
1, no request). Fetch the region feed and filter locally instead; regional
items carry no ressort, so match on title, topline or tags.
tagesschau news --region 9 \
| jq -r '.news[] | select((.title + " " + (.topline // "")) | test("Schule"; "i")) | .title'
7. Full-text search across articles
Why: find coverage of a topic by keyword.
tagesschau search "Bundestag"
The result includes searchResults, totalItemCount, and the echoed
searchText/pageSize/resultPage. Count the hits and list titles:
tagesschau search "Bundestag" | jq '.totalItemCount'
tagesschau search "Bundestag" | jq -r '.searchResults[].title'
An empty search text is rejected by the CLI before any request is made.
The API folds case (köln = Köln) but not spellings: Strasse found 88 hits
against 582 for Straße on 2026-10-05, Koeln 210 against 388 for Köln. When the
text has ae, oe, ue or ss and no letter outside ASCII, the CLI adds a note on
stderr (the JSON is unchanged); if the word is written with ä, ö, ü or ß, search
that spelling too:
tagesschau search "Koeln" | jq '.totalItemCount' # + a note on stderr
tagesschau search "Köln" | jq '.totalItemCount'
8. Page through search results
Why: walk large result sets. --result-page is a 0-based page index (0,
the default, is the first page); --page-size must be >= 1. Both are at most
2147483647, the API’s integer limit.
# 20 results per page, second page
tagesschau search "Wahl" --page-size 20 --result-page 1
9. List the live / broadcast channels
Why: discover the linear and streaming programme feeds and their stream URLs.
tagesschau channels | jq -r '.channels[].title'
Each channel exposes title, streams and image/copyright metadata.
10. Machine-friendly, single-line output
Why: feed downstream tooling or log a compact record.
tagesschau --compact homepage
--compact is a global option; it works before or after the command name
(tagesschau homepage --compact works too).
Global options
These apply to every command and may be given before or after the command
name (e.g. tagesschau --compact news --ressort sport or
tagesschau news --ressort sport --compact).
| Option | Description |
|---|---|
-V, --version |
Print the version and exit. |
--base-url <url> |
API base URL (default https://www.tagesschau.de); an http(s) URL, optionally with a path prefix, without a query (?), fragment (#), whitespace or control characters. Credentials (https://user:pw@host) are sent as Basic auth, to that origin only (not across a redirect to another host or scheme); write a literal % in them as %25. A plain http: base URL to a remote host logs one WARN record of tagesschau.http on stderr (… sent unencrypted to <host> (http:, not https:)) before the first request (naming the base URL’s credentials when it carries any, never printing them); loopback hosts (localhost, 127.x, ::1) don’t warn, and stdout and the exit code are unchanged. |
--timeout <ms> |
Time limit per request in milliseconds, whole response included (at most 2147483647). |
--user-agent <ua> |
User-Agent header value (not blank; no control characters or characters above U+00FF). |
--max-retries <n> |
Retries for transient 429/503 responses, 0–10 (default 2); each waits 200 ms × attempt, or the server’s Retry-After when that is longer (up to 30 s; a longer one is not retried, and the error names the wait). Each retry logs one WARN record of tagesschau.http before it waits (HTTP 503 from host: retry 1 of 3 in 2 s) |
--max-redirects <n> |
Max HTTP redirects to follow, 0–20 (default 5; credential headers are dropped on cross-origin hops). |
--max-response-bytes <n> |
Cap response body size in bytes (0 = unlimited; default 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 [tagesschau.http] …) or jsonl (one JSON object per line: ts, level, topic, msg). stdout is not affected. |
-h, --help |
Display help for the program or a command. |
Exit codes: 0 success, 4 on a 404 from the API, 1 for any other error,
and a non-zero usage error from the parser for invalid arguments. Output into a reader
that stops early (| head) ends quietly with 0; a failed run whose stderr reader has
gone away (2>&1 | true) keeps its own code.