Most of the time when people ask how our event headshot booths work, they want a product tour. What I usually end up talking about instead is convention-hall wifi. We have run these booths in rooms that were never designed for cloud AI: shared networks, a few hundred people hitting the system at once when a session breaks, and a line of attendees watching every spinner like it owes them money. This is a writeup of how we built for that world.
The constraint set nobody designs for
Consumer photo apps get to assume home broadband and a patient person sitting on a couch. Conference booths get neither. The network is often one vendor SSID shared with badge scanners, sponsor lead-capture tablets, and whoever in the keynote hall decided to livestream. Traffic is not smooth. It comes in waves when sessions let out, and we regularly see a few hundred concurrent users when a hallway suddenly empties into the booth.
Patience is just as constrained as bandwidth. From watching people in line, attendees will hang with a progress state for about thirty seconds. Stretch that toward ninety and the mood changes. People check their phones, start explaining the delay to whoever is behind them, or leave. Unlike a failed upload in a private settings screen, every error state here is public. The queue is the audience. That sounds dramatic until you have stood next to it.
Those two pressures, bad wifi and a public wait, pushed us toward three non-negotiables pretty early. The booth had to run in a browser. Generation had to keep going even if the client dropped. And email had to be the source of truth for delivery, not the on-screen gallery that only works while the connection holds.
Why “runs in the browser” is a hard requirement
“No app required” can sound like a soft convenience feature. At events it is load-bearing. Asking someone to install from an app store in a crowded hallway is a non-starter, corporate iPads are often locked down, and guest phones are a messy mix of OS versions and battery-saver modes that throttle anything ambitious in the background. The only deployment unit we trust on the floor is a URL.
So the booth is a microsite. An iPad station opens it in Safari. A QR code on a nearby monitor opens the same site on an attendee's phone when the kiosk line gets too long. There is no Dreamwave binary to push overnight, and we do not need to staff every tablet. Organizers bring their own devices. We bring a custom event link and the cloud pipeline behind it.
Keeping everything in the browser also forces a cleaner split of responsibility. We ask for a few selfies, compress them on-device before they cross the bad wifi, and then move the heavy work to the server. The client is supposed to stay thin: capture, compress, show progress, and recover if the tab dies. That split is what makes QR overflow practical. A phone that just joined the conference network should never be asked to run the model.
The compute trade-off: likeness lives in the details
The product promise is studio-grade likeness in a short wait, and the uncomfortable part of that promise is where likeness actually lives. It is not in the blurry global shape of a face. It is in pores, glasses frames, hair edges, and the exact way light hits someone's cheek. A lot of cheaper pipelines save money by under-computing those details. You feel the shortcut immediately in a booth, because the person standing there will look at the screen and say, without much diplomacy, that it is not them.
We spend the other way. Generation runs server-side on high-compute image models rather than on the attendee device. A typical booth session plans on the order of fifteen finished portraits across styles and variants. Inside a job we fan out a small parallel pool of model calls and retry the transient failures that show up under load.
The trade-off is straightforward once you accept the environment. We spend more compute per photoshoot than a consumer app usually wants to, and we pay for that by keeping the attendee's phone out of the critical path. Fast delivery at event scale only works if the browser is basically a remote control, while the durable work happens in a long-running server job that keeps writing progress heartbeats the client can poll.
That progress plane matters more than it sounds. The server records heartbeats while photos land in object storage. The browser checks in every second or two. Signed URLs hand each finished frame into the gallery as it becomes available. If the wifi blips, the job can keep going anyway. This feels obvious in a design doc and much less obvious when you have watched a spinner die in the middle of a hallway and take five people out of line with it.
Queue math at 10,000 attendees
When we say a booth can support an event with 10,000 attendees, we do not mean one giant simultaneous rush. We mean a three-day shape. Ten thousand badges across three exhibit days is roughly three thousand people a day if attendance were perfectly even, which it never is. Lunch breaks and session flushes create peaks, and a busy booth can see a few hundred concurrent users when a hallway empties all at once.
We do not try to win those peaks by making a single iPad magically faster. We try to make the system easy to scale out. Every device is just another browser hitting the same microsite. Organizers can add iPads when the line gets theatrical. QR codes absorb overflow onto phones when the line gets operationally painful. The cloud pipeline scales with jobs, not with how many stands someone rented from the AV vendor.
Even then, capacity needs a product brake. Every event gets a redemption cap in our config, and once that many external guests have completed a shoot, the booth stops taking new ones. We also gate once per email for a delivered job so the same person cannot burn through the allotment by looping the QR code for fun.
For a large conference, the setup that usually works is both at once: a visible kiosk that creates the line and makes the activation feel real, plus phone overflow so the line itself does not become the entire experience.
More details about our architecture
A few details matter a lot once the booth is live and the wifi is not.
Email is the durable handoff. The on-screen gallery is a nice convenience for people who stay on good wifi long enough to browse. The confirmation email is how you still get your photos if the hallway eats your connection halfway through.
The browser also has to be able to reattach. We store a short-lived session pointer in local storage, keyed to the event, so refreshing the page within that window lets the booth pick the job back up, resume polling, and restore the gallery if photos are already ready. Private mode and blocked storage still happen, and those guests fall back to email. That is fine. The point is not that local storage is perfect. The point is that a refresh should not equal starting from zero.
Unfinished work also needs an operator that is not the person standing in line. We run a recovery job on a fixed interval that looks for unfinalized booth shoots, refires missing slots in an idempotent way, and stops retrying a poisoned job after a hard cap so we do not burn spend forever. If generated files are already in storage, we skip those slots instead of regenerating them. The floor should never depend on one fragile client connection staying alive for the entire shoot.
We are also careful about what “waiting” means in the UI. If heartbeats go silent for several minutes, we stop pretending the spinner knows the future and tell the guest we will email them. Canceling the server job in that moment would be the wrong instinct. The work may still finish. What the attendee needs is a clear next step, not a confident lie dressed up as a loading bar.
The privacy architecture, because hospitals asked
A lot of consumer apps can get away with waving at privacy. Hospital systems, government events, and other regulated buyers ask for a packet. They want to know where faces live, who can access them, whether any model will train on them later, and what deletion actually means.
In practice, that means customer data stays in US-resident infrastructure, photos move over TLS, and access to a booth job is scoped to that event and that job rather than dumped into a public album. The on-screen gallery uses short-lived signed URLs. We do not train our models on customer photos. Guests can delete their data at any time. The longer version of the policy, including retention and subprocessors, lives on our Trust Center.
The only data we ask for is the photos required to generate the headshot, and enough contact detail to deliver results. We do not collect ethnicity, age brackets, or a permanent face database. Some consumer apps collect demographic labels, such as ethnicity, age, and whether you wear glasses (indicating a health condition) because they are building training datasets. That is a different business.
Unlike other AI photobooth solutions, we are not in the business of building a shadow face database. If a hospital would not put their clinicians through the flow, we should not be comfortable shipping that flow to a tech conference either.
Convention-hall wifi is probably not getting better any time soon, and people in line will keep being honest about how long they are willing to wait. Our job is to build for that reality: spend compute where likeness actually lives, keep the client thin enough to survive a bad network, and treat a dropped connection as a delivery problem to solve in the background, not a dead end for the guest.
Running a conference or expo? See event headshots.