Transport & Logistics

How to Build a Rideshare Dispatch System with Google Maps Geofencing

0 MIN READ • Markus Kohler on Oct 1, 2025
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

  1. Feature 1 — Geofenced Eligibility (H3 + PubNub Presence/State)
    Devices convert GPS location data/device location to H3 hex cells and flip a lightweight inZone flag. Eligibility becomes a constant-time lookup: currentCell ∈ allowedCells. These virtual boundaries (aka geofencing) are fast and reliable for location tracking.

  2. Feature 2 — Fair FIFO Dispatch Queue
    When inZone becomes true, a driver joins a queue with a joinTs. 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

  1. Go to admin.pubnub.com/signup and create a free account.

  2. If you already have one, sign in to your PubNub Dashboard.

  3. Click Apps in the left-hand sidebar → Create New App → name it (e.g., “Rideshare Dispatch”).

  4. Create a Keyset. Create a PubNub application

Enable PubNub Features

To ensure your keyset is configured correctly: Enable:

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. Configure PubNub Keyset

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

  1. Create a project in Google Cloud Console

  2. Enable Maps JavaScript API

  3. Enable Places API and Geocoding API
    Configure Google Maps JavaScriptSDK

  4. Create an API key with HTTP referrer restrictions

  5. Go to “Keys & Credentials” from the sidebar to view your key Grab API key from Google Credentials

  6. Store your key:

Other map options (optional):

  • Mapbox: highly customizable styling (great for branding)

  • HERE: strong routing/logistics in EU/Asia

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 for inZone 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.” Loading Google Maps

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. Hexigonal map layout

What we’ll use (and why)

  • H3 (hex grid)h3-js

    • polygonToCells (offline) to convert venue polygon → allowed hex cells

    • latLngToCell (device) to convert GPS → current cell ID

    • gridDisk (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 } to zone/<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:

  1. Open Overpass Turbo and zoom to the venue.

  2. Use the Wizard to search by tags (e.g., amenity=parking) or a named area.

  3. 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). Overpass Turbo Query

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, then v2.json as lots change). Your app can hot-swap without redeployments. Google Maps Zoning

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 & Guardrails

  • GPS 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), publish assign, enforce a grace timer, and prevent clients from spoofing joinTs.

  • 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