---
name: lobby-meetings
description: Lobbyist-meeting disclosures of the PM, Government Office and every ministry (quarterly XLSX/HTML).
module: lobi.mjs
execution: code
---
# Government Office and Ministry Lobby Meetings
Since the 2021 lobistidega suhtlemise hea tava, EVERY ministry publishes its ministers' and top officials' (kantsler, asekantsler, ministri nõunik) lobbyist meetings on its own site, at least quarterly. Bills are drafted in ministries, so for "who lobbied on this law" the drafting ministry's page is the first stop — the PM register covers only the Government Office.
## Retrieve
**Use `lobbyMeetings()` (below) — do not read the pages or workbooks by hand.**
One call resolves the body, picks the quarter's own workbook or the page's
disclosure tables, normalises every published column layout, filters by the
window and **counts the meetings in code**.
```js
const r = await lobbyMeetings("riigikantselei", { year: 2026, quarter: 1 });
show(r.totals); // { meetings: 21, firstDate: …, lastDate: … }
show(r.rows.slice(0, 5));
```
**The count is the thing this module exists for.** State `totals.meetings`.
Counting the rows you printed is a measured failure, not a hypothetical: runs
have answered 20, 22 and 20 for a quarter the register records 21 in, one of
them printing a 21-row table under a sentence that said 20, and an earlier one
said 68 by counting `
` rows on the page past the quarter's own section.
`body` accepts a key from `lobbyBodies()`, an Estonian name
("Rahandusministeerium"), or a ministry domain — an unknown domain is resolved
by trying `/lobitegevus`, `/lobistid`, `/lobistidega-kohtumised` in turn.
- `via` says which route ran: `xlsx` (a workbook covering the window) or
`html` (the page's own tables, for the bodies that publish no workbook).
- `totals.undated` counts rows the body published with no usable date —
siseministeerium.ee has cells reading "Jaanuar". They are left out of the
window rather than assumed into it.
- `read` lists every URL fetched; `source` is the one to cite, `page` is the
disclosure page a citizen can open.
## Access
The nine bodies below were opened and confirmed to carry the disclosure header
row on **2026-08-01**; `lobbyBodies()` returns the same list with the resolved
URLs, so a lookup costs no redirect.
- Government Office / PM: `riigikantselei.ee/…/lobistidega-kohtumised` — quarterly XLSX, one file per quarter. This is the only body whose page ALSO renders every past quarter as an HTML table, which is where the 68-row over-count came from.
- Ministries run one shared Drupal platform: `https:///lobitegevus`, else `/lobistid` or `/lobistidega-kohtumised`.
| Body | Format (2026-08-01) |
| --- | --- |
| Rahandusministeerium (`fin.ee`) | one `Lobiregister -veebi.xlsx` per year, plus the current quarter as an HTML table |
| Justiits- ja Digiministeerium (`justdigi.ee`) | per-quarter HTML accordions; older quarters as XLSX with one sheet per year |
| Majandus- ja Kommunikatsiooniministeerium (`mkm.ee`) | quarterly HTML accordions only; no XLSX since 2023 |
| Sotsiaalministeerium (`sm.ee`) | monthly HTML for the current year; yearly XLSX for the archive |
| `hm.ee`, `kliimaministeerium.ee`, `agri.ee`, `siseministeerium.ee` | HTML tables, quarterly or yearly |
**Not every ministry publishes.** `kul.ee`, `kaitseministeerium.ee` and `vm.ee`
answered 404 on all three aliases (checked 2026-08-01) — that is an absent
disclosure, not a broken page, and `lobbyMeetings()` says so by name.
If you ever read a page or workbook directly, the workbook has to arrive as
BYTES: an XLSX is a ZIP, so anything that decodes the response as text destroys
it (the archive's `fetchBytes` is what does this; `get()` calls `res.text()` and
will not). **Reading it then needs something that can open a ZIP and parse a
spreadsheet** — the archive's `xlsxRows` does it with no dependency, and any
spreadsheet library you already have does it too. Excel date serials such as
`45420` come back from `xlsxRows` already converted; whatever you use, state the
date and never the serial. On fin.ee the workbook links sit inside an embedded JSON widget
where the quote is `"` and every slash is `\/`, so a plain `href` scan
yields a path that 404s.
## Return
- One row per disclosed meeting: body, date, official (with post), lobbyist and
organisation, subject, and the URL the rows came from.
- Preserve names and organisation labels exactly as published.
- No two bodies use the same column headings — the module maps them by name, so
quote its `official`/`lobbyist` fields rather than a column position.
## Limits
- Cadence and layout differ per ministry (quarterly, monthly, yearly cumulative) and publication lags: on 2026-07-27 MKM's newest accordion was still 2026 I kvartal. An empty quarter can be a real statement — fin.ee: "2026. II kvartalis kohtumisi huvigruppidega ei toimunud."
- File naming dates do not always equal the covered quarter or revision date.
- **Absence from a disclosure is not evidence that no contact occurred.** The hea tava is a government guideline, not statute: it binds ministers and top officials, not every ministry specialist, and no one in the Riigikogu. Committee-stage lobbying appears nowhere in ANY of these pages. Worked example (verified 2026-07-26): in 2024 II kvartal the PM register lists 6 meetings and no food or beverage contact — in the exact quarter when four industry associations and the law firm Sorainen were working the sugared-drinks tax bill through the Rahanduskomisjon, all of it public in the bill's own document trail. Ministry pages close the drafting-stage part of that gap; for who entered a bill's parliamentary debate, still read the bill's opinion documents via `riigikogu-open-data` and ministry correspondence via `ministry-document-registries`.
- **We cannot open the workbooks with plain requests.** Several bodies publish a quarter only as an XLSX, and the bodies that also render HTML put every past quarter on one page — which is where the 68-row over-count came from — so without a runtime to unpack the file and filter by date, link the disclosure page and do not state a total.
- Route by who met whom: the PM register for the prime minister and riigisekretär, the drafting ministry's page for a bill under preparation, the bill's own document trail for the full picture.
## Verify
- A retrieval counts only when `totals.meetings` is a number and `rows` carries
a date and a lobbyist for each entry stated. `meetings: 0` with a `via` and a
`source` is a real finding — an empty quarter happens and fin.ee says so in
words ("2026. II kvartalis kohtumisi huvigruppidega ei toimunud").
- Ground truth, re-verified live 2026-08-01 with `lobbyMeetings()`:
Riigikantselei 2026 I kvartal = **21** meetings (2026-01-07 … 2026-03-27, via
the quarter's own XLSX), Rahandusministeerium 2026 I kvartal = **5** (via
`Lobiregister 2026-veebi.xlsx`). The same quarter counted off the
Riigikantselei page's HTML instead spans ten quarterly tables and 152 rows,
which is the over-count this recipe's module exists to make impossible.
- Never state a total the module did not compute. If you read a page by hand,
require its disclosure header row (Kuupäev / Kohtumise teema / Ametiisiku nimi
/ Lobisti või tema esindatava nimi) before quoting rows from it — and note
that four of the nine bodies word those headings differently.
## Module API
lobbyMeetings(body, {year, quarter, from, to}) -> {source, page, body, period, via, read, totals, rows, note}