Back to Blog

Building Fuel Greece: Live Greek Fuel Prices on MapLibre with a Zero-Host Ledger CDN

Emmanouil Athanasopoulos3 min read557 words
React NativeExpoMapLibreFuel PricesOpen DataTypeScript

The Motivation Behind the Project

Greek drivers care about one number: the cheapest litre within a sensible radius. Existing fuel apps are often ad-heavy, slow to refresh, or stuck on stale maps. Fuel Greece was built as a focused Expo React Native client: a glassmorphic MapLibre map and list, brand and radius filters, Min/Max jump-to-station, bilingual EL/EN settings, and station detail sheets with directions and rolling price charts. The hard part was not the map—it was serving nationwide prices and honest history without running a database or inventing sparkline noise.

Core Features and Design Goals

  • Nationwide Station Map & List: MapLibre WebView map plus list mode for 4,700+ stations with distance sorting, cheapest-first ranking, and multi-select brand filters.
  • Realistic Radius & Fuel Filters: Practical search radii and fuel-type filters (Unleaded 95/100, Diesel, LPG, heating diesel) tuned for Greek driving, not toy demos.
  • Real Price Ledger History: Charts and sparklines sourced from a rolling daily price_ledger.min.json published with the scraper—no simulated drift.
  • Bilingual Settings: Greek/English locale and light/dark appearance persisted with AsyncStorage.
  • Station Actions: Google Maps driving directions, Street View entry points, and Google review badges when Places data is available.
  • Zero App Backend: Stations, prefecture averages, reviews map, and ledger assets are fetched from GitHub Releases CDN with local cache fallback.

Deep Dive: How It Works Under the Hood

The mobile app never scrapes the ministry itself. A companion FuelGR Pipeline job publishes compact master JSON, Zstandard twins, a rolling price ledger, and incremental Google reviews enrichment. The client prefers the ledger for history sheets; if a station only has one real day so far, the UI shows that honestly and grows with each daily scrape. Safe-area handling on Android (nav bar insets, measured header height for list mode) mattered as much as the data model for a production feel.

Technical Implementation

  • Built the client with Expo Router, MapLibre in a WebView, and a settings sheet for locale/theme.
  • Cached stations_latest.min.json and price_ledger.min.json via AsyncStorage with no-cache network fetches against the Releases CDN.
  • Derived chart series from ledger day records (including single-day stations) instead of inventing 14-day drift.
  • Wired production Android signing with local credentials.json + Expo config plugin so release builds survive expo prebuild.

Architecture Overview

Fuel Greece (Expo app) ← HTTPS → GitHub Releases latest/download assets produced by fuelGR-scraper (daily Actions). UI layers: map/list screen, station callout, history sheet, settings sheet. Prefs and caches live on-device; no custom API server.

Challenges I Faced Along the Way

Honest history was the product risk: shipping fake sparklines looked complete but misled users. Switching to a real ledger made early charts thin (1–2 days) until scrapes accumulate—so the UI had to explain that history fills daily rather than falling back to invented curves.

The Technology Stack

React Native, Expo, TypeScript, MapLibre, AsyncStorage, lucide-react-native, and GitHub Releases as the data CDN (FuelGR Pipeline).

What I Would Do Differently Next Time

Ship the Play Store link and product narrative even before the listing is fully live—portfolio and case study should match the package id users will install (com.athanasso.fuelgreece), not the scraper repo.

Final Reflections

A Greece-specific utility app can stay lean if the heavy lifting lives in a scheduled open data pipeline: the mobile client stays a polished map UX, and the Play listing points at a product that gets more truthful every day the scraper runs.