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
- Go to developer.barikoi.com and create an account.
- Navigate to Dashboard → Account → API Key.
- 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
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"
}
}
}
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.
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
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.
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:
| Export | Type | Description |
|---|---|---|
barikoiClient | Object | Barikoi API client for search, geocoding, routing |
useBarikoiMapStyle() | Hook | Returns { styleJson, loading, error } |
fetchBarikoiMapStyle(apiKey) | Function | Fetches style JSON from Barikoi |
DEFAULT_COORDINATES | Object | Predefined city coords: DHAKA, CHITTAGONG, SYLHET, RAJSHAHI |
DEFAULT_CAMERA_SETTINGS | Object | Default center (Dhaka), zoom (16), animation settings |
MAP_STYLES | Object | Style presets: line, polygon, marker |
BARIKOI_COLORS | Object | Brand colors: primary, secondary, background, text, white |
isWithinBangladeshBounds(coord) | Function | Returns true if [lng, lat] is within Bangladesh bounds |
calculateDistance(c1, c2) | Function | Haversine distance in km between two coordinates |
createCirclePolygon(center, radiusKm, points?) | Function | Generates circle polygon coordinates |
Barikoi API client methods
| Method | Parameters | Returns |
|---|---|---|
barikoiClient.autocomplete({ q }) | Search query | result.data?.places — array of matching places |
barikoiClient.reverseGeocode({ latitude, longitude }) | Coordinates | result.data?.place — nearest place object |
barikoiClient.nearby({ latitude, longitude, radius, limit }) | Center + radius | result.data?.places — array sorted by distance |
barikoiClient.routeOverview({ coordinates, geometries }) | Route coords | result.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