Skip to content

Build a Food Tracking App with React Native

This guide wires the three endpoints a food tracker needs (autocomplete suggest, food details, and barcode lookup) into a React Native app. Requests are routed through a small backend proxy so your API key never ships inside the app binary.

Set up a backend proxy

Mobile binaries can be decompiled, so keep the X-API-Key header server-side. A minimal Express proxy forwards search traffic and adds the key:

server.js (Express proxy)
const express = require('express')
const app = express()

const API_BASE = 'https://calorieapiadmin.com/api/v1'

app.get('/api/food-search', async (req, res) => {
  const url = new URL(API_BASE + '/search/suggest')
  url.searchParams.set('q', req.query.q ?? '')
  url.searchParams.set('limit', '10')

  const upstream = await fetch(url, {
    headers: { 'X-API-Key': process.env.CALORIE_API_KEY },
  })
  res.status(upstream.status).json(await upstream.json())
})

app.listen(3001)

Debounced autocomplete

Debounce keystrokes so a fast typist costs one request instead of ten. It keeps the UI responsive and conserves your monthly quota.

useFoodSuggest.ts
import { useEffect, useState } from 'react'

export function useFoodSuggest(query: string) {
  const [results, setResults] = useState([])

  useEffect(() => {
    if (query.length < 2) return
    const t = setTimeout(async () => {
      const res = await fetch(
        `https://your-backend.example.com/api/food-search?q=${encodeURIComponent(query)}`
      )
      if (res.ok) setResults(await res.json())
    }, 250)
    return () => clearTimeout(t)
  }, [query])

  return results
}

Fetch full nutrition on selection

Suggest responses are intentionally lightweight (id, name, brand_name). When the user picks a suggestion, fetch GET /api/v1/foods/{id} through your proxy for per-100g macros, the nutrients array, and serving metadata, then compute logged amounts from the per-100g values.

Barcode scanning

Pair a scanner library (for example expo-barcode-scanner) with the barcode endpoint. The API resolves UPC/EAN codes against the local catalog and falls back to Open Food Facts automatically, so one code path covers both.

Scan handler
const onBarCodeScanned = async ({ data: upc }) => {
  const res = await fetch(
    `https://your-backend.example.com/api/barcode/${upc}`
  )
  if (res.status === 404) {
    // Unknown product, fall back to manual search
    navigation.navigate('FoodSearch')
    return
  }
  const food = await res.json()
  navigation.navigate('LogFood', { food })
}

Production tips

  • Cache food details by ID on-device, IDs are stable, and re-logging favorites then costs zero API calls.
  • Handle 429 with backoff using the X-RateLimit-Reset header; surface 402 (quota) as an app-level alert to yourself, not to end users.
  • Send X-API-Usage-Type: commercial from your proxy once the app monetizes (requires the Plus plan or higher).

Frequently asked questions

Can I call the Calorie API directly from React Native?

Technically yes, but you would ship your API key inside the binary. Route requests through a backend proxy so the key stays secret and you can add per-user throttling.

Which barcode scanner library works best?

Any library that returns raw UPC/EAN digits works, expo-barcode-scanner and react-native-vision-camera are common choices. The API accepts the digits as-is; dashes are stripped automatically.

Related resources