This is a guest post from Clinton Forster - a passionate full stack developer from Down Under where his app (Kuratour) recently won the 2025 Innovation Award in the Adventure Tourism Awards ceremony. He first landed on our radar when he submitted Kuratour to the 2025 Expo App Awards.
...
Travel should feel like discovery, not logistics. But for many travelers, the best stories are hidden behind expensive roaming fees, spotty reception, or rigid tour group schedules. Kuratour was built to change that, turning your phone into a personal, location-aware tour guide that works everywhere - even at the edge of the world.
The vision for Kuratour
Kuratour is a multilingual, GPS-powered audio tour app built entirely with Expo. It delivers immersive walking and driving experiences through real-time location triggers, offline maps, and AI-generated routes. Today, Kuratour powers not just our own platform but a suite of white-labeled apps for tour operators across Australia and beyond.
In this post, we’ll dive into how we leveraged the Expo SDK to solve the "Offline-First" challenge and how we built a modern audio engine using the new expo-audio library.
The Expo foundation: modern React Native at scale
Kuratour is built entirely with the Expo SDK on the new architecture, using both first-party modules and community packages to deliver a native-quality experience.
Core modules:
expo-locationfor real-time GPS tracking and region-based triggersexpo-file-systemandexpo-sqlitefor offline data caching and media storageexpo-audiofor smooth multilingual playbackexpo-videofor a descriptive introductory multilingual tutorialexpo-splash-screenfor a polished startup experienceexpo-apple-authenticationfor seamless login on iOSexpo-applicationfor checking the app version to advise users of updates and making sure offline content is up to date@rnmapbox/mapsfor interactive, offline-enabled maps
Building an offline-first experience
For Kuratour, "Offline-First" isn't a feature - it's the core requirement. Travelers often lose reception in remote areas or turn off data to avoid roaming fees. To solve this:
- Map tiles, images, and audio are downloaded ahead of time using
expo-file-system. - Metadata and visited locations are stored locally with
expo-sqlite. - The app detects connectivity and switches automatically between online and offline modes.
- Real-time GPS triggers from
expo-locationensure narration starts at exactly the right moment.
Step 1: Managing structured data with SQLite
We use expo-sqlite to track downloaded tours, user progress, and localized settings. Below is a simplified version of our DatabaseService. We use a versioning system to handle schema migrations - crucial when you're adding features like "Observed Directions" to an existing user base.
Step 2: Orchestrating asset downloads
When a user taps "Download," we have to sync multiple resources: Mapbox tiles, MP3 audio files, and high-res images. We use expo-file-system to mirror our remote directory structure locally.
Step 3: Integrating with the UI
In the TourDownload component, we wrap these calls in a sequential process. First, we fetch the map directions, then we download the main imagery, and finally, we loop through every location in the tour to fetch its specific audio and background tracks. Once complete, we save the local file URIs back into SQLite so the app can run entirely without a network connection.
Step 4: Smart Switching with Custom Hooks
Once the data is saved locally, the app needs to know which source to prioritize. We use a custom hook, useOfflineDetector, which leverages useFocusEffect from React Navigation. This ensures that every time a user navigates to a tour page, we check the local SQLite database first.
Handling data integrity on iOS updates
A common pitfall when building offline-first apps on iOS is the behavior of the Documents directory during app upgrades. While your SQLite database persists across updates, the files stored via expo-file-system in the documents directory can sometimes be purged or orphaned if the internal paths shift during a major version upgrade.
To prevent users from opening a "downloaded" tour only to find missing audio files, we implemented a Content Validation Bridge.
Step 1: Detecting the Update
We use expo-application to compare the current running version against the lastCheckedVersion stored in local storage. If they don't match, we trigger a validation sweep.
Step 2: Validating the Filesystem
The recheckDownloadedContent function iterates through every tour marked as "offline" in SQLite and pings the filesystem to ensure the assets actually exist. If even one file is missing (like the main tour image or the first audio stop), we trigger a background re-download.
Powering Discovery with expo-location
Kuratour’s magic lies in its "Hands-Free" mode. We want travelers to keep their phones in their pockets and simply listen as stories trigger automatically based on their coordinates. To achieve this, we built a custom useLocation hook that manages permissions and sets up a high-accuracy background subscription.
Implementing the Location Watcher
By using Location.watchPositionAsync, we can update the app's state every few seconds or every time the user moves as little as one meter. This precision is vital for walking tours in dense city centers.
Orchestrating Layered Sound with expo-audio
The "Kuratour experience" isn't just about reading text; it's about atmosphere. We use the modern expo-audio library to create a cinematic feel by layering location-based narration over a subtle ambient background track.
Unlike older audio implementations, expo-audio allows us to create multiple player instances: one for the story and one for the ambiance, while maintaining tight control over their volumes and sync.
Below is a simple example of using expo-audio
AI-powered walking tour generation
One of Kuratour’s funnest features is its AI-assisted tour creation. Users can input any city name to generate a mapped route, commentary script, and audio narration.
- AI-generated text is converted into speech in multiple languages, and expo-audio is used for playback.
- Tours are stored as structured data and become instantly available for offline playback.
- The system supports 14 languages with male and female voice options.
Monitoring performance and stability
Kuratour uses @sentry/react-native to track errors and monitor performance in real time. Sentry dashboards help the team identify and fix device-specific issues quickly.
Scaling with tour operators
Kuratour’s technology now powers white-labeled apps for tour operators around the world, including:
Operators can access a custom CMS to manage tours, upload media, and publish new multilingual content in minutes, with no technical expertise required.
Leveraging Expo’s dynamic app.config.js and Expo's Services, we built a white-labeling system that allows us to generate a custom app for any operator in minutes
Step 1: The Operator Switch
We use a single environment variable to define which "flavor" of the app we are building.
Step 2: Automated Configuration Generation
Instead of maintaining dozens of static app.json files, we use a generate-config.js script. This script reads our environment variables and maps them to a centralized "Master Map" of project IDs, splash screen colors, and store URLs. It then programmatically writes the app.config.js and updates eas.json.
Step 3: Dynamic branding with a theme engine
Once the generate-config.js script sets the operatorName at the build level, we use a centralized theme.ts file to drive the look and feel of the entire application. By mapping the operator name to a specific configuration object, we can swap out everything from primary brand colors to specific category icons (like "sightseeing" vs. "accommodation") without touching a single component.
The benefits of this approach
- Single Codebase, Infinite Flavors: We maintain one set of high-quality components. If we improve the audio player or the map view, every white-label partner gets that upgrade instantly.
- Asset Bundling: Since the logos are
require()'d based on the build config, only the assets relevant to that specific operator are bundled into the final binary. - Hybrid Data Strategy: While the visual identity is baked in at build time for speed and offline reliability, the tour content itself—scripts, routes, and coordinates—is fetched from our PostgreSQL database via a Go API. This allows us to update tour details in real-time without requiring a new app store submission.
What’s next?
We plan to expand Kuratour’s Walking and Driving Tours across the world. And we are going to add “My Tour Experience” for tour operators, which will allow them to ditch WhatsApp and manage tours and communication in their own custom app and backend.
We are also thinking of adding a portal for travel agents so they can offer Kuratour to their clients via commissionable sales.
Conclusion
Kuratour is a testament to what is possible when you combine Expo’s modern development stack, Expo’s production-grade infrastructure, and AI-driven personalization. By prioritizing an offline-first architecture and a layered audio engine, we’ve built more than just a travel app; we’ve created a robust platform for location-aware storytelling that scales across 14 languages and dozens of white-label partners.
For developers, this project should re-emphasize that Expo is the platform for building powerful applications. With the new expo-audio module, high-performance expo-location tracking, and the reliability of SQLite, you can build complex, media-rich applications that thrive in the most challenging real-world environments.
Experience Kuratour yourself
Whether you are a developer looking for inspiration or a traveler ready for your next adventure, we invite you to see the tech in action. Explore over 100 destinations with GPS-triggered stories, offline maps, and AI-generated routes tailored just for you.


