intermediate
rider-score
helmet-selfie
safety

Helmet Selfie Discount

How the pre-unlock helmet selfie verification works - capture, storage, TTL, and how the discount is applied.

Levy Fleets TeamMay 18, 20267 min read

Helmet Selfie Discount

A rider taps Verify helmet before unlock, the app captures a live selfie, the system stores it, and the rider gets a discount off the unlock fee. The verification is also fed into the per-trip score as the "helmet verified" signal.

Critical naming note

The helmet selfie table is rider_helmet_selfies. It was renamed from helmet_verifications to avoid a collision with the computer-vision pipeline's own helmet_verifications table (a different concept). If you are reading older internal docs that reference helmet_verifications in the rider-score context, treat that name as out of date - the canonical table is rider_helmet_selfies.

How it works for the rider

  1. At unlock, the app checks for an active helmet verification on the rider's account.
  2. If none exists or it has expired, the unlock screen shows a Verify helmet button with the discount preview ("Wear your helmet to save $0.50 on this unlock").
  3. Tapping it opens the camera. The rider captures themselves in their helmet.
  4. The selfie uploads to the private storage bucket and a rider_helmet_selfies row is created with passed_at=now() (v3.0 trusts the live capture; v3.1 will add a CV pass).
  5. The discount is applied immediately at the unlock-fee level. The "helmet verified" signal also feeds the per-trip score, raising it.

What gets stored

FieldValue
idUUID primary key
customer_uuidFK to customers
ride_uuidOptional FK to the ride at which the selfie was captured
storage_pathObject path inside the helmet-verifications private storage bucket
passed_atTimestamp the verification was accepted (null = pending/failed)
ttl_expires_atWhen this verification stops being valid for new unlocks (default 24h)
consumed_atWhen the discount was applied at unlock (tracks single-use behavior)
methodself_capture (v3.0) or cv_verified (v3.1+)

Note again: the table name is rider_helmet_selfies, not helmet_verifications. The storage bucket is helmet-verifications, which is fine - the bucket and the table are deliberately named differently to keep the naming separation intact.

TTL and reuse

  • Default TTL is 24 hours. Editable per-subaccount.
  • A verified selfie stays usable for multiple unlocks until ttl_expires_at, unless consumed_at is set (single-use mode, off by default).
  • After ttl_expires_at + 30 days, the image file is purged from the storage bucket by the helmet-verification-cleanup cron unless an open dispute references it.

Pricing integration

The discount is applied at the unlock-fee level through the standard pricing pipeline. The bridge function apply-uplift.ts is the single place where rider-score-related pricing modifiers (helmet discount AND price uplift) get computed, so the discount stays consistent with At Risk uplifts and never forks ride-pricing logic.

Subaccount settingEffect
helmet_discount_unlock_fee_centsCents off the unlock fee per verified ride
helmet_ttl_hoursHow long a single verification stays valid
helmet_single_useIf true, a verification is consumed on first unlock

Beginner riders

A successful helmet selfie during the Beginner tier (rides 1-3) unlocks Silver-tier perks for that rider for the remainder of their Beginner period. The intent: new riders get rewarded for safe behavior immediately, before they have a real rolling score.

What the score formula does with the signal

The "helmet verified" term is worth 10 points out of 100 on the default weights. A rider who is helmet-verified at unlock effectively gets a 10-point head start on the per-trip score.

This is on top of the unlock-fee discount. The two effects are deliberately independent - one is pricing, one is scoring - so you can tune them separately.

Storage and privacy

  • Selfies live in a private Supabase storage bucket. Riders cannot share or expose their own selfies; the operator sees them only in the appeal queue when relevant.
  • We do not run face recognition. We only check for the presence of a helmet (v3.1+ with CV) or trust the live-capture timestamp (v3.0).
  • Images are deleted 30 days after ttl_expires_at by the cleanup cron unless the verification is linked to an open dispute or appeal.
  • Levy never shares helmet selfies with insurers, cities, or law enforcement except by warrant.

v3.0 vs v3.1

Aspectv3.0 (today)v3.1 (planned)
VerificationTrust live capture metadata (timestamp + camera-real-time flag)Run a CV pass on the image to confirm a helmet is in frame
RiskSlightly easier to spoofHarder to spoof but adds compute cost
Where logic livessubmitHelmetSelfie()Same entry point, new CV step before passed_at is set

v3.0 is rolled out today. v3.1 lands once the computer-vision pipeline (project 4) is GA.

API surface

EndpointPurpose
POST /api/mobile/rider/helmet-selfieUpload selfie, returns discount token
GET /api/cron/helmet-verification-cleanupTTL+30d image purge (background)

What the operator can do

  • View any active or recent verification on a rider's profile (no raw image - only metadata and a signed short-lived URL if you click through).
  • Force-expire a verification (e.g. if you suspect spoofing). Writes a score_audit_log row.
  • Adjust the per-subaccount discount and TTL at Settings > Helmet selfie.

What the rider cannot do

  • Reuse another rider's selfie - selfies are keyed to customer_uuid.
  • Upload a still image from the camera roll - the capture flow forces the live camera.
  • Skip the helmet flow if a step-4 throttle cap or step-6 lockout is already active. Helmet verification does not override an active intervention.

Next

See Reward Tiers for how the discount complements tier perks. See Reaction-Time Safe Ride Check for the other pre-unlock verification.