All case studies
Case Study

Case Study: Rescuing a Booking System That Failed Silently

A clinic's online booking widget showed success while the backend failed. Here's how I reproduced it, found the identity collision, and fixed it.

US medical practice·August 1, 2026·7 min read
Table of contentstap to expand

A US clinic group came to me with a problem that looked random. Some patients would finish the online booking, see a confirmation, and then never appear on the right chart. Staff usually found out when the patient called asking where their appointment went. The widget said success. The backend disagreed. That gap between what the patient sees and what the system actually did is the whole story, and it costs practices more patients than they realize.

This is a de-identified write-up of a real engagement for a NYC healthcare group running Google Ads for calls and online bookings. No names, no patient data, no account IDs.

Quick answer

What it looked likeWhat was actually happening
Bookings vanished at randomAn identity collision filed appointments onto the wrong patient's chart
Some patients never got a confirmationEmail came from a free mailbox with no SPF, DKIM, or DMARC, so it went to spam
Text confirmations were "unreliable"SMS sends were failing systemically at the provider, not intermittently
The widget always said it workedThe frontend reported success without reading the API response

The bug was not random. It only felt random because four separate failures overlapped, and the frontend hid all of them behind a success screen.

The problem: patients booked, the clinic never saw it

The symptom the client described was lost revenue with no pattern. A patient would book, get a confirmation on screen, and then not exist in the schedule. Others booked fine. There was no obvious segment, no error the staff could point to, and no reliable way to reproduce it on demand. When a system fails without a pattern, the pattern is usually that several small failures are stacked on top of each other.

The dangerous part was the confirmation screen. Because the widget told every patient "you're booked," the business never learned when a booking was lost. A quiet failure that looks like success is worse than a loud failure, because nobody files a support ticket for a problem they think does not exist.

How I diagnosed it: reproduce first, then check the source of truth

I did not start by reading code and guessing. I started by reproducing the failure live, then checking what the two sources of truth actually contained: the application database and the scheduling API. Guessing at a booking bug from the frontend is how you spend a week fixing the wrong thing.

The sequence was:

  1. Reproduce a booking end to end and capture the exact request and response.
  2. Look up what the database wrote for that submission.
  3. Query the scheduling API for the appointment the database claimed to have created.
  4. Compare all three against what the patient saw on screen.
Reproduce
capture request + response
Database
what it actually wrote
Scheduling API
was it really created
Compare
all three vs the screen
Reproduce first, then compare the three sources of truth against what the patient actually saw.

Step four is where it broke open. The frontend was showing a confirmation on submissions where the backend had returned an error, and it was showing confirmations for appointments that had been created under the wrong patient. The UI was not lying on purpose. It simply never checked.

// The anti-pattern I found: any settled request counts as a win
async function submitBooking(payload) {
  const res = await fetch("/api/book", { method: "POST", body: JSON.stringify(payload) });
  showConfirmation();   // fires no matter what came back
  return res;           // a 400 or 500 sails right past
}
 
// What it has to do: trust the API response, not the fact that fetch resolved
async function submitBooking(payload) {
  const res = await fetch("/api/book", { method: "POST", body: JSON.stringify(payload) });
  if (!res.ok) return showError(res.status);        // 400 / 500 -> honest failure
  const data = await res.json();
  if (!data.appointmentId) return showError("no-appointment-created");
  showConfirmation(data.appointmentId);              // only now is it real
}

The root causes

Diagnosis turned one random-looking bug into a short, concrete list. Three real causes, plus the frontend behavior that hid them all.

  • An identity collision in the matching logic. A customer record in the booking system had been linked to the wrong patient chart in the scheduling system. Every new booking for that customer was filed onto someone else's record. The appointment was not lost, it was misfiled, which is exactly why the front desk could not find it under the right name.
  • Confirmation email with no authentication. Confirmations were sent from a free mailbox with no SPF, DKIM, or DMARC. Mailbox providers filtered them, so a patient who genuinely booked often got nothing in their inbox and assumed the booking had failed.
  • Systemic SMS failures. The text confirmation, the fallback channel, was failing to send at the provider level. So both confirmation paths were dark at the same time.
  • A frontend that reported success unconditionally. This is the multiplier. Any one of the above is survivable if the patient sees an honest error and calls the front desk. Instead they saw "you're booked" and went home.

