# Mapbox

- Tool: FlutterFlow
- Difficulty: Advanced
- Time required: 60 minutes
- Last updated: July 2026

## TL;DR

Connect FlutterFlow to Mapbox by building a Custom Widget that wraps the mapbox_maps_flutter pub.dev package. You need two Mapbox tokens: a public pk.* access token used at runtime inside the widget, and a secret sk.* download token (with DOWNLOADS:READ scope) configured at native build level so Flutter can download the Mapbox SDK. Pass your Mapbox Studio custom style URL as a widget parameter. Places search and Directions use separate API Calls to api.mapbox.com with the public token.

## Mapbox in FlutterFlow: Custom Styles, Vector Tiles, and a Two-Token Build Setup

Mapbox is the go-to choice for FlutterFlow founders who need maps that look distinctly branded — custom colors, dark mode, minimalist styles, or satellite overlays with custom data layers. Unlike the default Google Maps or OpenStreetMap tiles, Mapbox lets you design your map's visual appearance pixel by pixel in Mapbox Studio and then reference that style in your Flutter app with a mapbox://styles/ URL. That style URL is the main reason to choose Mapbox over the alternatives.

Mapbox pricing is generous for mobile apps: 50,000 free web map loads per month, 100,000 free Directions API calls per month, and 50,000 free static image requests per month. After the free tier, pricing is pay-as-you-go by request volume and decreases at higher volumes (verify current rates at mapbox.com/pricing before building financial projections). There is no separate per-user fee.

The Mapbox Flutter SDK (mapbox_maps_flutter) is a full-featured native map SDK that compiles to iOS and Android native code. This gives excellent performance and smooth animations but adds build complexity that does not exist for the OpenStreetMap flutter_map or the Google Maps native widget: you need a secret download token (sk.*) with DOWNLOADS:READ scope configured at the native build level so that the Flutter build system can download the Mapbox SDK binary. This token is NOT a runtime key — it is only used during compilation. The runtime key is your public pk.* token, which is fine to embed in the widget Dart code.

## Before you start

- A Mapbox account — the free tier with 50,000 map loads/month is sufficient for development and small production apps
- Two Mapbox tokens: your default public token (pk.*) and a new secret token (sk.*) created with only DOWNLOADS:READ scope
- A FlutterFlow project — a paid plan is recommended since Custom Widgets require Run mode and device testing for verification
- Understanding that the Mapbox Custom Widget will not render in the FlutterFlow canvas — only in Run mode and on real device builds
- Optional but recommended: a Mapbox Studio account to design a custom map style referenced by a mapbox://styles/ URL

## Step-by-step guide

### 1. Get your Mapbox tokens and create a custom map style

Log into your Mapbox account at account.mapbox.com. Your default public access token (starting with pk.) is visible on the Tokens page — copy it. This is the token you will embed in your Flutter widget Dart code. It is safe to ship in the app because Mapbox allows you to URL-restrict or scope-restrict public tokens, and the pk.* prefix itself tells Mapbox to apply public-scope rules.

For the download token, click 'Create a token'. Give it a name like 'FlutterFlow Build Token'. Under Secret Token Scopes, enable ONLY 'DOWNLOADS:READ' — do not add any other scopes. This token will be used during the Flutter build process to download the Mapbox native SDK binary from Mapbox's private Maven/CocoaPods repository. If you accidentally give this token broader scopes and it is discovered, the damage is limited to SDK downloads. Click 'Create Token' and copy the sk.* value — you will not be able to view it again.

For your map style, go to Mapbox Studio (studio.mapbox.com). Create a new style from a template (Streets, Outdoors, Dark, Light, Satellite Streets) or start from scratch. Customize colors, fonts, and layer visibility to match your app's branding. When satisfied, click 'Publish' and copy the Style URL in the format mapbox://styles/yourusername/yourstyleid. This URL is what you will pass as a parameter to your Custom Widget.

**Expected result:** You have your public pk.* token, a DOWNLOADS:READ-scoped sk.* token, and a Mapbox Studio style URL ready to use.

### 2. Add mapbox_maps_flutter as a Custom Code dependency in FlutterFlow

In FlutterFlow, click Custom Code in the left navigation panel. Find the Dependencies (pub.dev Packages) section and click Add Dependency. Type mapbox_maps_flutter and enter the latest stable version — check pub.dev/packages/mapbox_maps_flutter for the current release. Unlike flutter_map (which is pure Dart), mapbox_maps_flutter includes native iOS and Android code, which is why it needs the download token during compilation.

