Case studies
Automotive / live auctions · 2023

Live auction bidding without the timer drifting

Live auction bidding without the timer drifting

Client
Car Bidding (used-car auction platform)
Duration
24 weeks
Status
Shipped
Stack
React Native · React · FastAPI · FastAPI WebSocket / socket service

What we solved

A daily live auction for used cars dies the first time the countdown drifts. If the phone in your hand says 4 seconds and the phone next to you says 8, the dealer has a fight. If a bid placed at t=0.5s doesn’t reset the timer for everyone, the buyer who placed it watches their bid lose. Car Bidding needed a real-time bidding surface where the timer, the highest bid, and the car list were identical across iOS, Android, and the web - every frame.

The system at a glance

A React Native consumer app (iOS + Android) and a React admin web app, both talking to a FastAPI backend. FastAPI’s WebSocket support streams auction events: timer_update, new_bid, and car_rotate. Postgres holds vehicle metadata, users, and bid history. Every client reconciles state from the server, never from local math. Push notifications for auction-start route through OneSignal.

What the user experiences

  • Verified buyers log in and see the Available Now feed of cars scheduled for tonight’s event.
  • At event start, the Live Auction view opens. Each car is on the block for 30 seconds.
  • Every new bid resets the clock to 30.
  • Bid entry is one tap: minimum-bid suggestion, confirm, done. The current highest bid updates in real time.
  • When the timer expires, the list rotates to the next car automatically.
  • Won cars land in the Won list with pickup instructions.

How we built the pieces

The timer - server-authoritative, never client

The countdown is generated server-side and streamed over the WebSocket channel on FastAPI. Clients display what the server says. No clocks are computed locally because two phones in the same room drift apart within minutes. Bids go through REST; the server updates the timer and broadcasts to every connected client. Worst case lag is a network round-trip, not a device-specific bug.

The bid - atomic, with conflict handling

A bid includes the car ID, the user ID, and the client’s seen current-highest. The FastAPI endpoint checks the seen value against reality, rejects stale bids, and locks the Postgres row before writing. Two simultaneous bids resolve cleanly - one wins, one gets a retry hint.

React Native mobile, React web - shared patterns

Both surfaces share validation logic, API-client code, and the auction-view state machine. React Native for the buyer, React for the operator dashboard, one FastAPI backend. One team ships all three.

The admin - verify, onboard, schedule

The admin console (React web build) handles user verification before first bid, vendor and vehicle onboarding, auction scheduling, and sold/unsold tracking with re-list actions. An event can be assembled, scheduled, and live-monitored without engineering involvement.

Cross-device bids - one account, many screens

A buyer with the app on their phone and the web open on their laptop bids from either. The server deduplicates by user ID; both surfaces stay in sync on every bid, regardless of which surface placed it.

Push - OneSignal, not FCM directly

Auction-start pings go out through OneSignal. Same SDK handles iOS + Android + web, with cohort targeting so we only wake up buyers verified for a specific upcoming event.

Timing is the product, listings are decoration

Live auctions are a timing problem, not a listings problem. Most “auction app” MVPs die because they ship the catalogue and forget the timer. Car Bidding gets the timer, the bid-write path, and the cross-device consistency right. Everything else is decoration.

Results

  • Daily auction events running with 30-second per-car windows.
  • Bids propagate under one network round-trip to every connected device.
  • Admin can onboard a vehicle, schedule the auction, and close the event without deploying code.
  • Verified-user gate before first bid prevents drive-by disruption.
  • React Native iOS + Android consumer app; React web admin; FastAPI + WebSocket backend.

What an engineering team should take from this

If you are shipping anything with a live timer (auctions, voting, flash sales, live-event Q&A), three things:

  1. The timer is server-authoritative. Never trust clients to agree with each other.
  2. FastAPI’s WebSocket support + sticky sessions is enough at this scale - but put the sticky-session config in from day one, or reconnects will fragment state.
  3. Bid writes need seen-current-highest in the payload so late bids don’t silently overwrite.

Tech stack

  • Mobile: React Native (iOS + Android)
  • Web admin: React
  • Backend: FastAPI (REST + WebSocket)
  • Database: Postgres (users, cars, bids, auction schedules)
  • Real-time: FastAPI WebSocket with sticky sessions
  • Push: OneSignal for auction-start alerts
  • Media: AWS S3 for vehicle galleries

Screens

Buyer app screens - dashboard, live auction with 30s countdown, and won-bids list - with admin laptop views

Reference architecture

The stack, one-pass.

Named pieces, how they connect, and why each one earned its spot.

  • 01React Native

    iOS + Android consumer app from one codebase

  • 02React

    web admin + operator console

  • 03FastAPI

    typed Python REST API for users, vendors, cars, bids

  • 04FastAPI WebSocket / socket service

    bid broadcast + countdown reset across every connected device

  • 05Postgres

    users, cars, bids, auction schedules (relational + transactional)

  • 06OneSignal

    push notifications for auction-start alerts

Full stack

Every piece, named.

  • React Native
  • React
  • FastAPI
  • FastAPI WebSocket / socket service
  • Postgres
  • OneSignal
  • AWS S3
  • Sticky sessions
The team on the call

Named engineers, not a pool.

You speak to the person who’ll review the architecture. No account-manager layer. No offshore switcheroo.

Founder & Lead Engineer

Sameer Donga

Shipping Flutter, FastAPI, and AI systems since 2019. Reviews the architecture on every engagement.

Start a similar build

You have the reference. Now the project.

Tell us the shape of your version. We come back with a written architecture and a fixed quote.