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:- 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:- 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
Performance
Performance
- 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
UX
UX
- 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
Privacy
Privacy
- 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 clusteringapp/(map-flow)/detail.tsx:1-414- Merchant detail viewstores/btcMapStore.ts:1-243- Data fetching and cachingutils/mapClustering.ts:1-233- Supercluster wrapperutils/btcMapClusterCache.ts:1-67- Cluster manager caching
Key Functions
fetchPlaces()- Fetch all merchants from BTCMap APIfetchPlaceDetails(id)- Fetch detailed merchant informationgetClusters(bbox, zoom)- Get clustered markers for viewportgetClusterExpansionZoom(clusterId)- Calculate zoom level to expand clustercameraToBbox(lat, lon, zoom)- Convert camera to bounding box