NutriTrack AI is a privacy-focused personal nutrition assistant. It uses Google Gemini to analyze food photos or descriptions, tracks your macros against your goals, and stores all your data securely in your own Google Sheets via your Google Drive.
The app is a React SPA served from Cloudflare Workers, with a small Worker backend that handles Google OAuth so you stay signed in across sessions.
Zero cost: Designed to run on free tiers (Cloudflare Workers + Gemini Free Tier + Google Sheets API).
- Smart Food Analysis: Upload a photo 📸 OR describe your meal in text 📝 (e.g., "Chicken rice with extra egg"). Gemini estimates calories, protein, carbs, and fat.
- "What should I eat?": Context-aware suggestions based on your remaining macros, the time of day, and what you've already eaten.
- TDEE Calculator: Automatically calculates your Total Daily Energy Expenditure (Maintenance Calories) based on your profile and activity level.
- Daily Insights: AI-generated advice banner that adapts to your recent eating habits.
- Google Sheets Database: No 3rd party database. Your data lives in a spreadsheet (
NutriTrack AI Data) in your Google Drive. - Calorie Deficit Monitor: Real-time tracking of your daily and all-time calorie deficit.
- Macro Tracking: Progress indicators for Calories, Protein, Carbs, and Fat.
- Weight Trend: Interactive line chart to visualize weight changes over time.
- Timezone Smart: Uses Singapore Time (UTC+8) for consistent daily logging.
- Glassmorphism Design: Backdrop blurs and smooth animations.
- Interactive Charts: 7, 30, and 90-day views for calorie and weight history.
- PWA-Ready: Responsive on mobile and desktop.
https://nutritrack-ai.wby1279501447.workers.dev
Browser (React SPA)
├── Google Sheets / Drive API ── your data lives in your Drive
└── /api/auth/* ── Cloudflare Worker
├── Google OAuth (authorization code flow)
└── KV: refresh token + opaque session
GET /api/auth/loginstarts Google sign-in.GET /api/auth/callbackexchanges the code and stores the refresh token server-side.GET /api/auth/tokenreturns a fresh 1-hour access token to the browser.POST /api/auth/logoutrevokes and deletes the session.
The browser never receives the refresh token — only an HttpOnly, Secure session cookie.
- Node.js (v18 or higher)
- A Google Cloud Project (OAuth + Sheets + Drive APIs)
- A Google Gemini API Key
- A Cloudflare account (free) for deployment
- Go to Google AI Studio.
- Create a free API key.
- Create a project in the Google Cloud Console.
- Enable Google Sheets API and Google Drive API.
- Configure the OAuth consent screen (External).
- Publish the app (Audience → Publish app). This is required: refresh tokens issued by apps in Testing expire after 7 days.
- If you stay in Testing, add each user under Test users (max 100).
- Create an OAuth Client ID → Web application.
- Authorized redirect URI (exact):
https://nutritrack-ai.wby1279501447.workers.dev/api/auth/callbackAddhttp://localhost:8788/api/auth/callbackif you test locally with Wrangler. - The only scope requested is
https://www.googleapis.com/auth/drive.file(per-file access to the spreadsheet the app creates).
- Authorized redirect URI (exact):
- Create a KV namespace (Storage & Databases → KV) and put its ID in
wrangler.jsoncunderkv_namespaceswith bindingSESSIONS. - Build variables:
VITE_API_KEY= your Gemini key. - Runtime variables/secrets (Worker → Settings → Variables and Secrets):
GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRET(Secret)
- Connect the repository via Workers Builds (Workers & Pages → Create → Import a repository):
- Build command:
npm run build - Deploy command:
npx wrangler deploy - Root directory: blank (repository root)
- Build command:
git clone https://github.com/CPLADGRON/nutritrack-ai.git
cd nutritrack-ai
npm installCreate .env for the frontend build:
API_KEY=your_gemini_api_key_hereRun the UI only (no auth endpoints):
npm run devRun the full app (SPA + Worker + local KV):
npm run build
# .dev.vars: GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=...
npx wrangler devRegister http://localhost:8788/api/auth/callback in Google Cloud for local auth.
Production runs on Cloudflare Workers (Workers Builds from this repo). Every push to main builds with npm run build and deploys with npx wrangler deploy.
The legacy GitHub Pages workflow (.github/workflows/deploy.yml) is no longer used; disable or delete it after verifying the Cloudflare deployment.
- Cause: The callback URL doesn't exactly match Google Cloud.
- Fix: Add the exact redirect URI under Authorized redirect URIs — not Authorized JavaScript origins. It must match scheme, host, and path.
- Cause: The app is in Testing and the user isn't a test user.
- Fix: Add their email under Test users, or publish the app.
- Cause: The OAuth app is still in Testing; refresh tokens expire after 7 days.
- Fix: Publish app in Google Auth Platform → Audience.
- Cause:
GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET/SESSIONSare missing in the Worker. - Fix: Add the runtime variables and KV binding, then redeploy.
- Cause:
drive.filedid not cover an operation. - Fix: Add
https://www.googleapis.com/auth/spreadsheetstoSCOPESinfunctions/api/auth/_shared.jsand sign in again.
- Frontend: React 18, TypeScript, Vite
- Styling: Tailwind CSS, Glassmorphism
- Charts: Recharts
- AI: Google Gemini SDK (
@google/genai) - Backend: Cloudflare Workers (Static Assets + Functions-style handlers)
- Auth: Google OAuth 2.0 authorization-code flow, KV sessions
- Storage: Google Sheets API v4 / Drive API v3 (
drive.file)
- Data: Stored in your Google Drive. The app developer has no access to it.
- Auth: The refresh token is stored in Cloudflare KV, keyed by an opaque session ID. The browser only holds a 1-hour access token and an
HttpOnlysession cookie. - AI: Food images/text are sent to Google Gemini for analysis; only the results are saved to your Sheet.
- Note: The Gemini API key is embedded in the client bundle at build time (
VITE_API_KEY), so this deployment is intended for personal use.