The fix

I fixed the cause that kept creating new bad data, and documented the delivery fixes so the client could execute them without me touching mail or telecom credentials.

  • Matching logic. I corrected the mislinked record and changed the matching so an ambiguous match can no longer silently bind a customer to the wrong chart. New collisions cannot happen the same way; an uncertain match surfaces for review instead of guessing.
  • Email deliverability. Documented moving confirmations to an authenticated sending domain with SPF, DKIM, and DMARC in place, so the mail stops landing in spam.
  • SMS. Documented the provider-side configuration fix so texts actually send, restoring the second confirmation channel.
  • The success signal. The widget now confirms against the real API response and the created appointment ID, not the mere fact that the request completed.

Throughout, the work stayed HIPAA-conscious. Patient data was never persisted into logs or exports, phone numbers used in matching were hashed, and on the reporting side only an anonymous click id, a value, and a timestamp ever leave the system. That same discipline is what makes clean Google Ads conversion tracking possible for a medical practice: you can measure which ad produced a booked visit without ever moving patient data.

Once the booking record is trustworthy, it becomes the input for offline conversion tracking setup, so the clinic finally learns which spend produced a real appointment rather than a form submission that may or may not have landed.

I will not invent throughput numbers here, because I did not measure the before-and-after volume and I am not going to make one up. What I can say is verifiable: the engagement was delivered and rated 5.0. It was a clean win.

The takeaway: a fake success is worse than an honest error

If you take one thing from this, take this: a booking widget that shows "success" when the backend returned a 400 or 500 is worse than one that shows an error. An honest error sends the patient back to the front desk, and the business learns it has a problem. A fake success sends the patient home and teaches the business nothing while it quietly loses people.

Verify the success signal against the actual API response, not the UI. It applies to bookings, to form fills, and to every conversion you report into an ad platform. A confirmation screen is a claim. The API response is the fact. Report the fact.

If your booking flow or your conversion numbers feel a little too smooth, that is often the tell. I am happy to trace one real submission end to end, from the click to the created record, and tell you whether your success signal is real or decorative. That single trace usually settles it.

Tags

case studyconversion trackingbooking systemhealthcaredebugging

Frequently asked questions

Why do some online bookings never show up in the schedule?

The most common cause is a matching bug that files the appointment onto the wrong record, so it exists but staff cannot find it. The second is a widget that reports success even when the backend returned an error, so nothing was ever created. Both look random from the front desk.

Why do my appointment confirmation emails land in spam?

Almost always because they are sent from a free mailbox or a domain with no SPF, DKIM, and DMARC records. Mailbox providers treat unauthenticated mail as suspicious and filter it, so patients who really did book never see a confirmation. Moving to an authenticated sending domain fixes the bulk of it.

How do I know if my booking widget is silently failing?

Check whether the frontend confirms success based on the API response or just the fact that the request finished. If it shows a confirmation screen without reading the status code and the created appointment ID, it will happily report success on a 400 or 500. Log the real response and compare it to what the schedule actually contains.

Can you fix a booking system without exposing patient data?

Yes, and for a US medical practice you have to. The work here was HIPAA-conscious: patient records were never persisted into logs or exports, phone numbers used for matching were hashed, and only an anonymous click id, a value, and a timestamp ever left the system for ad reporting.

What is the difference between a check-in and a completed booking?

A booking request is what the patient submits; a confirmed appointment is what the scheduling system actually created and filed on the correct chart. A reliable system only shows the patient a confirmation once the second thing is true, not the first.

How long does a booking-flow rescue like this take?

Most of these are a focused two to four week engagement, because the hard part is diagnosis, not code volume. Reproducing the failure against the real database and scheduling API is what turns a random-looking bug into a short, concrete fix list.

Want this loop closed on your account?

I connect your EHR, booking system, and calls to Google Ads so it counts patients who actually showed up. HIPAA-conscious, fixed price, verified in the account.

More case studies