A crowded waiting room, customers asking "what number are we on?" every five minutes, and staff shouting names across the counter are signs that the service flow has outgrown pen and paper. It is not only about comfort: people who wait without any sense of progress are more likely to walk out. This guide covers how to design a simple, reliable digital queue system, whether you are choosing a product or building one yourself.
Parts of a Digital Queue System
- Ticket issuing: a kiosk or tablet on site, a mobile web page reached through a QR code at the door, or registration by staff.
- Calling: the agent presses "call next" and the system assigns the next ticket by order and service type.
- Display screen: a TV in the waiting area showing which number each counter is serving, ideally with an audio announcement.
- Notifications: a text message when the customer is a few places away, so they can wait outside.
- Metrics: average wait time, average service time, and peak hours.
You rarely need all five on day one. A one-bay repair shop might only need tickets and a display. A multi-department clinic needs service types and reporting.
Choosing a Type of Solution
| Option | Pros | Cons | Good fit |
|---|---|---|---|
| Physical ticket dispenser + display | Familiar, no phone needed | Hardware and paper costs, hard to analyze | Public offices with visitors of all ages |
| Queue SaaS (e.g. Qminder, Waitwhile) | Live within days, no server to run | Monthly fee, data held by a vendor, limited customization | Businesses that want to start this week |
| Custom web app | Fully tailored, links to customer or patient records | Needs a developer and hosting | Clinics and shops that already run other systems |
| Messaging-based queue | Nothing to install for customers | Needs an official messaging API | Appointment-driven services |
The criterion most people forget is integration. If a clinic's ticket is not linked to the patient record, staff still retype identity details into another system.
Design the Flow Before the App
- Define service types. In a repair shop, for example: "Quick Service" (A), "Major Repair" (B), "Pickup and Payment" (C). Each has its own number sequence.
- Map counters to services. Counter 1 handles A and B; counter 2 handles only C. That drives the "call next" logic.
- Define ticket statuses. At minimum: waiting, called, serving, done, skipped.
- Decide the no-show rule. Can a skipped customer be recalled, and how many times?
- Decide when numbers reset. Usually daily, back to A-001.
Table Design
services : id, code (A/B/C), name, avg_minutes
counters : id, name, is_active
counter_service : counter_id, service_id
tickets : id, service_id, number, queue_date, status,
counter_id (nullable), customer_phone (nullable),
called_at, served_at, finished_at, created_at
UNIQUE (service_id, queue_date, number)
The timestamp columns feed every metric you will want later, so keep them. For the reasoning behind relations like these, see designing a simple ERD for your app.
Issuing Collision-Free Numbers in Laravel
The classic bug in home-grown queue apps is two customers receiving the same number because they tapped at the same moment. The app reads the last number, adds one, and saves, with no locking. The fix is a database transaction with lockForUpdate, backed by a unique index.
use App\Models\Service;
use App\Models\Ticket;
use Illuminate\Support\Facades\DB;
public function take(Service $service): Ticket
{
return DB::transaction(function () use ($service) {
// Lock the service row so concurrent requests wait their turn
Service::whereKey($service->id)->lockForUpdate()->first();
$last = Ticket::where('service_id', $service->id)
->whereDate('queue_date', today())
->max('number');
return Ticket::create([
'service_id' => $service->id,
'queue_date' => today(),
'number' => ($last ?? 0) + 1,
'status' => 'waiting',
]);
}, attempts: 3);
}
"Call next" works the same way: inside a transaction, select the oldest waiting ticket for services that counter handles with lockForUpdate(), then set it to called with the counter id and called_at. Without the lock, two counters can call the same person.
Display Screen and Announcements
The simplest display is a page that polls a JSON endpoint every three to five seconds. For a single site with a few counters, that is perfectly adequate and easy to maintain. For instant updates, use Laravel broadcasting with Laravel Reverb or a hosted service such as Pusher.
For audio, the browser's built-in Web Speech API (speechSynthesis) works with many languages, or you can stitch together recorded clips. Browsers block autoplay audio until the user interacts, so add an "enable sound" button staff press once each morning.
Wait Estimates and Notifications
A simple estimate is people ahead multiplied by average service time, divided by active counters. For example, 6 people ahead, 8 minutes per service, and 2 counters gives about 24 minutes. Show a range ("about 20-30 minutes") rather than a precise figure, and compute the average from the last two to four weeks of data. Send "you are 3 places away" messages through SMS or an official messaging API from a queued job, as covered in Laravel queues and jobs, so the call button stays fast.
Metrics That Matter
- Wait time:
called_atminuscreated_at, averaged and maximum per hour. - Service time:
finished_atminusserved_at, per service type and counter. - No-show rate: share of skipped tickets. A high rate may mean estimates are scaring people off.
- Hourly distribution: tickets per hour across the week, to decide when to open an extra counter.
Common Mistakes
- Duplicate numbers from missing locks. Fix: transactions, row locks, and a unique index.
- Display dies when the internet drops. Add a backup connection or run a local server where connectivity is unreliable.
- No priority lane. Seniors, pregnant visitors, or booked appointments need their own service type, not manual queue-jumping.
- Agents forget to press "done", corrupting service-time data. Fix: "call next" automatically closes that counter's previous ticket.
Launch Checklist
- Concurrent ticket requests tested from several devices at once.
- The display is readable from the back row.
- Audio is clear and enabled in the browser.
- Staff are trained on call, recall, skip, and done.
- A paper fallback exists for power or network outages.
- Daily number reset runs automatically.
A queue system is often the first step toward wider digitization, such as customer records or point of sale. If you want a head start, the Laravel service apps in the GudangCode catalog are worth studying as a base.