Reserve-duty pay: from scraper to Chrome extension

Originally published as a LinkedIn post, expanded here.

Code on GitHubOmerLapidot/btl-scraper

I built a Chrome extension that reads your own account on the Bituach Leumi portal — Israel’s national insurance institute, which pays reserve-duty compensation — and collapses it into one table: days of reserve duty on record, what the compensation is worth, who it was paid to, and what is still unpaid. Before it I had a scraper doing the same job from my machine, but that requires storing an ID number, a user code and a password in a file. For me that is fine. For anyone else it is not acceptable. That difference, not a product decision, determined the architecture.

The tool is not finished. I published it to get notes, not to have anyone rely on it.

The money arrives on two tracks, and most people check only one

Miluim — Israeli reserve military duty — is compensated through two separate channels. Part goes straight to your bank account from Bituach Leumi. The rest is reimbursed to your employer, who pays it through your payslip. Employer-route money never appears in the bank as a transfer from the institute, so anyone checking only their current account concludes money is missing, and anyone checking only their payslip sees half the picture.

There is also a 40% supplement. I verified against the raw data that it is 40% of the daily compensation times days served — an addition above the base, not part of it — and it too splits between “paid to you” and “paid to the employer”. In the portal all of this sits across separate tabs, in tables that slice the periods differently in each one.

Step one: a scraper I could only give to myself

The first tool was a Node program that logs into the portal’s API and reads everything: insurance status, national-insurance and health-premium debt, benefits debt, the collection ledger, reserve-duty data, documents you uploaded, past inquiries, and every letter as a PDF. It has no npm dependencies; it talks to the portal through Node’s built-in fetch.

The one thing I insisted on was that it be read-only, enforced structurally rather than declared. A frozen list of paths lives in the code, and every request passes a check that throws before any network call if the path is not on it. No pattern matching, no probing. Adding a data source is a deliberate edit to that list.

It worked well. It just was not something I could hand to another person.

The fix: ride the session you already have

The extension never asks for a password, never sees one, never stores one. You log in yourself, as usual, and from there it uses the session your browser already holds to call the same endpoints the portal’s own app calls.

That was less straightforward than it sounds. The portal moved its token: it used to sit under a tidy sessionStorage key, and now it is buried inside the user object. Rather than hardcode a path that breaks on the next release, the code scans the whole storage tree — first for anything shaped like a JWT, then by key name.

Decisions that followed directly:

  • Minimum permissions. Access to ps.btl.gov.il and nothing else.
  • Fetched data never touches disk. What is fetched is held in memory and discarded when you close the browser.
  • No outbound calls. Fonts are bundled into the stylesheet, a strict CSP is applied, and the only request that leaves is to the portal — the origin you are already logged into.
  • Diagnostics that cannot leak. The “why didn’t this work” panel shows storage key names and a token length, never values. On a failed call only the numeric status is recorded, not the response body, which on an authenticated endpoint can drag the user’s name and ID number into a log.

The reserve-duty math in the extension is a verbatim port of the scraper’s, and I checked that the two produce identical output rather than let one copy drift.

The output: a table, then a file you can hand to any LLM

The table is the main output. All it really does is make a hard-to-read interface readable. Beside it is a period selector — everything, a year, the last 12 months, a custom range — and every number on the page follows it.

The second button downloads a Markdown file. Not a data dump: two separate tables — what should show up in the bank, what should show up in the payslip — plus instructions for checking. You hand it, your payslips and your bank statement to whichever LLM you already work with, and ask it to flag what is missing. The report masks your ID number to its last four digits; your name does appear in the header. That file is also the one exception to the never-touches-disk rule, which is why downloading it is a deliberate act on your part.

I stopped there deliberately instead of building an agent that runs the comparison itself. A payslip and a bank statement are sensitive material, and the choice of who receives them should stay with you.

Unpaid periods carry an estimated amount, labelled as an estimate: it comes from the most recent average daily rate paid to you, not an official figure. The paid/pending status comes from the portal’s own flag, not from whether the period appears in the 40% table — plenty of paid periods have no row there yet, and that is the kind of mistake that makes a tool like this lie with confidence. Each money row attaches to the one period it overlaps most, so nothing is counted twice.

What still does not work

  • The letters table shows date and subject only. A bottom line per letter needs PDF text extraction plus a summary, which will not run inside a purely local extension.
  • Letter files themselves are not downloaded, only the list.
  • No scheduling, no alerts. This is the click-and-look version.
  • The floating button in the corner depends on auto-detecting your login and does not always appear. The toolbar icon always works; that is the path I recommend.

The full process has several stages and I have built the first: what was paid, for what, when, to whom, and whether it arrived. Chasing down what did not arrive, and actually claiming it, are still ahead.

What I took from it

The decisive choice here was not technical — it was who the user is. A tool that runs only on my machine can keep passwords in a file and be fine. Aimed at someone else, the identical tool needs an architecture where I have nothing to lose: no password, no data, no server. That is not hardening bolted on at the end; it decides where the code runs.

This recurs in almost every automation I build inside an organization: who holds the keys comes before what the tool does. It is what my working process is built around.

Questions people ask

How do I check whether I received all the reserve-duty pay I am owed?

You have to look in two places, not one. Part of the compensation is transferred straight to your bank account by Bituach Leumi (Israel's national insurance institute), and part is reimbursed to your employer, who pays it to you through your payslip — so the employer-route money never shows up in the bank as a transfer from the institute. The extension I built separates the two tracks and produces a check file that spells out what to look for in each.

Does a Chrome extension that reads Bituach Leumi see my password?

No, and that is the reason it became an extension in the first place. You log in to the portal yourself, and the extension rides the session your browser already holds. It never asks for, sees, or stores a password, and the data it reads is kept in memory only and discarded when you close the browser.

What is the 40% supplement in Israeli reserve-duty compensation?

From what I verified against the portal's raw data, it is an addition calculated as 40% of the base daily compensation times the number of days served — an amount on top of the base, not a slice of it. It is also split between sums paid directly to you and sums reimbursed to your employer, which makes it one of the easiest components to miss.

Is this tool ready to use?

No. It currently does only the first step — working out what was paid, for what, when, and to whom — with no scheduling, no alerts, and no letter downloads. I am looking for people who will use it critically and send me notes, not people who will rely on it.