Blue Reacher
No-show recovery48 / 50

No-show recovery

Catch a missed appointment within the hour, rebook it in the thread, and stop after two attempts.

The problem

A booked appointment that does not happen costs more than a lead that never books, because you paid to acquire it and then held time for it. Most teams send one apologetic email and move on.

Recovery works because the person already wanted the thing. They just missed a slot.

The build

Trigger when an appointment passes without being marked attended, send inside the hour, offer times in the thread.

// runs on your scheduler, e.g. every 15 minutes
for (const appt of await crm.findMissedAppointments({ withinMinutes: 90 })) {
  await fetch("https://api.bluereacher.com/v1/messages", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.BLUEREACHER_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      to: appt.phone,
      message: `Hey ${appt.firstName}, we had you down for ${appt.timeLabel} today and missed you. No stress, things come up. Want me to grab you a spot tomorrow instead?`,
      send_mode: "instant",
      metadata: { crm_id: appt.recordId, recipe: "no-show-recovery" }
    })
  });
}

Tone carries this one. No guilt, no "you missed your appointment" formality, no cancellation-policy language. The message that rebooks is the one that assumes something reasonable happened.

Timing

First message within an hour of the missed slot, while it is still today's problem and they may still be free. Second message two days later if there is no reply. Then stop.

Sending the next morning instead of the same hour measurably reduces recovery, because by then the person has re-planned their week.

The instinct is to send the booking link. It performs worse. Ask the question, and when they reply, offer two specific slots:

Great. I've got Thursday 10am or Friday 2pm, either work?

Two options gets an answer; an open calendar link gets a "let me look at my week". Send the confirmation link after they pick, which is also the point where a link belongs, per links and previews.

Feed the outcome back

On reply, cancel the sequence and flag the record for a human. On rebooking, write the new appointment back to the CRM so the recovery is attributable:

if (e.event === "message.received") {
  const recordId = await crmIdForPhone(e.data.phone_number);
  await crm.update(recordId, { noShowReplied: true, lastReply: e.data.content });
  await sequences.cancel({ recordId });
  await notify(`No-show replied: ${e.data.content}`);
}

Stop at two

Two messages. Someone who missed the appointment and ignored two follow-ups is telling you something. Move them to the reactivation list and come back in a quarter with a genuinely new reason, per list reactivation.

Prevention beats recovery

The cheapest no-show is the one that does not happen. Run appointment reminders alongside this recipe; teams that add reminders usually cut the volume this recipe has to handle substantially.

What to measure

Rebooking rate on messaged no-shows, and the split between message one and message two. If message two is doing most of the work, your first message is going out too late.

On this page