Skip to main content

Overview

Sovran integrates with BTCMap.org to display over 30,000 Bitcoin-accepting merchants worldwide. The map uses high-performance clustering powered by Mapbox Supercluster to handle large datasets smoothly.
BTCMap data is sourced from OpenStreetMap and verified by the Bitcoin community. All merchant data is cached locally for 1 hour.

Features

Interactive Map

Clustering

Intelligent marker clustering for smooth performance

Categories

Filter by food, retail, ATMs, accommodation, or services

Privacy

Location is offset to protect your privacy

Details

View payment methods, hours, and contact info

Category Filtering

Filter merchants by type:

Implementation Details

Data Fetching

Merchant data is fetched from the BTCMap API and cached locally:

Clustering Algorithm

Sovran uses Mapbox’s Supercluster for O(log n) performance:

Cluster Caching

Cluster indexes are cached to avoid rebuilding on navigation:

Performance Optimizations

The map uses several techniques for smooth performance:
1

Deferred Rendering

Map rendering is delayed 50ms to allow modal animation to start
2

InteractionManager

Heavy operations run after interactions complete using InteractionManager.runAfterInteractions()
3

Debounced Updates

Marker updates are debounced 250ms during panning/zooming
4

Viewport Culling

Only markers in the visible viewport (plus padding) are rendered

Bounding Box Calculation

Convert camera position to bounding box for cluster queries:

Merchant Details

Data Model

Detailed merchant information includes:

Detail Screen

The detail screen displays comprehensive merchant information:
The UI shows:
  • Payment methods (on-chain, Lightning, contactless)
  • Contact information (phone, website, email, socials)
  • Opening hours
  • Description
  • Verification status and date

Privacy Features

Location Offsetting

User location is offset to prevent exact position tracking:
This is applied when:
  • Centering map on user location
  • Using “My Location” button
  • Initial map load with permissions

Map Controls

Floating Action Buttons

Map controls are rendered as glass-effect buttons on iOS:

Stats Card

Contextual stats with category filter:

Best Practices

  • Cache Awareness: Cluster managers are cached per category filter
  • Debouncing: Don’t update markers too frequently during panning
  • Viewport Queries: Only query visible markers plus reasonable padding
  • Progressive Loading: Show UI immediately, defer heavy operations
  • Loading States: Show skeleton/loading while fetching data
  • Error Handling: Gracefully handle network failures with cached data
  • Cluster Expansion: Tap cluster to zoom in and reveal individual merchants
  • Deep Links: Support direct navigation to merchant details
  • Location Offsetting: Never center map on exact user location
  • Permission Requests: Request location permission gracefully
  • Local Storage: Cache data locally to minimize API requests

Code Reference

Source Files

  • app/(map-flow)/index.tsx:1-778 - Main map screen with clustering
  • app/(map-flow)/detail.tsx:1-414 - Merchant detail view
  • stores/btcMapStore.ts:1-243 - Data fetching and caching
  • utils/mapClustering.ts:1-233 - Supercluster wrapper
  • utils/btcMapClusterCache.ts:1-67 - Cluster manager caching

Key Functions

  • fetchPlaces() - Fetch all merchants from BTCMap API
  • fetchPlaceDetails(id) - Fetch detailed merchant information
  • getClusters(bbox, zoom) - Get clustered markers for viewport
  • getClusterExpansionZoom(clusterId) - Calculate zoom level to expand cluster
  • cameraToBbox(lat, lon, zoom) - Convert camera to bounding box