Skip to main content

Getting Started

Complete guide for integrating Barikoi Maps into an existing React Native (Expo) application.

Prerequisites

  • Node.js 18+
  • Expo SDK 53+
  • An existing Expo project
  • Android Studio (for Android) or Xcode (for iOS, macOS only)
  • Barikoi API key

Installation

1. Get your API key

  1. Go to developer.barikoi.com and create an account.
  2. Navigate to Dashboard → Account → API Key.
  3. Copy your API key.

2. Install dependencies

npm install @maplibre/maplibre-react-native expo-location expo-constants expo-dev-client barikoiapis

If you are using TypeScript, also install the GeoJSON type definitions:

npm install -D @types/geojson
Why expo-dev-client?

Barikoi Maps uses native modules that cannot run in Expo Go. expo-dev-client lets you create a development build that supports native code.

3. Update app.json

Add the following keys inside your existing expo object. Do not replace your entire app.json — merge these in:

{
"expo": {
"plugins": [
"expo-router",
"expo-dev-client",
"expo-location",
"@maplibre/maplibre-react-native"
],
"extra": {
"barikoiApiKey": "YOUR_API_KEY_HERE"
}
}
}
note

Both @maplibre/maplibre-react-native and expo-location plugin entries are required — without them the native map module and location permissions will not register correctly.

New Architecture

If you want to enable the New Architecture, add "newArchEnabled": true to your expo object. Be aware this may affect other native modules in your project. Test thoroughly before enabling it in an existing project.

4. Create the map utilities file

Create utils/mapUtils.ts in your project. Adjust the import path in your screen files based on where you place this file.

// utils/mapUtils.ts
import Constants from 'expo-constants';
import { useEffect, useState } from 'react';
import { createBarikoiClient } from 'barikoiapis';

const apiKey = Constants.expoConfig?.extra?.barikoiApiKey;

// Barikoi API client for search, geocoding, routing
export const barikoiClient = createBarikoiClient({ apiKey });

export const fetchBarikoiMapStyle = async (apiKey: string): Promise<any> => {
const response = await fetch(
`https://map.barikoi.com/styles/barikoi-light-v2/style.json?key=${apiKey}`
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
};

export const useBarikoiMapStyle = () => {
const [styleJson, setStyleJson] = useState<any>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
const loadStyle = async () => {
try {
setLoading(true);
setError(null);
const style = await fetchBarikoiMapStyle(apiKey);
setStyleJson(style);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load map style');
} finally {
setLoading(false);
}
};
loadStyle();
}, [apiKey]);

return { styleJson, loading, error };
};

// Default coordinates for Bangladesh cities [longitude, latitude]
export const DEFAULT_COORDINATES = {
DHAKA: [90.364159, 23.823724] as [number, number],
CHITTAGONG: [91.8317, 22.3569] as [number, number],
SYLHET: [91.8833, 24.8949] as [number, number],
RAJSHAHI: [88.6044, 24.3636] as [number, number],
};

// Default camera settings
export const DEFAULT_CAMERA_SETTINGS = {
centerCoordinate: DEFAULT_COORDINATES.DHAKA,
zoomLevel: 16,
animationDuration: 1000,
animationMode: 'linearTo' as const,
};

// Shared map style presets
export const MAP_STYLES = {
line: {
lineColor: '#2e8555',
lineWidth: 3,
lineCap: 'round' as const,
lineJoin: 'round' as const,
},
polygon: {
fillColor: 'rgba(46, 133, 85, 0.5)',
fillOutlineColor: '#2e8555',
},
marker: {
anchorDefault: { x: 0.5, y: 1.0 },
iconSize: { width: 40, height: 40 },
},
};

// Barikoi brand colors
export const BARIKOI_COLORS = {
primary: '#2e8555',
primaryLight: 'rgba(46, 133, 85, 0.5)',
secondary: '#e74c3c',
background: '#f5f5f5',
text: '#333',
white: '#ffffff',
};

// Validate coordinates within Bangladesh bounds
export const isWithinBangladeshBounds = (coordinates: [number, number]): boolean => {
const [lng, lat] = coordinates;
return lat >= 20.3 && lat <= 26.8 && lng >= 88.0 && lng <= 92.8;
};

// Haversine distance between two coordinates (km)
export const calculateDistance = (
coord1: [number, number],
coord2: [number, number],
): number => {
const [lng1, lat1] = coord1;
const [lng2, lat2] = coord2;
const R = 6371;
const dLat = (lat2 - lat1) * Math.PI / 180;
const dLng = (lng2 - lng1) * Math.PI / 180;
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLng / 2) * Math.sin(dLng / 2);
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
};

// Generate circle polygon coordinates
export const createCirclePolygon = (
center: [number, number],
radiusInKm: number,
points: number = 64,
): [number, number][] => {
const coords: [number, number][] = [];
const [lng, lat] = center;
for (let i = 0; i < points; i++) {
const angle = (i * 2 * Math.PI) / points;
const dx = (Math.cos(angle) * radiusInKm) / 111.32;
const dy = (Math.sin(angle) * radiusInKm) / (111.32 * Math.cos(lat * (Math.PI / 180)));
coords.push([lng + dx, lat + dy]);
}
coords.push(coords[0]);
return coords;
};

