Full class, empty floor: where waitlist promotion silently fails
In short
A class that shows full and runs half empty is almost always a timing defect rather than a member-behaviour problem. Measure the interval between a cancellation and a promoted member being able to act on it: where that interval is shorter than travel time plus changing time, no promotion offered in that window can succeed, and the spot was lost the moment the cancellation arrived.
Key takeaways
- A promotion is only real if the offer lands before travel time plus changing time runs out.
- Instrument 4 timestamps per cancellation: cancelled, offered, delivered, deadline. The gaps name the fault.
- An acceptance window that extends past the class start holds a spot nobody can use and re-offers it to nobody.
- Measure notification delivery, not sends. A promotion loop over a channel members have muted is a lottery.
- Held spots for staff, trials and guests need an owner and an automatic release time, or they are a permanent capacity cut.
The class is capped at 24, the app shows 24 booked with 9 on the waitlist, and 17 people are on the floor. Nothing about that is a mystery once you look at the clock rather than at the members. Somewhere between a cancellation at 17:52 and a class starting at 18:30 there is an interval in which a promoted member has to be told, decide, travel, change and arrive. When that interval is negative, the promotion loop still runs, still sends, still reports success, and still leaves the spot empty.
So this is a latency diagnosis, not a policy one. Whether to sell more spots than you have is a separate argument settled in hard cap or overbooking for class capacity. What follows assumes the cap is right and asks why the seats under it are not being filled.
The check: four timestamps per cancellation, for one week
Instrument the loop before touching it. Every cancellation on every class for 7 days, with 4 timestamps and 2 derived numbers.
- Cancellation accepted. When the member's cancellation was written, to the second, and by which route — app, web, front desk or a message to the coach.
- Promotion offer created. When the system decided who to offer it to. The gap between this and the first timestamp is your scheduler lag.
- Notification delivered. Not sent — delivered, from the push service or email provider receipt. If you cannot get delivery receipts, that is your first finding.
- Acceptance deadline. When the offer expired or was accepted, and by whom.
- Derive the actionable window: class start, minus your required lead time, minus the delivery timestamp. Negative means the offer was never usable.
- Derive the outcome: accepted and attended, accepted and absent, expired, or never offered at all.
One evening, five empty spots, one recoverable
| Cancelled | Offer delivered | Deadline | Actionable minutes | Outcome |
|---|---|---|---|---|
| 15:40 | 15:45 | 16:45 | +135 | Accepted, attended |
| 17:52 | 18:01 | 19:01 | -1 | Expired after the class ended |
| 18:05 | 18:16 | 19:16 | -16 | Expired after the class ended |
| 18:22 | Never — next job ran at 18:30 | None | -22 | No offer made |
| Never cancelled | No event fired | None | n/a | Silent no-show |
Five spots, 1 filled. Two were offered to real people at times those people could not possibly use, and the 60-minute acceptance window then held both spots until well after the class finished — so nobody further down the list was ever asked either. One arrived too late for the scheduler to see. One never generated an event at all.
An acceptance window that outlives the class is not generosity. It is a spot taken off the market at the exact moment it was most needed.
Six causes, ranked by how often they are the whole story
| Cause | Signature in the data | Fix owner |
|---|---|---|
| Promotion runs on a schedule | Offer times cluster at fixed minutes past the hour | Whoever owns the job scheduler |
| Acceptance window outlives the class | Deadlines after class start; no second offer made | Product owner, one config change |
| Notifications not delivered | Sends far exceed delivery receipts, or none exist | Mobile and messaging |
| Cancellation fires no event | Front-desk and coach-message cancellations missing entirely | Whoever owns the desk process |
| Held spots never released | Capacity permanently below the nominal cap | Named owner per hold type |
| Capacity counted on bookings only | Full on paper while check-ins run well below cap | Product owner |
Delivery, not sends — the number most clubs never look at
A promotion loop is a notification product. If the message does not land on a locked screen within seconds, everything upstream of it was wasted effort, and the send count in your dashboard will not tell you that it did not.
- Count members with push actually enabled. Not installed — permitted. If that share is under roughly 60% of your active members, promotion is a lottery and no amount of scheduler tuning changes the odds.
- Treat a promotion as time-critical on the platform. Ordinary notifications can be batched or held back by the operating system; a spot expiring in 12 minutes has to be sent on the channel that wakes the device.
- Instrument the second channel. Email arrives in a promotions tab hours later. Text messages land reliably and cost money and irritate people. Pick per urgency, and measure both.
- Design for one tap from the lock screen. If accepting requires opening the app and logging in again because the session expired, you have added 90 seconds to a window measured in minutes.
- Assume the network is poor at exactly the wrong moment. Members are in basements, car parks and on trains — the same delivery reality that shapes streaming a match from a ground with one bar of signal.
Held spots and the capacity that was never really there
Before blaming the loop, count the seats. A class capped at 24 often has fewer than 24 sellable places because of holds nobody remembers creating: a coach's guest, 2 trial spots the sales desk asked for, a bike reserved for a member returning from injury, a place kept back for staff. Each is defensible. Together they can remove a fifth of the room permanently.
- Give every hold an owner and an automatic release time. A hold with no release time is a permanent capacity cut wearing a temporary label.
- Release trial holds on a schedule that matches how trials actually book, which is usually same-day and rarely a week ahead.
- Derive capacity from the physical resource, not a number typed into a class record — the modelling problem solved in pitches, courts and lanes as bookable units.
- Reconcile the nominal cap against sellable places weekly. Where they differ, the difference is the report, not an error to quietly correct.
- Watch for classes cancelled late because no coach was assigned, which dumps a whole cohort into the promotion loop at once — the failure that publishing a coach rota that survives contact with the week exists to prevent.
The promotion policy, with an explicit cut-off
One policy, expressed against the clock rather than as a set of defaults. The cut-off is the part almost every configuration is missing.
- Set required lead time per class and venue from your own check-in data. Everything below is relative to it.
- Earlier than 2 hours before start: offer to 1 member at a time in list order, with a 30-minute acceptance window. Fairness is affordable while there is time.
- Between 2 hours and the lead-time boundary: shrink the acceptance window to the minutes remaining minus the lead time, and once that drops below about 20 minutes, offer to several members at once with first acceptance winning.
- Inside the lead-time boundary: stop offering. Flip the class to walk-in, show the true remaining count in the app, and let anyone already in the building take the place.
- At the start time: release every spot not checked in, and let the coach admit from the door. Bookings become check-ins here, and the 2 numbers were never the same measurement.
- Never let an acceptance window cross the class start. Expire it at the boundary and re-offer while re-offering is still worth something.
- Log every offer, delivery, acceptance and expiry with actor and timestamp, so next quarter's version of this question is a query rather than an argument.
Decision tree
- Offer times cluster at fixed minutes. Make promotion event-driven off the cancellation, not a polled job. This is usually a same-week change and it recovers the largest share of spots.
- Deadlines fall after the class starts. Cap the acceptance window at the lead-time boundary. One configuration change, and it is the cheapest fix on this list.
- Sends look healthy and delivery receipts do not exist. Fix measurement before behaviour; you cannot tune a loop whose output you cannot see.
- Front-desk and coach-message cancellations are missing. The event is not firing because the cancellation never entered the system. That is a desk process with a software gap behind it.
- Check-ins run consistently below a cap that is always full on paper. You are counting bookings as capacity. Start counting attendance, then decide separately whether to sell against the difference.
- Everything above is clean and classes still run short. The remaining gap is genuine no-shows without cancellation, which is a policy question rather than a timing one.
Most of this is a fortnight of work on the loop you already have: an event on cancellation, a bounded window, delivery receipts and a cut-off. Where the booking layer itself cannot express any of that, it becomes a small product build around the existing system rather than a replacement of it. The rest of the silo — capacity, registers, allocation — sits under scheduling, attendance and the facility, within our sports, fitness and athletics practice.
Frequently asked questions
Short answers to the follow-ups this page tends to raise.
Why does a gym class waitlist not release spots when people cancel?
Usually it does release them, but too late to be usable. The offer is created by a scheduled job rather than by the cancellation event, the notification takes another minute to land, and by then the promoted member cannot travel and change before the class starts. Measure the minutes between cancellation and delivered offer against class start minus travel and changing time; where that number is negative, the loop is working exactly as configured and the spot was never recoverable.
How long should a waitlist acceptance window be?
Long enough to be answered, and never long enough to cross the class start. Two hours out, 30 minutes is reasonable. Thirty minutes out, the window should be a few minutes and the offer should go to several members at once. A fixed 60-minute window applied close to the start holds the spot past the point of use and prevents anyone further down the list from ever being asked.
Should a late cancellation still free up the spot?
Yes, but stop trying to promote into it once the offer can no longer be acted on. Inside your required lead time, release the place to walk-ins and show the real remaining count in the app instead of continuing to notify people who cannot arrive in time. Whether the late-cancelling member is charged is a separate policy question and should not be tangled with the release mechanism.
How do we tell a promotion timing problem from members simply not turning up?
Split the empty places by whether a cancellation event ever fired. Places vacated by a cancellation with a negative actionable window are a timing defect you can fix in software. Places where nobody cancelled at all are no-shows, and no promotion loop can help because the system had no idea the seat was free. Clubs routinely find both and spend all their effort on the wrong one.
- waitlists
- class booking
- notifications
- capacity
The work behind this page
Builds from our portfolio that this page draws on.
DockQueue
A dock scheduling and yard management platform that lets carriers self-book dock appointments, assigns the right door on arrival, and tracks every trailer's dwell and detention live.
LogisticsReply Rail
AI-drafted Google, Yelp, and Facebook review responses for local businesses — one queue, one click.
Local Business AIRead next
- Court utilisation is a fraction, and the denominator is the argumentBooked, attended and revenue-bearing over available: three honest utilisation numbers for one week, and the denominator argument that decides all three.definition
- A session series is not eighteen sessions: the recurrence record explainedA series is a rule plus an exception list, not a pile of rows. Every confusing this-event-or-all-events prompt comes from that one storage decision.definition
- Lapsed members are still getting through the doorThe door holds its own copy of who may enter. That makes revocation a push you have to design, and puts the fault in the timing and direction of that push rather than in your membership data.diagnostic
- What an attendance mark has to mean before you can count anythingAn attendance mark is a value from a small vocabulary plus an author, a timestamp and an amendment history. A tick box cannot answer a single question a club actually asks of a register.definition
- A guardian is not a member: the account type most club software lacksMost club systems model a parent as a member who happens to have children attached. That works until a household disagrees about who may do what, which happens constantly.definition
- Freeze, pause, hold: three words, three different billing outcomesA freeze moves dates. Which dates — the next collection, the agreement end, or both — is a product decision most clubs never wrote down, and every freeze argument starts there.definition
Working on something in this space?
Tell us where you are in a sentence or two. We'll tell you honestly whether we're the right team, and what a sensible first slice of the work looks like.
Start the conversation