How to Build a Rideshare Dispatch System with Google Maps Geofencing
Do you want to build a real rideshare dispatch system for an on-demand ride-hailing / ride-sharing mobile app? If so, you’re in the right place. This tutorial will walk you through setting up a deployable dispatch foundation in about a week. No, this won’t be your average application showing you a map on a screen. We’ll focus on two small but high-impact/advanced features that real taxi apps and ride-hailing apps rely on:
Geo-fenced Driver Eligibility — only drivers physically inside the pickup zone are eligible for trips.
Fair FIFO Dispatch Queue — once eligible, drivers are assigned in first-in/first-out order for predictable, dispute-free hand-offs.
We’ll utilize the Google Maps API (a location-based services API used for routing, route optimization, traffic data, points of interest, and map tiles) alongside PubNub to implement real-time App-Store-grade behavior you see on iOS/Android production apps step-by-step. At the bottom, you’ll find the resources I referenced while building this. Lastly, everything used here has a free tier — you can build this for free.
Who is this for? A startup or development company building an MVP for Uber/Lyft-style taxi booking in urban areas, taxi service providers and taxi companies modernizing their backend, or teams aiming to streamline app development and optimize user experience, customer satisfaction, and rider/driver retention.
What You’ll Build
Feature 1 — Geofenced Eligibility (H3 + PubNub Presence/State)
Devices convert GPS location data/device location to H3 hex cells and flip a lightweightinZone
flag. Eligibility becomes a constant-time lookup:currentCell ∈ allowedCells
. These virtual boundaries (aka geofencing) are fast and reliable for location tracking.Feature 2 — Fair FIFO Dispatch Queue
WheninZone
becomestrue
, a driver joins a queue with ajoinTs
. New rider requests go to the head of the line; timeouts bump the driver and continue. This reduces wait times and driver travel time while keeping assignment algorithms simple and auditable.
We’ll ship one tiny, user-friendly interactive component: a Queue Visualizer you can drop into a Next.js page to simulate join/leave/assign behavior.
These two features are the core of geofencing technology, and we can utilize PubNub to make it easier to create a scalable production-grade taxi booking application—whether it is Lyft, Uber, DoorDash, a mobile app or a web app. They all use this functionality at their core for real-time tracking, notifications (for in-app driver pings), and fair dispatch.
Prerequisites
Basic React/Next.js (frameworks & project dependencies)
Node.js 18+
A free PubNub account (for real-time messaging)
(Optional) Google Cloud project if you want to draw maps (the eligibility logic doesn’t require Maps).
(Optional) A test device on Android (uses Google Play services / play services) or iOS for geolocation/current location field testing.
MVP tip: You can launch a minimal, automate-friendly queue + eligibility MVP first, then layer advanced features like driver in-app notifications, surge pricing, and fleet management dashboards.
Set up your PubNub Account
Go to admin.pubnub.com/signup and create a free account.
If you already have one, sign in to your PubNub Dashboard.
Click Apps in the left-hand sidebar → Create New App → name it (e.g., “Rideshare Dispatch”).
Create a Keyset.
Enable PubNub Features
To ensure your keyset is configured correctly: Enable:
Presence (Select “All channels”)
Message Persistence (1 day)
Stream Controller (For subscribing to channels)
Leave disabled for now:
Important: Don’t deploy to production without Access Manager enabled to protect user data and restrict who can publish/subscribe.
Click Save on all changes.
Google Maps API (Optional — visualization only)
Google Maps provides interactive maps, geocoding, routes, and places (points of interest). You do not need Maps to compute eligibility. H3 + PubNub handles all the logic; Maps are for debugging, demos, and operator views.
Typical Google Maps API use case here: visualize fences, inspect traffic data, and preview route optimization impacts on driver travel time.
Keep an eye on pricing if you exceed free tier usage; you’ll authenticate with an API key.
Setup steps
Create a project in Google Cloud Console
Enable Maps JavaScript API
Enable Places API and Geocoding API
Create an API key with HTTP referrer restrictions
Go to “Keys & Credentials” from the sidebar to view your key
Store your key:
Other map options (optional):
Create the Project
Install Dependencies
We’ll focus on H3 for geofencing and PubNub Presence/State for the inZone
flip.
Why these:
pubnub
— real-time Presence/State forinZone
flips and lightweight events.h3-js
— converts GPS positions to hex cell IDs and polyfills polygons to cell sets; constant-time eligibility checks.@turf/turf
— union/simplify/buffer messy real-world polygons before hex-filling.@googlemaps/js-api-loader
(optional) — loads the Maps JS API (display/debug only).
Accuracy note: device geolocation blends GPS/Cell/Wi-Fi signals; on mobile devices, Google Play services (Android) and Apple Core Location (iOS) manage sensor fusion.
Environment Variables
Use public envs for browser code. In Next.js, public keys must start with NEXT_PUBLIC_
.
Optional: Visualizing Your H3 Fence on a Map
Heads-up (example-only): The map code below is just to visualize your hex fence. It’s okay if it doesn’t fully click yet — we’ll revisit and it explain what is going on later in the tutorial.
lib/renderH3.ts
If the code is running properly, you should see a map zoomed in on the Toronto International Airport.
I was able to send in a prompt into Cursor using the “auto” model feature, as well as copying the .env that was defined above with the appropriate keys.
“I saw this code in a blog post. I need it to run in a React or Next.js project. Start the project by using terminal commands and using the code defined above. Also, use the following .env file for any key needed.”
Feature 1 — Geo-fenced Driver Eligibility
Problem: Riders expect fast, fair pickups. That starts with considering only drivers inside the pickup zone (airport lot, stadium curb, venue circle). Letting outside drivers jump the line creates disputes.
Solution: Use a discrete global grid (H3). Eligibility becomes: “Is the current location currently inside one of our allowed hex cells?” This is fast, stable, and scales naturally.
What we’ll use (and why)
H3 (hex grid) —
h3-js
polygonToCells
(offline) to convert venue polygon → allowed hex cellslatLngToCell
(device) to convert GPS → current cell IDgridDisk
(device/server) to add a small neighbor buffer (reduces edge jitter)Start with res 9–10 (~174m / ~66m edge). Tune after field tests.
Geo preprocessing —
@turf/turf
Clean real-world shapes (union/simplify/buffer) before hex-filling.Zone geometry (data) — OpenStreetMap via Overpass Turbo
Export venue polygons as GeoJSON (free & fast). Follow ODbL attribution.(Optional) Map display — Google Maps
Use Maps for visualization only. Keep H3 as the source of truth.Presence/State — PubNub Presence
Publish a tiny state{ inZone, h3, lastSeen, zoneVersion }
tozone/<ID>
only when the flag flips (saves battery; easy to scale) and trigger driver notifications for in-app UI updates.
Why hex cells over polygons?
Speed: point-in-cell is a hash lookup (no heavy point-in-polygon math).
Smooth edges: add a neighbor buffer (
gridDisk(k=1)
) to tolerate GPS jitter.Sharding: cells are natural routing keys for channels, storage, dashboards, and backend rate-limits.
Where the zone polygon comes from (repeatable workflow)
You need a GeoJSON polygon for your pickup zone (airport staging lot, stadium curb, etc.). A simple, field-tested flow:
Open Overpass Turbo and zoom to the venue.
Use the Wizard to search by tags (e.g.,
amenity=parking
) or a named area.Run a query and Export → GeoJSON.
Example — parking inside an airport area (Overpass QL):
If you have multiple shapes, union them. If they’re very detailed, simplify a bit to avoid an enormous cell set (Turf helps).
Build once (offline): polygon → hex cells
We do this offline, so the app just downloads a versioned JSON of allowed cells at startup.
tools/build-zone.ts
File layout
Keep fences versioned (
zones/<ZONE>/v1.json
, thenv2.json
as lots change). Your app can hot-swap without redeployments.
Client: compute current cell → set ‘inZone’ via PubNub
Load the zone JSON, compute the device’s current H3 cell from lat/lng, add a small hysteresis buffer (neighbors), and set driver Presence state on a single zone channel. Publish only when inZone
changes. lib/geoEligibility.ts
Server guard: make the server the source of truth
For the tutorial, you can use client-side setState
, but for production, verify eligibility server-side (so clients can’t spoof inZone
). A tiny Node microservice works well.
server/eligibility.ts
server/zones-cache.ts
Why bother with a server?
Prevents tampering with
inZone
/h3
.Lets you roll out new fence versions centrally.
Keeps your secret key safely on the server (never ship it to clients).
Works great with Access Manager (restrict who can set state on
zone/*
).Leaves room to add driver notifications, surge pricing, and automate fleet management rules later. Picking a resolution (quick guide):
Res 9 (~174 m edge): airport lots, big venues
Res 10 (~66 m edge): curbs, parking rows, stadium gates Choose the coarsest res that still feels fair at the curb — fewer cells → fewer updates and simpler ops. If you see “flapping” at edges, use the neighbor buffer (
k=1
) before jumping to a finer resolution. Gotchas & GuardrailsGPS drift near edges: add the neighbor buffer and flip
inZone
only after two consecutive confirmations.Bad actors: lock
setState
behind Access Manager roles; prefer server-side updates.Version drift: include
zoneVersion
in state; if the client lags behind the server, the server wins.Multi-venue cities: keep one channel per zone (
zone/SFO
,zone/YYZ
), not per city; shard further by cell only if you need hyper-local fan-out.Testing: try both outdoor GPS and Wi-Fi-heavy urban areas to validate behavior.
Feature 2 — Fair FIFO Dispatch Queue
Problem: Even with a geofence, “who gets the next trip?” can devolve into chaos. Drivers need a predictable first-in/first-out queue to trust the system.
What we’ll build: When a driver becomes eligible (inZone: true
), they join the queue with a joinTs
. When a rider request arrives, the next driver is assigned and removed from the head of the line. If they don’t accept within a grace period, they’re bumped, and the next driver is notified. This helps optimize rider wait times and travel time while enabling clear in-app experiences.
We’ll wire a tiny Queue Visualizer into a Next.js page. It’s client-side here; in production, make a PubNub Function your queue authority.
lib/pubnub.ts
— a safe, client-only singleton
lib/queue.ts
— minimal client-side authority (demo only)
components/QueueVisualizer.tsx
— the interactive UI
app/queue/page.tsx
— Next.js page (App Router)
If you’re using the Pages Router, create
pages/queue-visualizer.tsx
with the same component and export a default page instead.
Production Notes
Make a PubNub Function the queue authority: on join/leave/request, update a stored list (sorted by
joinTs
), publishassign
, enforce a grace timer, and prevent clients from spoofingjoinTs
.Guard channels with Access Manager (drivers vs. riders).
If a metro is busy, shard queues by geocode/geohash prefix (e.g.,
queue/SF/9q8
).Persist queue state (Message Persistence or a KV in your Function) for resilience.
Add in-app notifications for assignment pings to elevate user experience.
(Optional) Showing Nearby Eligible Drivers on the Map
Once Feature 1 is live, you can show only eligible drivers on the rider map:
Consider filtering by current location proximity, traffic data, and routing ETA for better route optimization and real-time tracking.
Wrap-Up and Next Steps
You now have the core building blocks of a rideshare dispatch system:
Geo-fenced eligibility with H3 + PubNub Presence/State
A fair FIFO queue with a tiny interactive visualizer (move logic to PubNub Functions for production)
Where to go from here
Add a grace window (e.g., 30s) before bumping an assigned driver
Integrate a nearest-driver prefilter (distance threshold) before FIFO to reduce travel time
Build a lightweight operator dashboard that watches queue length and rider wait times or utilize PubNub Illuminate
Add fleet management & analytics, surge pricing, and automate safety checks
Expand to iOS/Android mobile devices with in-app UX polish and push notifications
FAQs
Q: Does this require Google Maps to work?
A: No. Maps are optional for visualization only. The geofencing eligibility works with H3 + PubNub using raw location data from the device (geolocation) whether on iOS or Android (Google Play services / play services).
Q: Will Wi-Fi affect accuracy?
A: Yes. In dense urban areas, Wi-Fi improves indoor fixes. Validate fences outdoors and indoors for the best user experience.
Q: How do I control costs/pricing for Google Maps?
A: Use an API key with referrer restrictions and monitor pricing in Google Cloud. For this tutorial, Maps are optional.
Q: Can I extend this to driver ETA and smarter assignment algorithms?
A: Definitely—feed routing, route optimization, and traffic data into your assignment algorithms to improve fairness and customer satisfaction.
Q: What about backend frameworks and dependencies?
A: Any Node/Express stack works. Keep your backend minimal, restrict secrets to the server, and version your fences. Add only the dependencies you need.
Q: Does this approach fit taxi companies and service providers?
A: Yes. It’s suitable for taxi companies, aggregators, and service providers modernizing legacy dispatch, and for startups shipping an MVP.
Resources
PubNub Docs: Core SDK, Presence, State, Objects (App Context), Access Manager
Google Maps Docs: Maps JavaScript, Geometry Library, Places (Google Maps API)
OpenStreetMap & Overpass: https://overpass-turbo.eu/