PlantSnap AI
A React Native mobile app built as a Replit Bounty contract — converting an existing web app into a cross-platform iOS and Android experience. Users snap or upload a photo of any plant to identify it, monitor its health, check repotting needs, determine watering requirements, and generate a schedule that syncs to their device calendar. Delivered in full; never deployed due to the client going silent during App Store submission.
Project Overview
PlantSnap AI started as a Replit Bounties contract — a UK-based client posted a bounty to convert their existing web app into a native mobile application. The scope expanded into a full plant care companion: identification as the entry point, with health monitoring, repotting checks, watering needs assessment, and calendar-synced schedules built on top.
The app targets both iOS and Android from a single React Native codebase and connects to a custom backend. The client-side architecture is intentionally decoupled behind a configurable API layer so it can work with any compatible backend.
The full build was delivered. Payment was never received from Replit. During the deployment phase — specifically the App Store submission process — the client went silent and the engagement ended. The app was never published. The source code is publicly available on GitHub.
Core Features
- Plant identification — snap a photo with the in-app camera or select one from the camera roll; the app identifies the plant and returns its name, species, and care profile
- Health monitoring — track the ongoing health status of each saved plant, with condition assessments based on visual and care history data
- Repotting check — assess whether a plant needs to be repotted based on its current data and care profile
- Watering needs — determine how much and how often a plant should be watered, factoring in species requirements and local weather conditions
- Watering schedule + calendar sync — generate a personalised watering schedule and add it directly to the user's device calendar so reminders surface at the right time
- Plant collection — save and organise identified plants, with per-plant detail screens for care instructions, health history, and watering logs
Tech Stack
- React Native + Expo — cross-platform iOS and Android from a single codebase; Expo managed workflow for simplified build and OTA updates
- Expo Router — file-system-based navigation with tab and stack layouts, matching the app's screen hierarchy
- TypeScript — strict typing across the full codebase including API types, store shapes, and component props
- Zustand — lightweight global state for auth session, plant collection, and UI preferences
- TanStack Query — server-state management, caching, and background refetching for plant and weather data
- Expo Camera + Image Picker — in-app camera for live capture; image picker for selecting from the camera roll
- AsyncStorage — local persistence for collection data and user preferences
- JWT authentication — user accounts with secure token-based auth
- Weather API — local weather data surfaced contextually alongside watering recommendations
- Light & dark theme — full theme switching with user preference persisted locally
The Problem
The client had a working web app and wanted it converted into a native mobile experience available on iOS and Android. They posted the contract on Replit Bounties, which is where I picked it up.
Beyond the web-to-mobile conversion, the brief called for extending the feature set — plant identification was the base, but the client wanted the app to serve as an ongoing care companion: health monitoring, repotting signals, watering guidance, and a schedule system that actually integrated with the user's calendar rather than relying on in-app notifications alone.
Camera-First Identification Flow
The core entry point is the camera screen — always one tap away from the home tab. Users can capture a photo live or pull one from their camera roll. The image is sent to the backend for identification, and the result screen returns the plant's name, species, and a full care profile. Identified plants can be saved to the collection with a single tap.
Per-Plant Health & Care Tracking
Each plant in the collection has a dedicated detail screen that acts as its ongoing care record:
- Health status — assessed and updated over time, with indicators for common issues like overwatering, underwatering, and light exposure
- Repotting assessment — the app evaluates whether the plant is likely root-bound based on its profile and signals when repotting is recommended
- Watering needs — calculated from the plant's species requirements and cross-referenced against local weather data so recommendations adapt to actual conditions, not just fixed schedules
- Care instructions — detailed guidance per plant including light, water, soil, and humidity requirements
Watering Schedules & Calendar Sync
A generated watering schedule is the app's most practical feature — it takes the watering needs assessment and turns it into a concrete, actionable plan. Users can review the recommended schedule and with one tap add it to their device's native calendar. Reminders appear automatically at the right time, in the same place users already manage their day — no custom notification system needed.
Architecture Decisions
- Expo Router over React Navigation: File-based routing maps naturally to the app's screen structure (tabs + modal-style plant detail), and the Expo ecosystem integration reduces build complexity for a managed-workflow project
- Zustand over Context API: The plant collection and auth state needed to be accessed across unrelated parts of the tree without prop drilling; Zustand gave clean, minimal store definitions without the boilerplate of Redux
- TanStack Query for server state: Plant data, weather data, and identification results are all server-fetched with different stale times; TanStack Query's per-query caching and background refetch handled this without manual cache management
- Decoupled backend: The API layer is abstracted behind a configurable base URL, meaning the client app could connect to the custom backend or any compatible alternative without code changes
Outcomes
- Contract delivered in full — all five care features (identification, health monitoring, repotting check, watering needs, and calendar-synced schedules) were built and functional
- Cross-platform from one codebase — runs on both iOS and Android via Expo without platform-specific branches
- Not published to the stores — the engagement was closed after delivery; the app was not submitted to the App Store or Google Play Store
- Code is publicly available — the full client codebase lives at github.com/thekiwidev/plantsnap.ai and is open to revisit, fork, or extend
Key Learnings
- Validate client commitment before delivering: The project was completed in full and handed over, but payment was never received through Replit Bounties. Securing a deposit or escrow milestone before beginning work would have protected against this outcome.
- App Store submission is a client responsibility too: The client went silent when the App Store submission process required personal and business information they weren't comfortable providing. This is a legitimate blocker that can't be resolved on the developer's side — it's worth discussing App Store requirements explicitly before a project starts, especially on mobile contracts.
- Bounty platforms shift leverage to the client: On platforms like Replit Bounties, payment is often tied to the client approving delivery. Without a separate agreement, there's little recourse if a client disappears. Independent contracts with staged payments are safer for projects of meaningful scope.