After adding the dependency, FlutterFlow will attempt to sync the package. If a version conflict appears, try the previous minor version of mapbox_maps_flutter. This package is more likely to cause dependency conflicts than flutter_map because it pulls in native Mapbox SDK dependencies that may conflict with other native packages in your FlutterFlow project.

The secret sk.* download token configuration cannot be done directly in the FlutterFlow UI — it requires configuring the native iOS and Android project files. When you export your FlutterFlow project as a Flutter project (via Download Code or GitHub integration) and build it locally or in a CI/CD pipeline, you will add the sk.* token to the .netrc file (for iOS CocoaPods) and the gradle.properties file (for Android) before running the build. If you use FlutterFlow's direct deploy feature, contact FlutterFlow support about configuring native credentials for Mapbox builds — this is an advanced build configuration step.

```
# For Android — add to ~/.gradle/gradle.properties before building:
MAP_BOX_SECRET_TOKEN=sk.eyJ1...your_secret_token

# For iOS — add to ~/.netrc before running pod install:
machine api.mapbox.com
  login mapbox
  password sk.eyJ1...your_secret_token
```

**Expected result:** mapbox_maps_flutter appears in your FlutterFlow Custom Code dependencies without version conflict errors. Native build configuration is documented for when you export and build the project.

### 3. Create the Mapbox Custom Widget in FlutterFlow

In the Custom Code section of FlutterFlow, click + Add → Widget. Name it 'MapboxMapWidget'. FlutterFlow will open a Dart code editor with a template. Replace the template with the complete Mapbox widget below.

The widget accepts four parameters you will configure in the widget's Parameters tab: styleUrl (String, the mapbox://styles/ URL from Mapbox Studio), latitude (double, center latitude), longitude (double, center longitude), and zoom (double, initial zoom level). The Dart code initializes a MapboxMap widget from the mapbox_maps_flutter package with these parameters. Marker support for basic use cases is handled by updating the map's annotation manager when the widget rebuilds with new coordinates.

After pasting the code, click the Parameters tab in the Custom Widget editor and add each parameter with its correct type and a sensible default value (e.g., latitude: 40.7128, longitude: -74.0060 for New York, zoom: 12.0, styleUrl: 'mapbox://styles/mapbox/streets-v12' for the default streets style).

The Custom Widget will show a grey placeholder box in the canvas editor — this is expected. It only renders in Run mode and on a real device build because it wraps native iOS and Android Mapbox code.

```
import 'package:flutter/material.dart';
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart';

class MapboxMapWidget extends StatefulWidget {
  const MapboxMapWidget({
    super.key,
    this.width,
    this.height,
    this.styleUrl = 'mapbox://styles/mapbox/streets-v12',
    this.latitude = 40.7128,
    this.longitude = -74.0060,
    this.zoom = 12.0,
  });

  final double? width;
  final double? height;
  final String styleUrl;
  final double latitude;
  final double longitude;
  final double zoom;

  @override
  State<MapboxMapWidget> createState() => _MapboxMapWidgetState();
}

class _MapboxMapWidgetState extends State<MapboxMapWidget> {
  MapboxMap? _mapboxMap;

  @override
  void initState() {
    super.initState();
    // Set your public pk.* token before MapboxMap renders
    MapboxOptions.setAccessToken('pk.YOUR_PUBLIC_TOKEN_HERE');
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: widget.width ?? double.infinity,
      height: widget.height ?? 300,
      child: MapboxMap(
        styleUri: widget.styleUrl,
        cameraOptions: CameraOptions(
          center: Point(
            coordinates: Position(
              widget.longitude,
              widget.latitude,
            ),
          ),
          zoom: widget.zoom,
        ),
        onMapCreated: (MapboxMap mapboxMap) {
          _mapboxMap = mapboxMap;
        },
      ),
    );
  }
}
```

**Expected result:** MapboxMapWidget appears in your FlutterFlow Custom Widgets list. It shows a grey placeholder in the canvas editor but renders a Mapbox map in Run mode on a real device.

### 4. Place the Mapbox widget on a page and bind parameters to Mapbox Studio style

Create a new page in FlutterFlow (e.g., 'MapScreen'). Add two Page State variables: mapCenterLat (double, default 40.7128) and mapCenterLng (double, default -74.0060). These will drive the map's center coordinates dynamically.

