Skip to content
Rapcsány Krisztián
hu
← All projects iOS and Android app

Event check-in mobile app

The mobile check-in app that staff use at the door to validate tickets. QR scanning, entry, exit, on-site ticket sales and live statistics, on iOS and Android.

React Native Expo TypeScript REST API Biometric authentication OTA updates
The challenge
My role

I designed and built it, from the first version to 2.0.

At the entrance every second counts. If the queue is slow, guests get impatient, and the organiser watches revenue slip away. The door staff need fast, clear feedback: green or red, done.

Before this there was a browser-based scanner. I replaced it with an app that is faster, and where everyone only sees what their job needs.

The solution
01

Camera ticket validation

It reads the QR code with the phone camera and shows the result in colour: the ticket is valid, already used, expired or unknown. VIP guests get a separate mark.

02

Fast check-in

An automatic mode you can switch on: if the ticket is valid, the scan admits the guest straight away, with no extra tap.

03

Check-out

There is a separate exit flow too, so you always see how many people are inside.

04

On-site ticket sales

With a cart and payment, so tickets can also be bought at the door.

05

Live statistics

Arrival chart in 10-minute buckets, the number of sold, checked-in and no-show tickets by ticket type, and a chronological list.

06

Roles and users

There are five roles: admin, validator, exit staff, gatehouse and viewer. Everyone sees only the screens their job needs, and users are managed from within the app.

Screenshots
Sign in

Staff sign in with their own account, and the sign-in persists.

Choosing the event

Only valid events are listed, so door staff cannot start on the wrong one.

Check-in

The camera waits for a QR code. The event name is shown at the top and can be switched with one tap.

On-site ticket sales

Ticket types at door and member price, with a quantity picker and a running total.

Issuing tickets

A QR code or email for every ticket, with payment and check-in in a single step.

With brand and customer names and personal data removed (except the app store screenshots).

What makes it special

One scan, done

There is a fast mode: for a valid ticket the scan itself admits the guest, with no extra tap.

Five roles

Admin, validator, exit staff, gatehouse and viewer. The gatehouse role, for example, only sees live statistics, and exit staff only see the exit screen.

It measures itself

For every guest it times the scan to the result and to the check-in. It summarises the last fifty on the phone and sends the rest to the server in batches. From those I can see how fast it is.

Challenges I ran into
01

Weak signal, and nobody gets in twice

On a network error I retry the call once, but only if repeating it cannot do harm. Anything that only reads, or is idempotent on the server, may be retried. Anything that is not, I do not call a second time.

02

The first guest is the slowest

On the first scan, setting up the connection eats the time (name lookup, encryption). So the app warms up the connection in the background before the first guest arrives, at most once a minute.

03

The selected event got stuck

In version 1.1.1 I fixed a bug where the selected event stayed in place even when it was no longer selectable. Now the app checks at launch and every time it comes to the foreground, and if the event is no longer valid it sends you back to the event picker.

Under the hood

Tuned for speed

The connection is already set up before the first guest gets there. I measure the time from scan to result for every guest, so a slowdown shows up quickly.

Works on weak networks

On a network error, repeatable calls retry by themselves. Non-repeatable ones never do, so nobody can be admitted twice.

Security

The login sits in encrypted storage, and longer sessions are protected by biometric authentication. The app keeps checking that the selected event is still valid.

Operability

Automatic error reporting, fixes without waiting for a store update, and role-based access on the server too.

Live code

A retry that does no harm

On a weak signal the call is repeated once, but only when that is safe. Non-repeatable write calls deliberately have no automatic retry, so nobody can be admitted twice.

network-retry.ts
/** No response at all = network failure (offline, timeout). A 4xx/5xx reply is not. */
function isNetworkError(error: unknown): boolean {
  return axios.isAxiosError(error) && !error.response;
}

/**
 * Retries a call once on a network failure. ONLY use it for calls that are
 * safe to repeat: reads, or writes that are idempotent on the server.
 */
async function withNetworkRetry<T>(call: () => Promise<T>, retries = 1): Promise<T> {
  try {
    return await call();
  } catch (error) {
    if (retries > 0 && isNetworkError(error)) {
      await new Promise((resolve) => setTimeout(resolve, 700));
      return withNetworkRetry(call, retries - 1);
    }
    throw error;
  }
}
Result

The app is a released, production-grade version (2.0) on both iOS and Android. Admission is down to a single scan, and organisers see arrivals in real time.

Do you need a mobile app or an entry-check solution?

I build mobile apps for iOS and Android, together with their backend.

More projects

Write to me →