Mobile App Development

Building QR-code table payments for a restaurant client

APP

A restaurant group asked us for a way for diners to pay their bill without waiting for a server to bring a card machine over. We built a mobile-web flow rather than a native app, since asking diners to install something just to pay dinner would have killed adoption before it ever had a chance — nobody wants to download an app for a single meal at a restaurant they may never return to.

Why mobile web instead of a native app

This decision shaped almost everything that followed. A native app would have given us more control over the payment experience and a persistent presence on a diner's phone, but the adoption math simply does not work for a single-visit use case: even a well-designed app install flow loses the overwhelming majority of people at the "install this app" step, and a restaurant group whose whole pitch is convenience cannot afford that kind of friction. A QR code that opens directly in the phone's existing browser has zero install step, which was the entire point.

How the flow works

Each table gets a printed QR code linking to a unique, short-lived URL tied to that table's current open order in the point-of-sale system. Scanning it opens a mobile-optimized page showing the current bill, a tip selector, and a card payment form backed by Stripe. Once payment clears, the POS system marks the table closed and prints a receipt automatically, with no server needing to manually reconcile anything on their end.

Keeping the bill in sync with the kitchen

The trickiest part was keeping the bill in sync if the kitchen adds an item after the diner has already opened the payment page — we solved it with a short polling interval on the total rather than a full websocket connection, which was simpler to build and reliable enough for how quickly a payment actually happens in practice. A diner typically opens the page, reviews the bill, and pays within a couple of minutes, which is a short enough window that a few seconds of polling latency on a late-added item almost never causes real confusion. We did add a visible "bill updated" banner that appears if the total changes while the payment page is open, specifically so a diner never pays a stale amount without at least seeing that something changed.

Security needed real attention

Security needed real attention given that this handles live payments: each table's URL token is single-use and expires the moment payment clears or after a short window of inactivity, preventing a diner from reusing a link after leaving or a stale QR code print from a previous seating being scanned by the next table's guests. We also rate-limited how many times a given token could be used to attempt payment, since a payment page reachable by anyone with a phone camera is a more exposed surface than a login-gated checkout, and it is worth treating it with a correspondingly higher level of caution.

Handling split bills and partial payments

  • A table with multiple diners can split the bill evenly across a chosen number of people, or by item, with each split portion getting its own single-use payment link
  • A partial payment updates the remaining balance for the table in real time, so a second diner scanning the same code sees an accurate remaining amount rather than the original full total
  • Once the full bill is paid across however many separate payments it took, the table closes automatically, the same as a single-payer table

Printing and physical logistics

A detail that seems trivial but genuinely was not: printed QR codes at a restaurant table get spilled on, torn, and occasionally taken as souvenirs, so we built a simple admin page letting restaurant staff regenerate and reprint a table's code in under a minute without involving us, rather than every damaged code becoming a support ticket. We also learned the hard way on our first location that laminating the printed codes matters more than it sounds like it should — an un-laminated code left near a plate of pasta sauce does not scan reliably, and a diner who cannot get a QR code to scan on the first or second try tends to just flag down a server anyway, quietly defeating the whole point of the feature.

Results

The restaurant group has since rolled it out to four more locations, and staff have reported that tables using the QR payment flow turn over noticeably faster during busy periods, since diners are not waiting on a server's availability to close out and leave. Tip amounts through the flow have also tracked slightly higher on average than cash tips at the same locations, which the restaurant group attributes to the tip selector defaulting to a percentage of the bill rather than diners doing mental math with cash on hand — a side effect we did not specifically design for, but one the client has been happy to see.

Diners without a smartphone, or without one handy

Not every diner wants to or can use a QR code to pay, and we made sure the flow never became the only option — a server can still bring a card machine to any table on request, and the QR flow is presented as a convenience rather than a requirement. Staff are trained to offer it rather than assume it, since a table of diners unfamiliar with QR codes or simply not in the mood to fumble with a phone at the end of a meal should never feel pressured into using it.

Rollout process across locations

The first location was deliberately treated as a pilot with close monitoring for a full month before we considered rolling it out further. That caution paid off: our first version showed the tip selector's default option a little too prominently, based on the highest suggested percentage, which a few diners flagged as feeling pushy compared to how a server would typically present the same choice verbally. We adjusted the default to a more neutral middle option and made all percentage choices visually equal weight, and diner feedback on that specific point disappeared entirely after the change. Each new location since then gets a shorter, two-week monitoring window rather than the original month, since the flow itself is now proven and most per-location issues turn out to be printing and physical setup rather than anything in the software.

Analytics we added after launch

  • Time from QR scan to completed payment, which the restaurant group uses as a rough proxy for table turnover speed during busy periods
  • Split-payment usage rate, which turned out to be higher than we expected on larger tables and directly informed a UI simplification for that specific flow
  • Tip percentage distribution, shared with the restaurant group but not with individual servers, specifically to avoid the flow being used as a performance-management tool for staff, which was a boundary the client was thoughtful enough to set clearly from the start

Handling connectivity inside the restaurant itself

A detail specific to physical restaurant spaces that we had not fully anticipated: several locations have genuinely poor cellular reception in the areas where tables are seated, particularly in below-street-level dining rooms. We added the restaurant's guest wifi network information directly on the printed table card next to the QR code, since a diner whose phone cannot get a reliable signal will otherwise simply give up on the flow entirely and flag down a server anyway, which defeats the purpose without the diner ever realizing the payment page itself was not actually broken.

What we would tell another restaurant considering this

Restaurants evaluating a similar system tend to ask us the same handful of questions up front: will it slow down table turnover if diners linger over the payment page (it does not, in our experience, since most diners pay faster than waiting for a server would have taken), will it reduce tips (it has not, and if anything average tips have trended slightly higher), and will it require staff retraining (minimal — the main training need is simply remembering to offer it rather than assuming every diner already knows it exists). We also learned to keep the printed card copy short and reassuring rather than technical, since the goal is a diner feeling confident enough to try it without a server prompting them, and copy that reads like a support document undermines that confidence more than a missing feature ever would.

← Back to the journal

Have a project in mind?
Let’s talk.

Tell us where you are and where you want to go. We'll map the fastest route between the two.

Currently accepting new clients