From the Widget Palette under Custom Widgets, drag your MapboxMapWidget onto the page. Set its width to 100% (full width) and height to 350 px or half screen. In the widget's parameter bindings in the right panel, bind latitude to mapCenterLat, longitude to mapCenterLng, and set zoom to a hardcoded value of 12.0.

For the styleUrl parameter, paste your Mapbox Studio URL — for example mapbox://styles/yourusername/yourstyleid. If you have not created a custom style yet, use one of Mapbox's built-in styles: mapbox://styles/mapbox/streets-v12, mapbox://styles/mapbox/outdoors-v12, mapbox://styles/mapbox/dark-v11, or mapbox://styles/mapbox/satellite-streets-v12.

To verify the parameter binding, add a button on the page that sets mapCenterLat to 48.8566 and mapCenterLng to 2.3522 (Paris). In Run mode, tapping this button should pan the map to Paris. This confirms that the widget responds to Page State changes before you add the full geocoding flow in the next step.

**Expected result:** The MapboxMapWidget is on the page, bound to Page State variables, and switches map center when you tap a test button in Run mode.

### 5. Add Mapbox Geocoding and Directions API Calls

Mapbox's Geocoding and Directions services are separate REST APIs at api.mapbox.com — you connect them via FlutterFlow API Calls using your public pk.* token as a query parameter.

For geocoding (address search), click API Calls in the left nav, + Add → Create API Call. Name it 'MapboxGeocode'. Method GET, URL https://api.mapbox.com/geocoding/v5/mapbox.places/{{searchText}}.json. Query params: access_token (your pk.* token, hardcoded) and limit with value 5. In Response & Test, test with a city name and generate JSON Paths: $.features[0].center[0] for longitude and $.features[0].center[1] for latitude, and $.features[0].place_name for the display text. Note that Mapbox's geocoding response puts coordinates in GeoJSON format [longitude, latitude] order — double-check you are mapping center[0] to longitude and center[1] to latitude.

For directions, create another API Call named 'MapboxDirections'. URL https://api.mapbox.com/directions/v5/mapbox/driving/{{originLng}},{{originLat}};{{destLng}},{{destLat}}. Query params: access_token, geometries=geojson, and overview=full. The response includes $.routes[0].geometry.coordinates (an array of [lng, lat] pairs) for drawing the route line, and $.routes[0].duration (seconds) and $.routes[0].distance (meters) for the trip summary.

For heavy Places or Directions usage, consider proxying calls through a Firebase or Supabase function to obscure your pk.* token from network traffic inspection. For lighter use with a URL-scoped public token (set allowed URLs in Mapbox account token settings), direct calls from the app are the accepted pattern.

```
// Mapbox Geocoding API Call config
// Method: GET
// URL: https://api.mapbox.com/geocoding/v5/mapbox.places/{{searchText}}.json
// Query params:
//   access_token = pk.YOUR_PUBLIC_TOKEN
//   limit        = 5
// Response JSON Paths:
//   $.features[0].place_name     → display text
//   $.features[0].center[0]      → longitude (GeoJSON order!)
//   $.features[0].center[1]      → latitude

// Mapbox Directions API Call config  
// Method: GET
// URL: https://api.mapbox.com/directions/v5/mapbox/driving/{{originLng}},{{originLat}};{{destLng}},{{destLat}}
// Query params:
//   access_token = pk.YOUR_PUBLIC_TOKEN
//   geometries   = geojson
//   overview     = full
// Response JSON Paths:
//   $.routes[0].duration              → travel time in seconds
//   $.routes[0].distance              → distance in meters
//   $.routes[0].geometry.coordinates  → array of [lng,lat] for route line
```

**Expected result:** MapboxGeocode and MapboxDirections API Calls are configured in FlutterFlow and return correct results when tested with sample locations.

### 6. Test on a real device and address the sk.* build token

