Skip to main content
Onboarding flows can contain a Map element — a route through several stops, or a single place with its details. Before it can draw anything, the app needs a map provider and a key. All of it is configured once per app, not per flow and not per map: Settings → Apps → your app → Maps

Choose a provider

The provider applies to every Map element in every flow for this app. It sits next to the keys because it selects between them: picking a provider you have no key for is the one mistake that produces a placeholder on every device with nothing to explain it, so the settings page warns you inline when the two disagree.
Both keys are yours. Maps are fetched directly by the device and by the flow editor’s preview, so usage bills to your own Mapbox or Google account. There is deliberately no shared AppDNA key: Mapbox’s Product Terms forbid us serving their imagery on another account’s behalf, and Google bills map requests to whoever owns the key.

Mapbox public token

Create one under Account → Tokens at mapbox.com, then paste it into the Mapbox field. It must be a public token — it starts with pk.. It travels inside every map image URL, so it is public by design; restrict it by URL in the Mapbox dashboard rather than trying to keep it secret. A secret sk. token is rejected by the image API and must never be shipped to devices.

Google Maps API key

In the Google Cloud console, create an API key and enable the APIs you need: Paste the key (it starts with AIza) into the Google Maps field.
The API restrictions dropdown only lists APIs that are already enabled in the project. If it looks empty, enable the ones above in the Library first, then come back to the key — the list refreshes. Key changes can take a few minutes to take effect, so an immediate 403 is not necessarily a mistake.
Restrict it by API, not by application. A Google key accepts only one application restriction — None, HTTP referrers, IP addresses, Android apps, or iOS apps — and the SDK fetches the static map as a plain HTTPS request straight from the device. That request carries no referrer and no bundle ID, so an HTTP-referrer restriction works in the console preview and fails on every device, while an iOS/Android app restriction covers pan & zoom but not the static image.Set Application restrictions: None, then use API restrictions → Restrict key and select only the APIs in the table above. Add a cap under APIs & Services → Quotas so a leaked key cannot run up a bill. That is the combination that works on device and in the console.

Google Places key — a different key

The Google Places API key on the same page is not the same credential and is entirely optional. It powers place search when you add stops to a map in the editor. It is used only by the console, never shipped to devices, and stored encrypted — so it is never displayed again after you save it. Without it you can still enter coordinates by hand.

Pan & zoom

Turning on Interactive (pan & zoom) for a Map element gives the user a real, draggable map instead of a still image. A Map element whose setting was never saved is interactive — the switch shows it on unless you switch it off — while a Map element you add now starts with the switch off. It needs the Google provider, and on Android it also needs one line in your app’s manifest, because the Maps SDK for Android reads its key at build time:
iOS needs nothing for the static map — its Maps SDK takes the key at runtime, so the key you set here is enough. For pan & zoom, an iOS app that integrates via Swift Package Manager needs GoogleMaps.bundle copied to its app bundle root; SwiftPM nests it where the Maps SDK cannot find it, and adding the GoogleMaps package to the app target does not change that. CocoaPods hosts — including React Native and Flutter — are unaffected. See the iOS installation guide. See the Android and iOS installation guides for the full detail, including the CocoaPods linkage settings React Native and Flutter hosts need. Without that manifest line an Android app falls back to the still image — the map simply does not pan. Nothing breaks.

Route line and camera on the pan & zoom map

The pan & zoom map draws the same route as the still image:
  • Route line. When the element has a Fixed route line (an encoded polyline, set in the editor or supplied by your app), the map draws that polyline. Otherwise, with two or more stops, it draws straight segments between the stops. The route colour and width apply to whichever line is drawn. Stops are always shown as markers; polyline points never become markers.
  • Polylines use Google’s encoding at precision 5. Precision-6 polylines (polyline6, as produced by some routing services) are not supported — read as precision 5, every coordinate comes out ten times too large. If any point then falls outside ±90° latitude / ±180° longitude the line is ignored and the map falls back to the stops — that is almost every route. A route whose every point lies within 9° of the equator and 18° of the prime meridian decodes in range instead, and draws in the wrong place. The still image does not check the polyline: it passes it to Mapbox or Google unchanged, and both read it at precision 5 too. Always encode at precision 5.
  • Camera. With Auto-fit to the route and stops on (the default), the map frames the route line and every stop, with a small margin, as soon as the map has a size — and again whenever the route or stops change (for example when your app’s route data arrives after the first frame). If only one point exists, the map centres on it at zoom 15. With Auto-fit off, the map centres on the authored centre at the authored zoom (the same rule as the still image). The user’s own pan and zoom are never overridden except by such a route change.
  • Antimeridian: on iOS, routes that cross the ±180° meridian are not framed correctly; the fit uses a simple min/max bounding box. Android frames with the Google Maps SDK’s bounds builder instead.

When a map shows “Map unavailable”

That placeholder is the deliberate, labelled fallback: a map with no key degrades to a caption, never to a blank box. It appears when: The flow editor’s preview uses the same keys and the same provider as the device, so whatever you see on the canvas is what your users will see.