Web App · React · Node · API Engineering · Tax Tech
The only Ghana vehicle duty calculator that matches what GRA actually charges — line for line, levy for levy.
Ghana's vehicle import duty isn't one number — it's a stack of 15+ levies applied on CIF × a customs multiplier, recalculated daily against a moving exchange rate. Existing calculators are outdated, oversimplified, or wrong. Ghana Duty Calculator is the only tool that returns a line-by-line breakdown matching what GRA actually charges at the Bill of Entry, for 1,500+ vehicles across 80+ brands.


GRA doesn't publish a structured API for duty rates, levy schedules, or its daily customs exchange rate. The official rates exist only inside ICUMS (Integrated Customs Management System) and in scattered PDF notices. Any calculator built on hardcoded values is wrong within weeks.
So the first thing I built wasn't the calculator. It was the data layer.
Private rates API — deployed on Fly.io. Scrapes and normalises the daily GRA/ICUMS customs exchange rate. Parses GRA levy notices into a structured schedule: rate, base, applies-to. Maintains a versioned snapshot of the duty schedule so historical calculations stay reproducible. Exposes a single clean JSON endpoint to the frontend with cache headers tuned for daily refresh. Status is surfaced in the UI as a live/loading/stale indicator — users always know the basis of the calculation.
The frontend trusts one source. The source has one job. Updates to GRA rates ship without touching the React bundle.

The 2024 public transport EV waiver applies only to commercial fleets — private EVs are still charged 20%, not 5%. Caught and corrected before launch.
For a tool people use to negotiate six-figure cedi purchases, a wrong rate is worse than no tool. Regulatory correctness was a hard requirement, not a nice-to-have. Every levy in the schedule was verified against the published GRA notice before the calculation engine was written.
Circular import resolved by context extraction. Bundling broke because App.jsx and the Bill of Entry Guide both imported each other's theme. Pulled ThemeCtx and the useT hook into a standalone theme.js module. Both screens now consume the context without referencing each other.
Stale service worker debug. A blank-page crash on deploy traced to a service worker holding a cached useAuth.jsx chunk that no longer existed in the new bundle. Reviewed registration, added version-keyed cache invalidation to the deploy pipeline.
Vehicle data as a runtime asset. 1,500+ models served as a runtime-fetched JSON, not bundled. New vehicles ship without a redeploy. Custom searchable dropdown handles the scale that breaks a native select element.
Security at the edge. Strict CSP, CORS whitelist, rate limiting, structured request logging, pinned dependencies, Netlify _headers and netlify.toml enforcing security headers before requests hit the app. Cloudflare Web Analytics — no cookies, no PII.


React + Vite SPA served from Netlify handles all user interaction — vehicle search, form state, duty calculation, Bill of Entry rendering. No server-side rendering; the calculation is client-side once rate data arrives.
Private Rates API on Fly.io (Node/Express) is the only backend. It scrapes GRA/ICUMS for the daily customs exchange rate, parses the levy schedule, and returns a single structured JSON response. The frontend polls it once per session and caches the result in localStorage with a timestamp.
Cloudflare sits in front of both. Security headers, DDoS mitigation, analytics without cookies.
The information asymmetry in Ghana's vehicle import market is real and consequential. Buyers walk into negotiations not knowing what they owe. Clearing agents who do know have no incentive to tell you. A wrong estimate at the start of an import process can mean hundreds of thousands of cedis in unexpected cost.
Ghana Duty Calculator is small infrastructure that redistributes one specific piece of that information. It doesn't replace a clearing agent — but it means you sit across the table from one knowing your numbers.