← Blog

Mobile apps

Veterinary tablet PWA: clipboard intake retired in Leiden

A Saturday morning in Leiden, a bichon with a half-legible note about paracetamol, and six minutes to decide if anaesthesia is safe. The clipboard had to go.

Jacob Molkenboer· Founder · A Brand New Company· 7 Jun 2026· 8 min
Veterinary clipboard with handwritten note, folded linen cloth, green ribbon, wax pencil on ivory paper surface.

It is a Saturday morning at a clinic on the edge of Leiden. The waiting room has two cats, a bichon with a bandaged paw, and a teenager holding a shoebox. The duty vet is on his third coffee. A nurse hands him a clipboard with an intake form for the bichon. Stapled to it is a referral letter from a neighbouring practice, and a half-legible note that reads "owner thinks the dog ate paracetamol on Tuesday." Surgery is booked for 11:00. The vet has roughly six minutes to spot whether anything on that form means he should not put this dog under.

That is the moment a paper intake system fails. The information exists, the team is competent, the failure is mechanical: a human eye on three pieces of paper, under time pressure, looking for an interaction that might be one footnote in a 1,200-page pharmacology reference. Acetaminophen toxicity in dogs is well documented in the literature (see the Merck Veterinary Manual), and yet under real clinic conditions a note in cursive on the bottom of a form is exactly the kind of signal that gets missed.

A 28-person veterinary chain in Leiden, running six clinics across the Randstad, asked us to fix that. This is what we built, what worked, and the things we got wrong on the way.

The intake stack before the rebuild

Six clinics. Each one running the same Dutch practice-management system, configured slightly differently by whoever had set the clinic up four or five years earlier. Intake was paper. The paper was scanned at the end of each day. Scans went into a folder per patient inside the PMS. Nobody opened the scans again unless a case escalated to a referral or a complaint.

The chain had tried two things before they called us. A native iPad app from a vendor in Eindhoven, which took roughly twelve seconds to load a patient record on the clinic wifi. Nurses gave up after a fortnight and went back to paper. A Google Form embedded in the internal wiki, which technically worked, but had no link to the patient record, so the data ended up retyped into the PMS by reception staff who already had a queue of vaccination reminders to send out.

The practice manager put it cleanly in the first scoping call: "We do not have a software problem, we have a friction problem." Anything that added a step lost the team. Anything that needed a login during a consult lost the team. Anything that asked the vet to remember a workflow rule lost the vet. The brief was small in scope and absolute in standard: the new system had to be faster than the clipboard from the first day, or it was dead on arrival.

The tablet PWA, in concrete terms

We built a Progressive Web App, served from a single origin, that the clinic team opens on six iPads (one per consult room, plus a floater that lives at reception). It is a PWA, not a native app, for the reasons web.dev documents: one codebase, no App Store review on every patch, instant install from the browser, full offline support through a service worker. The team installs it once, pins it to the home screen, and from that point on it behaves like any other app on the iPad.

Login is once per device, per shift. A nurse taps the patient's chip against the clinic's existing chip reader, the record loads from local cache (typically 80 to 150 milliseconds), and the intake form is pre-filled with the last known weight, current medications, allergies, and chronic conditions. Anything new is typed by the nurse in front of the owner. The owner sees the screen. The owner corrects the spelling of their cat's name. That five-second loop is half the value of the entire project: the owner becomes a collaborator on the record instead of a person being talked at.

For the engineers reading, the cache strategy is intentionally boring. Workbox does most of the heavy lifting:

// service-worker.ts
import { registerRoute } from 'workbox-routing';
import { CacheFirst, StaleWhileRevalidate, NetworkOnly } from 'workbox-strategies';
import { BackgroundSyncPlugin } from 'workbox-background-sync';

// Patient records: serve cache, refresh in background.
registerRoute(
  ({ url }) => url.pathname.startsWith('/api/patients/'),
  new StaleWhileRevalidate({ cacheName: 'patients-v3' }),
);

// Static formulary: cache first, almost never changes.
registerRoute(
  ({ url }) => url.pathname.startsWith('/api/formulary/'),
  new CacheFirst({ cacheName: 'formulary-v3' }),
);

// Writes: queue offline, replay on reconnect.
const writeQueue = new BackgroundSyncPlugin('intake-writes', {
  maxRetentionTime: 24 * 60, // minutes
});

registerRoute(
  ({ url, request }) =>
    request.method === 'POST' && url.pathname.startsWith('/api/intake/'),
  new NetworkOnly({ plugins: [writeQueue] }),
  'POST',
);

The PMS integration is a webhook in both directions. When intake is saved, our server posts a structured payload to the PMS within a second. When the PMS updates a record (a vet adds a chronic condition after a consult, for example), it pings our server and the next clinic device that opens that record gets the refreshed copy through the stale-while-revalidate route.

The four-second drug-interaction check

This is the headline feature. Before any pre-surgical medication is confirmed, the app sends the patient signalment (species, breed, weight, age, organ-function flags) and the proposed drug list to a knowledge-base agent. The agent runs against a private corpus: the chain's house formulary, the chain's anaesthesia protocols, a licensed reference work, and a curated set of peer-reviewed interaction papers selected by the chain's clinical lead.

It returns one of three states, in under four seconds:

  • Green: no flagged interactions.
  • Amber: a known cautionary interaction, with the citation and a one-sentence summary.
  • Red: a hard contraindication, with citation, mechanism, and a suggested alternative drawn from the house formulary.