5. Build and run

Rebuild required

Any time you change the plugins array in app.json, you must create a new native build. A Metro reload or hot reload is not enough.

# Android emulator or connected device
npx expo run:android

# iOS simulator (macOS only)
npx expo run:ios

# Physical device via EAS
eas build --profile development --platform android
npx expo start

Coordinate convention

All coordinates throughout this guide use [longitude, latitude] order — the GeoJSON standard:

const dhaka: [number, number] = [90.364159, 23.823724]; // ✅ [lng, lat]
const wrong = [23.823724, 90.364159]; // ❌ [lat, lng]

Simple map

Render a basic map centered on Dhaka with a single marker. This is the three-step pattern used in every guide: load the style with useBarikoiMapStyle(), handle loading/error states, then render MapView.

Marker asset

The example below uses a <View> as the marker so it works out of the box without any image assets. Replace it with your own <Image> when ready.

import { Camera, MapView, MarkerView } from '@maplibre/maplibre-react-native';
import React from 'react';
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
import { BARIKOI_COLORS, DEFAULT_CAMERA_SETTINGS, useBarikoiMapStyle } from '../utils/mapUtils';

export default function SimpleMapScreen() {
const { styleJson, loading, error } = useBarikoiMapStyle();

if (loading) {
return (
<View style={styles.centered}>
<ActivityIndicator size="large" color={BARIKOI_COLORS.primary} />
<Text style={styles.statusText}>Loading map...</Text>
</View>
);
}

if (error) {
return (
<View style={styles.centered}>
<Text style={styles.errorTitle}>Map loading error</Text>
<Text style={styles.errorText}>{error}</Text>
</View>
);
}

return (
<View style={styles.container}>
<MapView
style={styles.map}
attributionEnabled={false}
zoomEnabled
compassEnabled
mapStyle={styleJson}
>
<Camera
centerCoordinate={DEFAULT_CAMERA_SETTINGS.centerCoordinate}
zoomLevel={DEFAULT_CAMERA_SETTINGS.zoomLevel}
animationDuration={DEFAULT_CAMERA_SETTINGS.animationDuration}
animationMode={DEFAULT_CAMERA_SETTINGS.animationMode}
/>
<MarkerView
coordinate={DEFAULT_CAMERA_SETTINGS.centerCoordinate}
anchor={{ x: 0.5, y: 1.0 }}
>
<View style={styles.marker} />
</MarkerView>
</MapView>
</View>
);
}

const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: 'white' },
map: { flex: 1 },
centered: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: BARIKOI_COLORS.background },
statusText: { marginTop: 16, fontSize: 16, color: BARIKOI_COLORS.primary, fontWeight: '500' },
errorTitle: { fontSize: 20, fontWeight: 'bold', color: BARIKOI_COLORS.secondary, marginBottom: 8 },
errorText: { fontSize: 16, color: BARIKOI_COLORS.text, textAlign: 'center' },
marker: { width: 16, height: 16, borderRadius: 8, backgroundColor: BARIKOI_COLORS.primary },
});

Utilities reference

All shared utilities live in utils/mapUtils.ts:

ExportTypeDescription
barikoiClientObjectBarikoi API client for search, geocoding, routing
useBarikoiMapStyle()HookReturns { styleJson, loading, error }
fetchBarikoiMapStyle(apiKey)FunctionFetches style JSON from Barikoi
DEFAULT_COORDINATESObjectPredefined city coords: DHAKA, CHITTAGONG, SYLHET, RAJSHAHI
DEFAULT_CAMERA_SETTINGSObjectDefault center (Dhaka), zoom (16), animation settings
MAP_STYLESObjectStyle presets: line, polygon, marker
BARIKOI_COLORSObjectBrand colors: primary, secondary, background, text, white
isWithinBangladeshBounds(coord)FunctionReturns true if [lng, lat] is within Bangladesh bounds
calculateDistance(c1, c2)FunctionHaversine distance in km between two coordinates
createCirclePolygon(center, radiusKm, points?)FunctionGenerates circle polygon coordinates

Barikoi API client methods

MethodParametersReturns
barikoiClient.autocomplete({ q })Search queryresult.data?.places — array of matching places
barikoiClient.reverseGeocode({ latitude, longitude })Coordinatesresult.data?.place — nearest place object
barikoiClient.nearby({ latitude, longitude, radius, limit })Center + radiusresult.data?.places — array sorted by distance
barikoiClient.routeOverview({ coordinates, geometries })Route coordsresult.data?.routes — array of route objects

Next steps

  • Markers — single, multiple, interactive, and draggable markers
  • Current location — track and display the user's position
  • Shapes — draw lines, polygons, and circles on the map
  • Search & Geocoding — integrate Barikoi's search APIs with the map
  • Routing — fetch and display routes between two points
  • Troubleshooting — common errors and fixes