Case study
Wayvero: route-overlap matching and a real trust model
A consumer carpool app is a hard startup, not a freelance job. The narrow versions are real, funded work: a corporate campus carpool, a university transport portal, a travel operator’s shared cabs. Wayvero is built to be white-labelled into exactly those.
- Stack
- Next.js 15, TypeScript, no database
- Demo data
- 4 corridors, 41 pickup landmarks, 108 generated rides
- Engine
- Route segments in a 0.1° grid index, 3 km snap radius
01 The narrow version
Not a BlaBlaCar clone. The pitch is the narrow version done right: overlap matching and a real trust model, white-labelable for a campus, a company or a travel operator.
| Product | Strength | Gap Wayvero highlights |
|---|---|---|
| BlaBlaCar | Intercity trust and a large review base; India is among its biggest markets by users. | Matching is mostly city to city, landmark pickups are weak, and there is no corporate layer. |
| Quick Ride | Commute and cab in NCR and Bengaluru, with auto-match, recurring rides, number masking and SOS. | Consumer-first, dense UI; corporate reporting is opaque. |
| sRide | Corporate carpool with workplace verification, fuel split and route matching. | Closed and enterprise-only: there is nothing to see before a sales call. |
| Toogo, Zify, WhatsApp groups | Zero friction and community trust. | No verification, no cost split, no safety tooling. |
Where the incumbents are strong, and the gap this demo is built to show.
BlaBlaCar
- Strength
- Intercity trust and a large review base; India is among its biggest markets by users.
- Gap Wayvero highlights
- Matching is mostly city to city, landmark pickups are weak, and there is no corporate layer.
Quick Ride
- Strength
- Commute and cab in NCR and Bengaluru, with auto-match, recurring rides, number masking and SOS.
- Gap Wayvero highlights
- Consumer-first, dense UI; corporate reporting is opaque.
sRide
- Strength
- Corporate carpool with workplace verification, fuel split and route matching.
- Gap Wayvero highlights
- Closed and enterprise-only: there is nothing to see before a sales call.
Toogo, Zify, WhatsApp groups
- Strength
- Zero friction and community trust.
- Gap Wayvero highlights
- No verification, no cost split, no safety tooling.
The demo visibly matches the table stakes — OTP-verified profiles, two-way ratings, number masking, women-only rides, recurring commutes, trip sharing and SOS — and shows off what the incumbents don’t: the overlap drawn on the map, a “why this matched” explanation, pro-rata fares for partial trips and a company CO₂ dashboard.
02 Matching on partial route overlap
Matching only on origin and destination misses most viable rides. Someone driving New Delhi → Jaipur should show up for a Gurugram → Behror search.
- 1Index the routesEach ride’s route is split into segments. A segment goes into every 0.1° grid cell its bounding box touches, padded by the snap radius, so a lookup reads a single cell.
- 2Snap drop, then pickupFind segments within 3 km of the drop point first: most rides fail there, so the pickup lookup only runs when something passes the drop.
- 3Check direction and overlapThe pickup must come before the drop along the route, and the shared distance must be 0.7–1.6× the straight-line trip, which rejects routes that only brush both points.
- 4Price the stretchCheap filters (day, seats, women-only, visibility) run before any timezone maths. The fare is pro rata to the shared kilometres, rounded to ₹10 with a ₹50 floor.
const nearDrop = nearSegments(ctx, q.to, stats)
if (nearDrop.size === 0) return noMatches // most rides fail here, cheaply
const nearPickup = nearSegments(ctx, q.from, stats)
for (const [rideId, pickupSnap] of nearPickup) {
const dropSnap = nearDrop.get(rideId)
if (!dropSnap) continue
if (pickupSnap.km >= dropSnap.km) continue // wrong direction
const matchedKm = dropSnap.km - pickupSnap.km
const ratio = matchedKm / tripKm
if (ratio < MIN_OVERLAP_RATIO || ratio > MAX_OVERLAP_RATIO) continue
// Cheap filters first; date maths only for rides that survive them.
if (dayOffset !== null && ride.dayOffset !== dayOffset) continue
if (ride.seatsTotal - ride.seatsBooked < q.seats) continue
if (q.women && !ride.womenOnly) continue
if (!canSee(ride, ctx.viewer, ctx.policy)) continue
// …departure time at the pickup, fare, score
}lib/matching/match.ts.Is the grid worth it?
- 12.1×faster lookup at p50
- 4.9×faster lookup at p95
- 3.8×faster end to end at p95
| Strategy | Lookup p50 | Lookup p95 | End to end p50 | End to end p95 | Segments checked |
|---|---|---|---|---|---|
| Naive scan | 6.60 ms | 7.20 ms | 7.04 ms | 7.82 ms | 70,659 |
| Grid index (0.1° cells) | 0.55 ms | 1.45 ms | 0.92 ms | 2.06 ms | 5,068 |
1,000 dated searches over 5,000 synthetic rides (36,460 route segments). Both strategies return identical results.
Naive scan
- Lookup p50
- 6.60 ms
- Lookup p95
- 7.20 ms
- End to end p50
- 7.04 ms
- End to end p95
- 7.82 ms
- Segments checked
- 70,659
Grid index (0.1° cells)
- Lookup p50
- 0.55 ms
- Lookup p95
- 1.45 ms
- End to end p50
- 0.92 ms
- End to end p95
- 2.06 ms
- Segments checked
- 5,068
Honest reading: the typical search is about 12× faster, but the slow tail only gains about 5×. That tail is Delhi-NCR, where the Jaipur, Chandigarh and commute corridors overlap and a query still checks thousands of segments — the case a finer grid or a real R-tree is for. In production the segments live in PostGIS with a GiST index and the same lookup is ST_DWithin(segment.geom, point, 3000), followed by the same direction and overlap checks in SQL.
03 Trust is the product
Ride-sharing is a safety product first. Every feature below answers a specific fear a first-time rider has.
A trust ladder you can see
- Tier 0NewA phone number, nothing more.Can request rides that need driver approval.
- Tier 1VerifiedPhone confirmed by OTP, plus a profile photo.Can instant-book and offer rides.
- Tier 2TrustedFive or more rides, rated 4.5 or higher.History that can’t be faked quickly.
- Alongside any tierWork-verifiedA workplace email on a registered company domain.Lets company commute rides stay inside the company.
Invisible, not disabled
Women-only rides don’t appear for men at all — not in results, counts or nearby days. A direct link shows the same neutral “This ride isn’t available” page a full or cancelled ride would, so the ride can’t be probed.
Numbers stay masked
Phones show as +91 98XXX XXX21 until a booking is confirmed; then a call and WhatsApp link appear. Until then chat redacts Indian mobile numbers, emails and UPI IDs, so contact can’t move off-platform early.
Blind ratings, both ways
Passengers rate drivers and drivers rate passengers. Neither sees the other’s review until both are in, so nobody softens a rating out of fear of retaliation.
Share my trip
A link for family shows the driver’s first name, the car and a masked plate with live progress — no phone numbers, no passenger surname — plus an SOS button that dials 112.
04 Demo mode, honestly
This build runs on Vercel with no database and no paid APIs. Anything that would be a server is a clearly labelled simulation; the engineering that matters is real.
| Concern | In this demo | In production |
|---|---|---|
| Database | Typed fixtures from a seeded generator, plus what you do stored in this browser’s localStorage. | Postgres + PostGIS. Route segments in their own table with a GiST index, queried with ST_DWithin(segment.geom, point, 3000). |
| Routing | Hand-authored corridor polylines; each ride’s route is stitched from its corridor through its stops. | OSRM (self-hosted) or Google Directions for the real road geometry. |
| Match cache | In-memory FIFO memo of the last 50 searches. | Redis, keyed by query and invalidated when a ride changes. |
| Phone OTP | Any valid Indian mobile number; the code 246810 is shown on screen. | MSG91 SMS OTP with rate limits per number and device. |
| Payments | A real upi:// deep link and QR to a demo VPA, then “I’ve paid” or settle in cash. | Razorpay UPI collect with webhook reconciliation. |
| Chat | A local thread; the driver replies from a script after 1.5 s. Contact details are redacted until confirmation. | WebSocket chat with the same redaction enforced on the server. |
| Live trip | A simulated clock moves the car along the ride’s route at 120× speed. | The driver app streams GPS; the share link reads the latest position. |
| Sign-in | A persona switcher: Priya, Arjun, Neha, Rohan and Kavita. | Phone-OTP sessions, with workplace email as a second factor. |
| Weekday commutes | Series expand into dated runs in the browser, 14 days ahead. | A nightly job materialises runs, re-plans each rider’s week and alerts them when a day loses its ride. |
What the demo simulates, and what the production build would use instead.
Database
- In this demo
- Typed fixtures from a seeded generator, plus what you do stored in this browser’s localStorage.
- In production
- Postgres + PostGIS. Route segments in their own table with a GiST index, queried with ST_DWithin(segment.geom, point, 3000).
Routing
- In this demo
- Hand-authored corridor polylines; each ride’s route is stitched from its corridor through its stops.
- In production
- OSRM (self-hosted) or Google Directions for the real road geometry.
Match cache
- In this demo
- In-memory FIFO memo of the last 50 searches.
- In production
- Redis, keyed by query and invalidated when a ride changes.
Phone OTP
- In this demo
- Any valid Indian mobile number; the code 246810 is shown on screen.
- In production
- MSG91 SMS OTP with rate limits per number and device.
Payments
- In this demo
- A real upi:// deep link and QR to a demo VPA, then “I’ve paid” or settle in cash.
- In production
- Razorpay UPI collect with webhook reconciliation.
Chat
- In this demo
- A local thread; the driver replies from a script after 1.5 s. Contact details are redacted until confirmation.
- In production
- WebSocket chat with the same redaction enforced on the server.
Live trip
- In this demo
- A simulated clock moves the car along the ride’s route at 120× speed.
- In production
- The driver app streams GPS; the share link reads the latest position.
Sign-in
- In this demo
- A persona switcher: Priya, Arjun, Neha, Rohan and Kavita.
- In production
- Phone-OTP sessions, with workplace email as a second factor.
Weekday commutes
- In this demo
- Series expand into dated runs in the browser, 14 days ahead.
- In production
- A nightly job materialises runs, re-plans each rider’s week and alerts them when a day loses its ride.
What is not simulated
The matching engine, pro-rata fares, visibility and company-policy rules, the booking rules and the commute planner are pure TypeScript functions that take the current time as a parameter, with unit tests. Every simulated surface carries a Demo badge naming the real integration, and Reset demo in the menu puts everything back.
05 For companies
What an office admin in Gurugram actually buys is a commute programme they can report on and control.
A report computed from rides, not typed in
- Employees pooling, rides shared and seat fill.
- Money saved against a cab baseline of ₹12 per passenger-km, net of fares paid.
- CO₂ saved at 0.12 kg per passenger-km.
- Four- or eight-week range, a weekly chart with a data-table fallback, and CSV export.
A policy that is actually enforced
- 1. Kavita, Acme’s admin, turns on Work email required.
- 2. Rohan has no acme.in email. He searches Cyber Hub → Sector 18 and the Acme commute rides are simply not in his results.
- 3. He opens a booking link directly anyway. The booking rules check the same policy and answer “This ride isn’t available.”
- 4. Priya, verified at acme.in, still sees and books them.
Recurring commutes
- A driver posts their office drive once with the days it runs. Each day becomes its own ride with its own id, such as
r-037-on-2026-09-17, so it is searchable, bookable and tracked separately — 14 days ahead. - A rider saves their commute. The planner lines up the next five days with a ride that stops within 2 km of both of their points and picks up within an hour of their time.
- Book all books every open day or none of them, and names the day that failed if one can’t be booked.
06 Out of scope, and how I’d approach it
Real problems that are described here rather than half-built.
Payment disputes
Collect through Razorpay before the ride, release to the driver after completion, and keep a short dispute window with a ledger per booking so support can see exactly what moved and when.
Live GPS and route deviation
Stream driver GPS from the app. The matching engine’s point-to-segment distance already measures how far a point is from a route; alert the rider and their shared contacts when the car stays off route beyond a threshold.
Fraud
An OTP ties an account to a SIM, not to a person. Add device fingerprinting, velocity limits on new accounts, and flags for rating patterns that repeat between the same pairs of users.
Insurance and commercial-vehicle rules
Private cars can share fuel costs; carrying passengers for profit can breach commercial-vehicle rules. Keep prices near fuel-share guidance — the offer flows already suggest one — and get a legal review per state before launch.
07 Try it
Two minutes, six stops.
The tour walks through a partial match, a women-only ride disappearing, booking and chat, a live trip and the company dashboard. Everything you do stays in this browser; reset it from the menu.