The retrieval architecture is deliberately not a chat. The vet never types a prompt. The input is the structured form data. The output is a deterministic block of flags rendered above the "Confirm" button. The vet still signs off. The agent is a second pair of eyes, not a decision-maker. This distinction mattered for the chain's clinical lead, who signed off on the design only after we agreed to remove the free-text query field from the prototype.

Takeaway

The agent does not make the call. It puts a citation in front of the vet's eyes during the four seconds when the call is being made.

Why four seconds? Anything slower and the muscle memory becomes "tap through the warning." We watched bypass behaviour climb sharply past about eight seconds on the first prototype, and drop to near zero once the round trip fit inside the natural pause between picking a drug and tapping confirm. The latency budget was a behavioural constraint, not a technical one. The technical work was making sure we could meet it from the worst clinic on the worst connection on the worst Saturday.

The offline-first contract

This is the part nobody puts in the demo video. A Leiden veterinary clinic has thick walls, an X-ray suite that interferes with 2.4 GHz, and a fibre line that occasionally drops for ninety seconds while the ISP renegotiates. The PWA has to keep working when the network does not. The Background Synchronization API handles the happy path: every form submission writes locally first, returns success to the UI, and replays to the server when connectivity returns.

The drug-interaction check has its own contract. If the agent cannot reach the knowledge base within 4.5 seconds, the form shows a yellow "offline check only" indicator and falls back to a locally cached subset of the formulary covering the top 60 surgical drugs the chain actually uses. The vet sees, immediately, that the check was partial. We made the degradation visible rather than hide it. A silent fallback is worse than a missing feature: if the agent runs on stale data and the vet does not know, you have built a liability, not a tool. That visibility is what kept the clinical lead comfortable with shipping the offline path at all.

The rollout, clinic by clinic

We rolled out one clinic at a time, two weeks apart. The first clinic took five weeks of small fixes before the nurses stopped reaching for the clipboard. The sixth took four days. The difference was not the software. The practice manager learned how to introduce the tool. She stopped saying "this replaces your intake form" and started saying "this is your intake form, on a tablet, that fills itself in." The second framing held.

We also learned, around the third clinic, that we had built the wrong undo flow. If a nurse hit submit and the owner immediately corrected something (the dog's weight, usually), you could fix the record, but the agent had already run on the pre-correction data and the flag was stale. We added a 90-second mutable window with automatic re-check. That should have been there from day one. It was not, because the design assumed the form was a single atomic event. The form is not a single atomic event. It is a five-minute conversation that ends in a save.

Numbers after ten weeks

These are the chain's numbers, measured by their practice manager on a sample they timed themselves. Not industry averages, not extrapolations, not the kind of figure you scale up by guess. One client, ten weeks, with a stopwatch.

  • Average intake duration: 6.5 minutes per patient down to 2.1 minutes, across a sample of 80 consults timed before and after.
  • Pre-surgical interaction flags surfaced by the agent that the vet had not already noted: 14 over ten weeks. Eleven were amber (consult and continue), three were red (drug substitution).
  • Reception retype time: effectively zero. Intake data lands in the PMS through the server-side webhook the moment the form syncs.
  • Vet time saved per week, chain-wide: roughly 18 hours. Reception time saved: about 26 hours.

Nobody was let go. Two reception roles shifted to client communications, which was where the chain had a real backlog (post-op call-backs, vaccination reminders, the sort of work that used to fall through the cracks of a paper day). That redeployment is, honestly, the number the practice manager cares about most.

What we would do differently

Three things, briefly. We would build the mutable submission window on day one rather than ship it as a patch. We would put the offline indicator on the form header rather than next to the drug check, because nurses associate connectivity with the whole record, not with one field. And we would invest earlier in the chain's clinical lead being the voice of the rollout, rather than us being it. Software adoption inside a clinical team is a question of who is asking, not what is being asked for.

When we built this for the Leiden chain, the part of the project that earned us the trust to ship the agent was the unglamorous offline behaviour. Nurses do not adopt a tool that fails the first time the wifi blinks. If you want to see how we approach this kind of work, our AI agents page describes the architecture in more depth. The smallest thing you could do this week: time your own intake on ten consults with a stopwatch, and write the number on a sticky note. If it is over four minutes, you have a project worth scoping.

Key takeaway

The agent does not make the call. It puts a citation in front of the vet's eyes during the four seconds when the call is being made.

FAQ

Why a PWA instead of a native iPad app?

One codebase, no App Store review for every fix, full offline support through a service worker, and instant install from the browser. The chain's prior native app took twelve seconds to load a record and nurses gave up on it.

How does the knowledge-base agent stay current with new drugs?

The corpus is versioned. The chain's clinical lead reviews additions monthly. New drugs and protocols are added to the private formulary, and the cache invalidates on the next device load.

What happens if the agent gets a flag wrong?

The vet signs the prescription, not the agent. Every flag carries a citation that opens in one tap. The system logs both the flag and the vet's decision for clinical audit.

Does this architecture scale to a larger chain?

The technical architecture does. The harder scaling problem is the rollout playbook: the practice manager's framing was as important as the code. Plan for that, not just for the engineering.

mobile appsai agentsragknowledge basecase studyworkflow

Building something?

Start a project