OpenMeal is an open-source, privacy-focused mobile nutrition tracker built with React Native and Expo. It leverages on-device machine learning and Google's Gemini API to provide users with detailed nutritional analysis from photos of their meals. All user data is stored locally, ensuring complete privacy.
This README provides a technical overview of the OpenMeal project, intended for developers and contributors.
You can view the project website at https://maximilianromer.github.io/OpenMeal/.
- Technical Stack
- Project Architecture
- Core Functionality & Implementation
- Getting Started
- Acknowledgements
- Framework: React Native with Expo
- Language: TypeScript
- State Management: React Context API & Hooks
- Navigation: Expo Router
- AI: Google Gemini API for multimodal meal analysis
- Health Data: Android Health Connect via
react-native-health-connect - Data Storage: Local file system via
expo-file-systemandexpo-secure-store - Linting: ESLint
- Testing: Jest for unit tests.
The application is architected with a service-oriented approach, separating concerns into distinct modules. This design enhances maintainability, scalability, and testability.
app/: Contains the application's screens and navigation logic, powered by Expo Router. The file-based routing system defines the app's URL structure and screen hierarchy.components/: A library of reusable UI components. This includes everything from basic elements like themed text and views to complex modals and charts.services/: The core of the application's business logic. Each service encapsulates a specific domain of functionality (e.g.,GeminiService,HealthConnectService,FileSystemStorageService). This separation allows for easier management and testing of individual features.hooks/: Custom React hooks that provide reusable logic to components, such asuseColorSchemefor theme management.constants/: Application-wide constants, including colors, fonts, and other configuration values.types/: TypeScript type definitions, including custom declarations for libraries likereact-native-health-connect.
The GeminiService.ts is responsible for interacting with the Google Gemini API.
- Multimodal Input: It takes a base64-encoded image of a meal and a text prompt as input.
- API Interaction: It constructs a request to the Gemini API endpoint, sending the image and prompt for analysis.
- Structured Output: The service is configured to expect a structured JSON response from the API, which includes detailed nutritional information (calories, protein, carbs, fats), a meal name, and a confidence score. This is achieved by defining a
responseSchemain thegenerationConfig.
Integration with Android's Health Connect is managed by HealthConnectService.ts.
- Data Synchronization: It provides methods to write meal data (total calories, protein, carbs, fat) to Health Connect, associating it with the correct time and meal type.
- Permissions: The service handles the process of checking for and requesting user permissions to read and write nutritional data.
All user data, including meal history, user profile, and daily goals, is stored locally on the user's device using expo-file-system.
FileSystemStorageService.ts: This service provides a simple key-value store abstraction over the file system. It handles serialization and deserialization of JSON data, making it easy to store and retrieve complex objects.- Data Models: Services like
UserProfileService.tsandDailyGoalsService.tsuse the storage service to persist their respective data models. - Privacy by Design: By storing data locally, the app ensures that sensitive user information never leaves the device, providing a high level of privacy.
The application utilizes React's built-in Context API and custom hooks for state management.
- Decentralized State: Instead of a single global store, state is managed by multiple contexts, each responsible for a specific slice of the application's state (e.g.,
OnboardingContext,MealContext). - Service-Oriented Contexts: Context providers often wrap the logic from the
servicesdirectory, providing a clean API for components to interact with the application's business logic. For example, theMealContextwill use theAnalysisProcessorandFileSystemStorageServiceto manage meal data.
- Node.js and NPM (LTS version recommended)
- Expo Go app on your Android device for testing
- A Gemini API key, which can be used for free with all currently released Gemini models at high rate limits.
-
Clone the repository:
git clone [https://github.com/maximilianromer/OpenMeal](https://github.com/maximilianromer/OpenMeal.git) cd OpenMeal -
Install dependencies:
npm install
- Start the development server:
npx expo start
I built this app in about a month of summer break, with no prior experience in mobile app development or React Native. A few tools were instrumental to my success:
- Cursor: an excellent AI code editor, with a powerful agent that wrote 99% of the app's code
- Anthropic's Claude 4 models: By far the most adept at code writing and tool calling for agentic editing. I used these for 99% of actual code edits and implementation work.
- Google Gemini: a plethora of free tools that made this project possible
- API free tier: opened the possibility of building open tools that rely upon LLMs like this, with no cost. I have probably used hundreds of dollars of inference off this; it is a true act of altruism
- Gemini 2.5 Pro model: Fantastic long-context analysis of the codebase, which helped me plan features and detect issues.