The Mapbox Custom Widget requires native SDK compilation and will only render in Run mode (FlutterFlow's full-screen browser preview) or on a real device build — the canvas editor shows a grey placeholder. Use Run mode first to verify the widget loads, the style URL renders the correct map appearance, and the Geocoding API Calls work as expected.

If the map fails to render in Run mode with a message like 'Mapbox token invalid' or 'Failed to initialize map', check that you replaced 'pk.YOUR_PUBLIC_TOKEN_HERE' in the Custom Widget Dart code with your actual pk.* token string. FlutterFlow's Run mode does execute Dart custom widget code, so token errors will surface there.

For a production device build (APK or IPA), you need the sk.* download token configured in the native build environment. If you are using FlutterFlow's direct build/deploy feature, you may need to download the Flutter project code from FlutterFlow (via the Download Code or GitHub Export option) and build it locally or in a CI/CD pipeline. Before running flutter build, add the sk.* token to ~/.netrc (for iOS pod install) and ~/.gradle/gradle.properties (for Android). Without this step, the build will fail when Flutter tries to download the Mapbox native SDK binary from Mapbox's private repository.

If managing the native build setup feels like too much overhead for your project, RapidDev's team handles FlutterFlow + Mapbox integrations including native build configuration weekly — you can book a free scoping call at rapidevelopers.com/contact to get started faster.

**Expected result:** The Mapbox map renders in Run mode with the correct custom style, geocoding search pans the map correctly, and you have a documented plan for configuring the sk.* token in your native build environment.

## Best practices

- Use two separate Mapbox tokens: a public pk.* for in-app runtime use (safe to embed in Dart code) and a secret sk.* with DOWNLOADS:READ scope only for the native SDK build download
- Scope your public pk.* token with URL restrictions in Mapbox account settings to limit which domains and apps can use it — this reduces the impact if the token is discovered in network traffic inspection
- Design your map style in Mapbox Studio and pass the mapbox://styles/ URL as a Custom Widget parameter — this lets you update the visual design by republishing the style without releasing a new app version
- Verify your Custom Widget renders in FlutterFlow Run mode before setting up the full native device build — Run mode surfaces token and style URL errors quickly
- Test the Mapbox Custom Widget on both Android and iOS real devices — the native SDK can behave differently across platforms, especially around initial map load and camera animation
- Keep the mapbox_maps_flutter package version pinned in FlutterFlow Custom Code dependencies — auto-updating a native package mid-project can break builds unexpectedly
- For heavy Directions or Geocoding API usage, proxy calls through a Firebase or Supabase function to protect your pk.* token from network inspection and to enable server-side caching
- Monitor your Mapbox usage in the account dashboard — the free tier (50,000 map loads/month) resets monthly and usage counts can grow quickly in active user testing periods

## Use cases

### Branded property map for a real estate app

A premium real estate app uses a custom Mapbox Studio style — muted colors, no business labels, subtle road network — to make their property pins stand out on a clean background. The Custom Widget loads the mapbox://styles/ URL from Mapbox Studio and renders property pins from a Supabase database, giving the app a distinctive visual identity that generic Google Maps cannot match.

Prompt example:

```
Build a FlutterFlow map screen using a Mapbox Custom Widget with a custom dark style from Mapbox Studio that shows property location pins from a Supabase table.
```

### Food delivery tracking with turn-by-turn routing

A restaurant delivery app shows the customer a live map of the driver's location using a Mapbox Custom Widget, with a route overlay drawn using the Mapbox Directions API. The app polls driver coordinates from a Realtime database and updates the map markers in real-time, while the route line updates as the driver progresses.

Prompt example:

```
Create a FlutterFlow screen with a Mapbox map widget that shows a driver pin and draws a route from the restaurant to the delivery address using the Mapbox Directions API.
```

### Outdoor adventure app with terrain map style

A hiking and trail discovery app uses Mapbox's Outdoors style (showing elevation, trails, and terrain contours) as the base layer. Users can search for trail names using the Mapbox Geocoding API Call, and the map zooms to the trail location. Saved trails from Firestore are shown as route overlays on the Mapbox terrain base style.

Prompt example:

```
Add a Mapbox Custom Widget to a FlutterFlow trails app using the Mapbox Outdoors style, with a search bar that geocodes trail names and centers the map on results.
```

## Troubleshooting

### Mapbox map shows a blank white area or 'Token is not authorized' error in Run mode

Cause: The public pk.* token in the Custom Widget Dart code is either incorrect, missing, or has URL restrictions set in Mapbox account settings that block the current rendering context.

Solution: Open your Custom Widget code in FlutterFlow and verify that MapboxOptions.setAccessToken() is called with your full pk.* token string (not a placeholder). Log into your Mapbox account at account.mapbox.com → Tokens and check if the token has URL restrictions that would block Flutter's rendering request. For testing, temporarily remove URL restrictions on the token to confirm the token itself is valid.

### Flutter build fails with 'Could not download mapbox-android-sdk' or CocoaPods install fails on iOS

Cause: The sk.* download token with DOWNLOADS:READ scope is missing from the native build configuration. The Mapbox SDK binary is hosted on a private Mapbox repository that requires authentication.

Solution: Add the sk.* token to your build environment before running the Flutter build. For Android, add MAPBOX_DOWNLOADS_TOKEN=sk.eyJ1... to ~/.gradle/gradle.properties. For iOS, add the token to ~/.netrc in the format shown in Step 2. These are one-time machine-level configuration steps. If you are building in CI/CD, add the token as a protected environment variable and inject it into the build configuration at runtime.

### Mapbox Geocoding returns coordinates in the wrong location (swapped lat/lng)

Cause: Mapbox Geocoding returns coordinates in GeoJSON format as [longitude, latitude] — the reverse of the conventional (latitude, longitude) order. Using center[0] as latitude and center[1] as longitude places pins on the wrong side of the world.

Solution: In your API Call action flow, extract $.features[0].center[0] and assign it to your longitude Page State variable, and extract $.features[0].center[1] and assign it to your latitude Page State variable. This reversal from the GeoJSON standard [lng, lat] order to conventional [lat, lng] order is the correct mapping.

### mapbox_maps_flutter causes dependency version conflicts in FlutterFlow Custom Code

Cause: mapbox_maps_flutter bundles native iOS and Android dependencies that may conflict with the Flutter SDK version bundled in your FlutterFlow project, or with other packages already added as dependencies.

Solution: Try the previous minor version of mapbox_maps_flutter in FlutterFlow's Custom Code dependency panel. Remove the current version, add the older version, and wait for FlutterFlow to sync. Check the FlutterFlow community forum or mapbox_maps_flutter's GitHub releases page for known compatibility notes with specific FlutterFlow versions.

## Frequently asked questions

### Do I need to pay for Mapbox to use it in FlutterFlow?

Mapbox has a generous free tier that covers most small to mid-size apps: 50,000 free web map loads per month, 100,000 free Directions API calls, and 50,000 free static image requests. Beyond the free tier, pricing is pay-as-you-go per request. Verify current free tier limits and per-request pricing at mapbox.com/pricing — rates change periodically.

### Can I use a Mapbox custom style I designed in Mapbox Studio in my FlutterFlow app?

Yes — this is the main reason to choose Mapbox over alternatives. Design your style in Mapbox Studio, click Publish, and copy the Style URL in the format mapbox://styles/yourusername/yourstyleid. Pass this URL as the styleUrl parameter to your Mapbox Custom Widget. When you update and republish the style in Studio, the app picks up the changes on next load without any app code changes.

### Will the Mapbox Custom Widget work on both iOS and Android in FlutterFlow?

Yes, mapbox_maps_flutter supports both iOS and Android. However, each platform requires the sk.* download token configured in its respective native build system before the Mapbox SDK binary can be downloaded during compilation — this is a one-time build machine setup. The FlutterFlow canvas preview and Run mode work without native builds, but a full device APK or IPA requires this setup.

### Can I show user location or draw routes on the Mapbox Custom Widget?

Yes, but these features require additional Dart code in the Custom Widget. To show the user's current location, add a location permission request and update the camera to the device's GPS coordinates. To draw a route, call the Mapbox Directions API Call to get a GeoJSON LineString of coordinates, and add a PolylineAnnotation to the map's annotation manager. These additions are best handled by extending the Custom Widget's Dart code rather than trying to express them purely through FlutterFlow action flows.

### What is the difference between the Mapbox pk.* token and the sk.* token?

The pk.* (public) token is a runtime credential that your Flutter app uses to authenticate API calls to Mapbox tile servers, Geocoding, and Directions. It is safe to embed in app code because Mapbox applies public-scope restrictions and you can URL-restrict it. The sk.* (secret) download token with DOWNLOADS:READ scope is a build-time credential used only during Flutter native compilation to download the Mapbox SDK binary from Mapbox's private Maven and CocoaPods repositories. The sk.* token should never be in your app's runtime code or API call headers.

---

Source: https://www.rapidevelopers.com/flutterflow-integrations/mapbox
© RapidDev — https://www.rapidevelopers.com/flutterflow-integrations/mapbox
