How to — add a map provider
Adding a fifth map provider touches the widget (tile URL templates + attribution + style builder) and the dashboard (provider picker + API key guide). No backend change is required — the map provider and API key are stored as design.* settings in the finder’s JSON column.
The four existing providers are: TomTom, Mapbox, HERE, and OpenStreetMap.
Step 1 — Add the provider to the widget’s mapSettings.js
The widget builds MapLibre-compatible style objects in dropafinder-app-external/ext/2/source/src/lib/mapSettings.js. This is the file you edit most heavily.
1a — Add the provider to the MapProvider type normalizer
Extend normalizeMapProvider() with the new provider slug:
export function normalizeMapProvider(value) {
switch (value) {
case 'tomtom':
case 'mapbox':
case 'here':
case 'osm':
case 'stadia': // ← new provider
return value;
default:
return 'tomtom';
}
}1b — Add attribution text
The DEFAULT_ATTRIBUTION object holds the attribution string required by each provider’s terms of service. Attribution is passed to MapLibre and rendered in the map corner:
const DEFAULT_ATTRIBUTION = {
tomtom: '© TomTom',
mapbox: '© Mapbox © OpenStreetMap',
here: '© HERE',
osm: '© OpenStreetMap contributors',
stadia: '© Stadia Maps © OpenMapTiles © OpenStreetMap contributors', // ← add
};Check the new provider’s terms of service for the exact required attribution string.
1c — Add style variant support
If the new provider supports dark/satellite/hybrid styles, add the configuration object (matching the HERE pattern):
const STADIA_STYLE_IDS = {
standard: 'stamen_toner_lite',
dark: 'alidade_smooth_dark',
// satellite and hybrid: null if not supported
};If the provider supports only one style, update isMapStyleVariantSupported() to restrict it:
export function isMapStyleVariantSupported(provider, styleVariant) {
if (provider === 'osm' || provider === 'stadia') {
return styleVariant === 'standard' || styleVariant === 'dark';
}
return true;
}1d — Add the style builder function
Add a buildStadiaStyle() function following the pattern of the existing builders:
function buildStadiaStyle(styleVariant, apiKey) {
const styleId = STADIA_STYLE_IDS[styleVariant] ?? STADIA_STYLE_IDS.standard;
return buildSingleSourceStyle(
[`https://tiles.stadiamaps.com/tiles/${styleId}/{z}/{x}/{y}.png?api_key=${apiKey}`],
256,
DEFAULT_ATTRIBUTION.stadia
);
}buildSingleSourceStyle(tiles, tileSize, attribution) returns a MapLibre style object with a single raster source. Use it for any provider that serves raster tiles; TomTom hybrid is the example of a multi-source style.
1e — Register in buildMapStyle()
Add a case to the buildMapStyle() switch:
export function buildMapStyle({ provider, styleVariant, apiKey }) {
switch (provider) {
case 'mapbox':
return buildMapboxStyle(styleVariant, apiKey);
case 'here':
return buildHereStyle(styleVariant, apiKey);
case 'osm':
return buildSingleSourceStyle(OSM_TILES, 256, DEFAULT_ATTRIBUTION.osm);
case 'stadia': // ← add
return buildStadiaStyle(styleVariant, apiKey); // ← add
case 'tomtom':
default:
return buildTomTomStyle(styleVariant, apiKey);
}
}1f — Update providerNeedsApiKey()
If the new provider requires an API key:
export function providerNeedsApiKey(provider, tileSet) {
if (tileSet === TOMTOM_GIFT_TILE_SET) return false;
return provider !== 'osm'; // all others require a key — no change needed for most providers
}OSM is the only key-free provider today. If the new provider is also key-free, add it to the exception:
return provider !== 'osm' && provider !== 'stadia-free';Step 2 — Add the provider to the dashboard’s mapSettings.ts
The dashboard has a mirrored (TypeScript) version of the provider registry in dropafinder-app-nextjs/src/lib/mapSettings.ts.
2a — Extend the MapProvider type
export type MapProvider = 'tomtom' | 'mapbox' | 'here' | 'osm' | 'stadia';2b — Add to MAP_PROVIDER_OPTIONS
export const MAP_PROVIDER_OPTIONS: Array<{ value: MapProvider; label: string }> = [
{ value: 'tomtom', label: 'TomTom' },
{ value: 'mapbox', label: 'Mapbox' },
{ value: 'here', label: 'HERE' },
{ value: 'osm', label: 'OpenStreetMap' },
{ value: 'stadia', label: 'Stadia Maps' }, // ← add
];2c — Add the API key guide URL
export const MAP_PROVIDER_API_KEY_GUIDES: Record<MapProvider, { label: string; url: string }> = {
// ...existing entries...
stadia: {
label: 'Stadia Maps API key guide',
url: 'https://docs.stadiamaps.com/authentication/',
},
};The API key guide link appears in MapsSection.tsx (dropafinder-app-nextjs/src/components/finders/v2/sections/MapsSection.tsx) automatically via getMapProviderApiKeyGuide(), so no changes to the section component are needed unless the new provider requires custom UI.
2d — Update normalizeMapProvider() in mapSettings.ts
export function normalizeMapProvider(value: unknown): MapProvider {
switch (value) {
case 'tomtom':
case 'mapbox':
case 'here':
case 'osm':
case 'stadia': // ← add
return value;
default:
return 'tomtom';
}
}Also update isMapStyleVariantSupported() to match the widget’s version.
Step 3 — Add env var for dashboard Live Preview key (optional)
If you want the dashboard’s Live Preview to render maps for this provider using a shared key (the way TomTom’s gift tile set works), add an env var to dropafinder-app-nextjs/.env.local:
NEXT_PUBLIC_STADIA_KEY=your_key_hereThen update getResolvedMapApiKey() in mapSettings.ts to fall back to it:
case 'stadia':
return fallbackKeys?.stadia ?? '';Step 4 — Verify locally
- Build the widget:
npm run build:devinext/2/source/. - Open the Finder Builder at
http://localhost:3000. - Navigate to Maps → Base Map. The new provider should appear in the dropdown.
- Select it, enter an API key, and confirm the Live Preview renders tiles from the new provider.
- Test each supported style variant (standard, dark, etc.) in the Live Preview.
Step 5 — Deploy
Both the widget and the dashboard changed:
# 1. Widget first
cd "/Users/codydavis/Local Sites/dropafinder-app-external/ext/2/source"
npm run deploy:02
# 2. Dashboard second
cd "/Users/codydavis/Local Sites/dropafinder-app-nextjs"
git push origin mainSee deploy for the full ritual.
Where to next
- Customer-facing map provider reference:
content/customization/map-providers.md - Add an autocomplete provider (separate surface): add-autocomplete-provider