Capture GPS-tagged street-level photos on iOS and Android, review your sequences, and upload them to Mapilio. OpenStreetMap contributors can use the imagery as a reference to improve the map. This repository contains the mobile app, built with Expo (bare workflow) and React Native.
- Get the published app on the App Store or Google Play.
- Explore imagery in your browser.
- Build the app locally to try the source in this repository.
The source has been public since 7 September 2026. Store listings may contain an earlier version; publishing the source does not mean the next store build has shipped. See the store-release checklist.
Start with the contribution guide and roadmap. The architecture overview explains capture, upload, API clients, state and sign-in, with links to the code. Small fixes, clearer documentation, translations, and reproducible bug reports are welcome. Browse good first issues or help wanted. Those lists may be empty; start a discussion to find a small task before taking on a release blocker.
A star helps others find the project. Choose Watch > Custom > Releases on GitHub for release notifications without following every issue.
- Camera capture — GPS-tagged photos with automatic interval shooting
- Sequence management — Organize, review, and upload photo sequences
- Interactive map — Browse captured imagery on a MapLibre-powered map
- Community — Contributor profiles and a capture leaderboard
- Upload pipeline — In-app upload with progress tracking, pause and retry
- Local capture storage — JPEG files and SQLite metadata retained for later upload
- Localization — 31 languages supported via i18next
- Multi-auth — Email, Google, Apple, Facebook, and OpenStreetMap OAuth
Marketplace and future reward campaigns are roadmap work, not a promise of available paid tasks or prizes. Provider sign-in and capture/upload changes still need the deployment and device checks recorded in ROADMAP.md.
Mapilio is a street-level imagery capture and contribution app for OpenStreetMap mappers and the open mapping community. Its mission is to make it easy to capture geotagged imagery on foot, by bicycle, or in a vehicle, and contribute it to the open mapping ecosystem.
In scope
- Capturing geotagged photos at configurable intervals during a journey
- Reviewing, managing, and uploading captured sequences to the Mapilio platform
- Browsing contributed imagery on a MapLibre-powered map
- Integration with the Mapilio API for storage, processing, and publication
Out of scope
- General-purpose photography or video recording
- Real-time navigation, turn-by-turn directions, or offline map downloads
- Social networking beyond contributor profiles and the community leaderboard
- Server-side image processing — that is handled by the Mapilio backend
If you have an idea that falls outside this scope, please open a Discussion rather than an Issue. Feature requests are evaluated against the capture-and-contribute mission; the project aims to do a few things well rather than many things broadly.
See the public roadmap for release gates, near-term priorities, and longer-term direction. GitHub issues, milestones, and discussions remain the source of truth; the roadmap includes no dates or promises.
| Layer | Library |
|---|---|
| Framework | Expo SDK 57 (Bare Workflow) |
| Runtime | React Native 0.86.2 |
| UI library | React 19.2.3 |
| Navigation | React Navigation v7 |
| State | Redux 5 + Redux-Persist |
| Maps | MapLibre React Native |
| Database | expo-sqlite |
| File system | expo-file-system (adapter: util/fs.js) |
| Camera | expo-camera |
| Location | expo-location |
| Notifications | OneSignal + expo-sensors |
| Monitoring | Sentry |
| Testing | Jest 29 + jest-expo |
| Tool | Version |
|---|---|
| Node.js | >=22.13 <25 |
| npm | 10+ |
| Expo CLI | Project-local CLI via npx expo |
| Xcode | Compatible with the pinned Expo SDK; React Native enforces 16.1+ |
| Android Studio | A version supporting Android Gradle Plugin 8.12 |
| Java | JDK 17 for the Android toolchain |
| CocoaPods | 1.14+ (iOS only) |
macOS + nvm users: Run
nvm usebefore building. The trackedios/.xcode.envresolves Node from your PATH. If Xcode cannot find it, setNODE_BINARYto your selected Node executable in the ignoredios/.xcode.env.local; a system-wide Node symlink is not required.
Use the committed Gradle wrapper (9.3.1), not a separate global Gradle install. The native build requirements come from the locked React Native/Expo packages; the store and physical-device evidence remains in ROADMAP.md.
git clone https://github.com/mapilio/mobile-apps.git
cd mobile-apps
nvm use
npm cicp .env.example .env.developmentOpen .env.development and set your API URLs and public client identifiers
(see Environment Variables below). Do not put server
secrets or signing credentials in the app environment.
npx expo run:iosnpx expo run:android# Install an Expo-compatible package version
npx expo install <package>
# Refresh iOS pods after native dependency changes
npx pod-installThe committed Android and iOS projects contain reviewed Mapilio integrations.
Do not run expo prebuild --clean. When a config plugin must update native
files, use a dedicated branch, run prebuild without --clean, and review every
generated native diff before opening the pull request.
Production builds use release credentials managed outside this repository. The
production EAS profile explicitly uses Expo's remote credential store:
eas build --platform android --profile productionThe tracked android/app/debug.keystore is only for local debug builds. A local
Gradle release build is intentionally not configured to use that key; provide a
secure external signing configuration when building outside EAS.
Copy .env.example to .env.development (local dev) or .env.production (release builds) and provide only non-sensitive public runtime values. Expo embeds every EXPO_PUBLIC_* value in the app bundle, so never put a confidential credential in one of these variables.
| Variable | Description |
|---|---|
EXPO_PUBLIC_SERVICE_URL |
Mapilio REST API base URL |
EXPO_PUBLIC_ROAD_TILE_URL |
Self-hosted road vector-tile URL template |
EXPO_PUBLIC_ROAD_TILE_ID |
Road source-layer ID |
EXPO_PUBLIC_POINT_TILE_URL |
Self-hosted point vector-tile URL template |
EXPO_PUBLIC_POINT_TILE_ID |
Point source-layer ID |
EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID |
Google Sign-In iOS client ID |
EXPO_PUBLIC_GOOGLE_ANDROID_CLIENT_ID |
Google Sign-In Android client ID |
EXPO_PUBLIC_SENTRY_DSN |
Sentry DSN for error reporting |
EXPO_PUBLIC_ONESIGNAL_APP_ID |
OneSignal app ID for push notifications |
See .env.example for the full list. Existing deployments can continue using the
legacy EXPO_PUBLIC_MAPBOX_ROAD_* and EXPO_PUBLIC_MAPBOX_POINT_* names during
migration; new installations should use the neutral tile variables above.
Social sign-in exchanges provider tokens through the backend-first
/api/v1/mobile/auth/social-token endpoint. The mobile bundle contains only
provider client identifiers and platform-SDK values intended for public native
clients. Provider tokens and backend tokens are sent in request bodies; backend
OAuth client secrets must never be configured in the mobile environment.
The mobile source is public. Sensitive-history cleanup, GitHub Support ref cleanup, asset-rights verification, and public-clone checks are complete. The history remediation runbook documents that completed work; it is not a pending publication gate.
Signed App Store and Google Play releases remain separate work. Follow the store and operational release checklist for provider verification, store declarations, signed artifacts, and physical device checks. The legal review packet records preparation, not legal approval. Report vulnerabilities privately using the security policy.
# Interactive watch mode
npm test
# CI (single run, no watch)
npm run test:ci
# With coverage report
npm run test:ci -- --coverageThe test suite covers reducers, helper functions, configuration, and the file-system adapter (more than 250 tests).
mobile-apps/
├── App.js # Root component (providers, global toast shim)
├── index.js # Expo entry point
├── db.js # SQLite initialization
├── config/ # Tile service URLs and source-layer configuration
├── modules/mapilio-storage/ # Android removable-storage discovery (Expo module)
├── resolver/ # Legacy React Native compatibility shim
├── util/
│ ├── fs.js # File-system adapter (expo-file-system wrapper)
│ └── helpers/api/ # API transports, account paths and token exchange
├── store/
│ ├── store.js
│ ├── actionsName.ts
│ ├── actions/
│ └── reducers/ # cameraReducer, generalReducer, loginReducer, …
├── screens/ # Full-screen views (AppCamera, AppMap, Login, …)
├── components/ # Reusable UI components
├── highordercomponents/ # Higher-order components (MapView, …)
├── navigator/ # React Navigation stacks & tabs
├── helper/ # Helpers and side effects (capture, upload, auth, …)
├── docs/ # Architecture, security and release notes
├── hooks/ # Custom React hooks
├── styles/ # Global style constants
├── translations/ # i18n JSON files (31 locales)
├── types/ # TypeScript type definitions
├── __tests__/ # Jest test suites
├── android/ # Android native project
└── ios/ # iOS native project
We welcome bug reports, feature requests, and pull requests. Please read CONTRIBUTING.md before submitting.
The Mapilio Mobile source code is licensed under the Apache License, Version 2.0. Bundled visual assets are not automatically covered by that source-code license: Mapilio-proprietary visual families and their current owner/source evidence are identified in asset-rights-manifest.json, while retained third-party materials are documented in THIRD_PARTY_NOTICES.md.
The repository tracks every Git-tracked file in assets/** in
asset-inventory.json. Family
classification and the current rights-review state are defined in
asset-rights-manifest.json. The current retained
inventory contains 126 records; the manifest records verified redistribution
rights for every retained record.
Maintainers must review an intentional asset change, then run
npm run assets:update, inspect the generated diff, and commit the manifest or
inventory changes together with the asset change. CI runs npm run assets:check
and does not regenerate files. New directories must be added to the manifest
before their assets can be inventoried. npm run assets:check only verifies
repository bookkeeping; it does not replace rights review for future changes.
Removed third-party and unclear-provenance assets are documented in
THIRD_PARTY_NOTICES.md.
Copyright 2024–2026 Mapilio
