Skip to content

Venue Import Guide โ€‹

Purpose: Populate the platform with real businesses so users can discover and visit venues.


Quick Start โ€‹

Import San Diego downtown venues (5km radius, ~500 venues):

bash
GOOGLE_APPLICATION_CREDENTIALS=$HOME/repos/secrets/firebase/lantern-app-dev-firebase-adminsdk-fbsvc-6ea86176a1.json \
npm run import:venues:osm

Dry run (preview without writing):

bash
GOOGLE_APPLICATION_CREDENTIALS=$HOME/repos/secrets/firebase/lantern-app-dev-firebase-adminsdk-fbsvc-6ea86176a1.json \
npm run import:venues:osm -- --dry-run

Custom area (North Park, San Diego):

bash
GOOGLE_APPLICATION_CREDENTIALS=$HOME/repos/secrets/firebase/lantern-app-dev-firebase-adminsdk-fbsvc-6ea86176a1.json \
npm run import:venues:osm -- --lat=32.7416 --lng=-117.1286 --radius=3000 --limit=200

Import + consolidate duplicates (recommended):

bash
GOOGLE_APPLICATION_CREDENTIALS=$HOME/repos/secrets/firebase/lantern-app-dev-firebase-adminsdk-fbsvc-6ea86176a1.json \
npm run import:venues:osm -- --lat=32.7157 --lng=-117.1611 --radius=5000 --consolidate

Consolidate only (merge duplicate docs in area, no new fetch):

bash
GOOGLE_APPLICATION_CREDENTIALS=$HOME/repos/secrets/firebase/lantern-app-dev-firebase-adminsdk-fbsvc-6ea86176a1.json \
npm run import:venues:osm -- --consolidate-only --lat=32.7157 --lng=-117.1611 --radius=5000

Data Source: OpenStreetMap (OSM) โ€‹

Why OSM:

  • โœ… Free, no API key required
  • โœ… Good coverage in major cities (San Diego, LA, SF, NYC, etc.)
  • โœ… Community-maintained, proven long-term sustainability
  • โœ… Includes name, address, coordinates, category

Tradeoffs:

  • โŒ No official business verification (use Google Places for merchant claims later)
  • โŒ Hours/phone less reliable than Google (community-entered)
  • โŒ Quality varies by region (excellent in cities, sparse in rural areas)

When to upgrade to Google Places:

  • Merchant claim flow (need verified placeId and business details)
  • High-quality hours/phone required
  • Areas with poor OSM coverage

How It Works โ€‹

  1. Query Overpass API for businesses in radius (cafes, bars, restaurants, bookstores, yoga studios, etc.)
  2. Normalize OSM data โ†’ venue format with geohash, address, category
  3. Deduplicate by osmId (skip venues already in Firestore)
  4. Batch write to Firestore venues collection

Script: scripts/import-venues-osm.mjs


CLI Options โ€‹

FlagDescriptionDefault
--latCenter latitude32.7157 (San Diego downtown)
--lngCenter longitude-117.1611
--radiusSearch radius in meters5000 (5km)
--limitMax venues to import500
--dry-runPreview without writing to Firestorefalse
--consolidateAfter import, merge duplicate docs in area by osmIdfalse
--consolidate-onlyOnly run consolidation (skip OSM fetch/import)false

Categories Imported โ€‹

OSM tags โ†’ Lantern categories:

  • cafe โ†’ coffee_shop
  • bar, pub, nightclub, biergarten โ†’ bar
  • restaurant, fast_food โ†’ restaurant
  • bookshop, library โ†’ bookstore
  • yoga, fitness_centre, gym โ†’ yoga_studio

Add more categories by editing CATEGORY_MAP in scripts/import-venues-osm.mjs.


Cost & Rate Limits โ€‹

Overpass API:

  • Free, no authentication
  • Rate limit: ~2 requests/second
  • Timeout: 60 seconds per query
  • Fair use policy: don't hammer the API

Firestore writes:

  • 500 venues = 500 writes = $0.09 (well within free tier)
  • Geohash computed client-side (no extra cost)

Deduplication โ€‹

The import script now:

  • Updates existing venues when the same osmId is found (preserving merchant-customized fields like name/description)
  • Can consolidate duplicates that already exist in Firestore (multiple docs with the same osmId) within an area

Run consolidation after an import, or on its own:

bash
# Import + consolidate in one step
GOOGLE_APPLICATION_CREDENTIALS=$HOME/repos/secrets/firebase/lantern-app-dev-firebase-adminsdk-fbsvc-6ea86176a1.json \
npm run import:venues:osm -- --lat=32.7157 --lng=-117.1611 --radius=5000 --consolidate

# Consolidate only for an area
GOOGLE_APPLICATION_CREDENTIALS=$HOME/repos/secrets/firebase/lantern-app-dev-firebase-adminsdk-fbsvc-6ea86176a1.json \
npm run import:venues:osm -- --consolidate-only --lat=32.7157 --lng=-117.1611 --radius=5000

Dry-run is supported for both import and consolidation with --dry-run.


On-Demand Refresh Strategy โ€‹

How it works:

  1. User opens app โ†’ location detected โ†’ check geohash prefix staleness
  2. Fresh (<30 days): Return cached venues immediately
  3. Moderately stale (30-90 days): Return cached + trigger background refresh
  4. Very stale (>90 days) or new area: Show friendly loading message + block for refresh

Loading messages:

  • New area: "Thanks for your patience while we load nearby spots..."
  • Stale area: "Updating venue data, thanks for waiting..."
  • Background: Toast notification "Refreshing venues in the background"

Benefits:

  • Only refresh areas people actually visit (cost-efficient)
  • Fresh data in popular areas
  • Instant results for returning users
  • No stale data shown

Firestore collections:

  • venueRefreshMetadata - tracks { geohashPrefix, lastRefreshedAt, inProgress }
  • One doc per ~5km area (geohash precision 5)

Current behavior (dev site):

  • The app checks staleness and calls triggerAreaRefresh() when needed.
  • In development, triggerAreaRefresh() logs the command and marks the area as in progress, but does not execute the import automatically.
  • To actually populate or refresh from the dev site trigger, run the CLI command that is logged in the console.

Production setup (TODO):

  • Deploy a Cloud Function for real refreshes. It should invoke the import script (or equivalent) with lat/lng/radius and update venueRefreshMetadata on completion.

Troubleshooting โ€‹

"Overpass API error: 429"

  • Rate limited; wait 1 minute and retry
  • Reduce --radius or --limit

"Overpass API error: 504 Gateway Timeout"

  • Query too complex or server overloaded
  • Reduce --radius (try 2000m instead of 5000m)
  • Retry in a few minutes

"No venues found in this area"

  • Check lat/lng are correct
  • Try larger --radius
  • Area may have poor OSM coverage (switch to Google Places)

Venues missing hours/phone

  • OSM data is community-entered and incomplete
  • Merchants can add these during claim flow
  • Consider Google Places for verified business details

Next Steps โ€‹

  1. Import pilot area (San Diego downtown): npm run import:venues:osm
  2. Verify in Firestore console that venues appear with geohash
  3. Test in app (npm run dev) โ†’ Dashboard should show nearby venues
  4. Build merchant claim UI (see TODO.md) so merchants can claim their venues
  5. Optional: Add Google Places import script for verified business data


Questions? Check Overpass API docs: https://wiki.openstreetmap.org/wiki/Overpass_API

Built with VitePress