Pricing intelligence for informal economies.
MarketLens is a full-stack platform that tracks, analyzes, and surfaces real-time price data from informal markets across the globe. It combines crowdsourced price observations with World Bank macroeconomic data, FAO producer price records, and live humanitarian alerts to compute an Informal Inflation Index (III) for each tracked market. An AI layer powered by Claude generates contextual price analysis, negotiation guidance, and market summaries.
The platform ships as a cross-platform mobile and web app (Expo / React Native Web) backed by a Python Flask API.
- Features
- Architecture
- Tech Stack
- Getting Started
- Project Structure
- API Reference
- External Data Sources
- Environment Variables
- Informal Inflation Index (III) - composite deviation score per market, updated in real time as observations come in
- Volatility Score - weighted coefficient of variation across all tracked items in a market
- Price Trend Acceleration (PTA) - percentage change in average price week-over-week
- Real Inflation Differential (RID) - gap between the informal III and official CPI from the World Bank
- Confidence Score - composite metric of observation volume, reporter diversity, and data recency
- Interactive heatmap of all tracked markets (mobile)
- Zoom-to-market with item-level price zone circles
- Card-based deviation view on web (native map not available in browser)
- Submit a price for any tracked item in any market
- Instant AI-powered analysis: deviation score, fairness rating, and negotiation guidance
- Dry-run mode to analyze without saving to the dataset
- Observations persist to PostgreSQL and improve the baseline for all users
- Point camera at any market item to identify it (mobile)
- File upload fallback on web
- Sends image to Claude for identification, then routes to price lookup
- Search all items across any market
- View price range (min, mean, max) with observation counts
- Live disaster feed from ReliefWeb API
- Disruption events automatically raise item baselines in affected categories (drought raises staples 35%, cyclone raises staples and merchandise 40%, etc.)
- Per-market narrative summary generated by Claude on each analysis cycle
- Per-submission insights: price context, severity label, negotiation script with cultural adaptation per city
┌─────────────────────────────────────────┐
│ Expo App (client/) │
│ React Native + React Native Web │
│ │
│ Mobile routes Web-only routes │
│ map.tsx map.web.tsx │
│ scan.tsx scan.web.tsx │
└───────────────┬─────────────────────────┘
│ HTTP (REST)
│ localtunnel for physical device
v
┌─────────────────────────────────────────┐
│ Flask API (backend/) │
│ │
│ /markets /market/:id │
│ /price/submit /identify │
│ /intel/global /intel/:id │
│ /intel/export /heatmap │
└──────┬───────────────────┬──────────────┘
│ │
v v
┌─────────────┐ ┌───────────────────────┐
│ PostgreSQL │ │ External APIs │
│ │ │ │
│ market_ │ │ Anthropic Claude │
│ reports │ │ World Bank API │
│ │ │ ReliefWeb API │
│ │ │ FAO CSV Data │
└─────────────┘ └───────────────────────┘
Baseline computation pipeline:
- FAO producer price CSV gives a historical floor for each item in each region
- World Bank CPI and food inflation multipliers adjust that floor for current macroeconomic conditions
- ReliefWeb disaster events add a category-specific shock multiplier if active
- Community observations from PostgreSQL further refine the baseline if enough data exists
- Submitted prices are scored against this adjusted baseline using a z-score method
| Technology | Version | Role |
|---|---|---|
| React Native | 0.81.5 | Core UI framework |
| Expo SDK | 54 | Native module management, build tooling |
| Expo Router | 6 | File-based navigation (Stack routing) |
| TypeScript | 5.9 | Type safety across all screens |
| React Native Web | 0.21 | Browser rendering of React Native components |
| React Native Maps | 1.20 | Interactive map with heatmap (mobile only) |
| Expo Camera | 17 | Live camera for field scanner (mobile only) |
| Expo Vector Icons | 15 | Ionicons icon set |
| React Native Reanimated | 4 | Smooth animations |
| React Native Gesture Handler | 2 | Gesture input |
| React Native SVG | 15 | SVG rendering |
| Technology | Version | Role |
|---|---|---|
| Python | 3.11+ | Runtime |
| Flask | 3.x | REST API framework |
| Flask-CORS | 5.x | Cross-origin request handling |
| psycopg2 | 2.9 | PostgreSQL driver |
| NumPy | 2.x | Numerical computation for baseline stats |
| SciPy | 1.x | Statistical modeling, z-score anomaly detection |
| pandas | 2.x | FAO CSV ingestion and data manipulation |
| Anthropic Python SDK | 0.x | Claude API client for AI analysis |
| python-dotenv | 1.x | Environment variable management |
| requests | 2.x | HTTP calls to World Bank and ReliefWeb |
| Technology | Role |
|---|---|
| PostgreSQL | Stores all price observations (market_reports table) |
| API | Role |
|---|---|
| Anthropic Claude | Item identification from images, price analysis narratives, negotiation scripts, market summaries |
| World Bank API | Official CPI and food inflation rates by country, used to adjust FAO baselines |
| ReliefWeb API | Live humanitarian disaster feed, used to detect supply shocks |
| FAO Producer Prices | Historical producer price CSV files for West Africa, India, and France, used as baseline floor |
| Tool | Role |
|---|---|
| localtunnel | Exposes local Flask server to physical devices during development |
| ThreadPoolExecutor | Parallel baseline computation per market item on each API request |
| In-memory cache | TTL-based response cache in Flask to avoid repeated external API calls |
- Node.js 18+ and npm
- Python 3.11+
- PostgreSQL (local or remote, e.g. Neon, Supabase, Railway)
- An Anthropic API key
- Expo Go installed on your phone (for mobile testing)
cd backend
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txtCreate a .env file in backend/:
DATABASE_URL=postgresql://user:password@host:5432/marketlens
ANTHROPIC_API_KEY=sk-ant-...Run migrations and start the server:
python app.py
# API available at http://localhost:5000cd client
npm installUpdate app/constants.ts to point to your backend:
// Local development
export const API_BASE = 'http://localhost:5000';
// Physical device (replace with your machine's local IP)
export const API_BASE = 'http://192.168.x.x:5000';
// Tunnel (for sharing across networks)
export const API_BASE = 'https://your-tunnel.loca.lt';cd client
npx expo start --clear
# Scan the QR code with Expo Go on your phonecd client
npm run web
# Opens at http://localhost:8081Note: the map screen automatically uses a card-based web layout instead of the native map component. The field scanner uses a file upload instead of the camera.
Marketlens/
├── backend/
│ ├── app.py # Flask app, all route definitions
│ ├── models/
│ │ ├── anomaly.py # Z-score baseline and price anomaly detection
│ │ ├── claude_insights.py # Claude API calls for analysis and summaries
│ │ └── intelligence.py # III, volatility, PTA, RID, confidence computation
│ ├── services/
│ │ ├── fao.py # FAO CSV ingestion and price floor lookup
│ │ ├── worldbank.py # World Bank CPI/food inflation API
│ │ └── reliefweb.py # ReliefWeb disaster feed and shock multipliers
│ └── data/
│ └── raw/ # FAO producer price CSV files
│
├── client/
│ └── app/
│ ├── constants.ts # API base, color palette, market and item definitions
│ ├── index.tsx # Home screen with active indices
│ ├── map.tsx # Interactive price map (mobile)
│ ├── map.web.tsx # Card-based deviation view (web)
│ ├── scan.tsx # Camera-based field scanner (mobile)
│ ├── scan.web.tsx # File upload scanner (web)
│ ├── search.tsx # Item lookup and price search
│ ├── report.tsx # Price observation submission
│ ├── intelligence.tsx # III dashboard with signals
│ ├── market/[id].tsx # Market detail with price index
│ ├── item/[name].tsx # Item detail with price history
│ └── lib/
│ └── cache.ts # Client-side fetch cache
│
└── design/
└── web-dashboard-spec.md # B2B web dashboard design specification
All endpoints are served from the Flask backend. Default port: 5000.
| Method | Endpoint | Description |
|---|---|---|
| GET | /health |
Server health check |
| GET | /markets |
All markets with current deviation rates and disaster flags |
| GET | /heatmap |
Simplified heatmap data (coordinates, color, deviation) |
| GET | /market/:id |
Full market detail: items, price ranges, summary, disaster status |
| POST | /price/submit |
Submit a price observation; returns AI analysis and score |
| POST | /identify |
Identify an item from a base64 image using Claude |
| GET | /intel/global |
Global composite III, volatility, confidence across all markets |
| GET | /intel/:id |
Single-market intelligence snapshot |
| GET | /intel/history/:id |
8-week historical III and volatility series |
| GET | /intel/export |
Full B2B data export for all markets |
Request body:
{
"market_id": "lagos",
"item_name": "Imported Rice (50kg bag)",
"submitted_price": 45000,
"quality": 7,
"amount": "50kg",
"reporter_type": "local",
"neighborhood": "Balogun",
"dry_run": false
}Request body:
{
"image_base64": "<base64-encoded image>",
"market_id": "lagos"
}CSV files sourced from the FAO STAT database covering producer prices for West Africa, India, and France. These files live in backend/data/raw/ and provide the historical price floor used to anchor baselines.
Fetches annual CPI (FP.CPI.TOTL.ZG) and food price inflation (FP.FPI.TOTL.ZG) for Nigeria, India, and France. This inflation multiplier adjusts FAO baselines to account for macroeconomic conditions. Results are cached locally to avoid hitting rate limits.
Live humanitarian alert feed from ReliefWeb. The backend queries for active disaster events in each market's country and maps disaster types (drought, flood, cyclone, epidemic) to price category multipliers. Example: a drought raises staple food baselines by 35%.
Used for three distinct tasks:
- Item identification - given a base64 image and market context, returns the identified item name and its expected price range
- Price analysis - given a submitted price and baseline data, returns a fairness score, severity label, deviation percentage, and a culturally-adapted negotiation script
- Market summaries - given a market's current deviation rate and flagged items, returns a paragraph of contextual analysis displayed on the market detail screen
| Variable | Description |
|---|---|
DATABASE_URL |
PostgreSQL connection string |
ANTHROPIC_API_KEY |
Anthropic API key for Claude |
| Constant | Description |
|---|---|
API_BASE |
Base URL of the Flask backend |
TUNNEL_HEADERS |
Headers required to bypass localtunnel browser warning |
| Market | City | Currency |
|---|---|---|
| Balogun Market | Lagos, Nigeria | NGN (Naira) |
| Chandni Chowk | Delhi, India | INR (Rupee) |
| Marche de Metz | Metz, France | EUR (Euro) |
Each market tracks 8 items covering staple foods, street food, and local merchandise.
Built for Hackalytics 2026.