01
The problem
Remittances are ~20% of The Gambia's GDP. Every Gambian family has someone abroad sending money home. The Central Bank of The Gambia has internal forecasts of FX rates and remittance inflows; ordinary Gambians don't. There is no public-facing forecast of what the Dalasi will do next month, no dashboard showing diaspora corridors, no calculator for 'what will £100 be worth when I receive it'. I built the citizens' version: a public dashboard that shows what the Dalasi is doing, where remittances are coming from, and what the next six months look like, so a family deciding when to send or receive can plan instead of guess.
02
How it fits together
03
What this is built on
- The Central Bank of The Gambia's annual reports (2019-2024) set the currency list (USD, EUR, GBP, CHF, JPY) and the seasonality: remittance peaks during Ramadan, Eid, school-year start in September.
- The World Bank KNOMAD methodology on bilateral remittance estimation is the source. The data is corridor-level: UK to GM, US to GM, ES to GM, DE to GM. The methodology matters because the numbers are mostly imputed from migration stocks and sender-country incomes, not actual transaction data.
- Prophet's Bayesian framework (Taylor and Letham 2017) is the reference for handling Ramadan and Eid, which drift 11 days a year against the Gregorian calendar and are invisible to a month-of-year seasonal term. Prophet is better at multi-period seasonality, SARIMA at short cyclicality. Both are used in ensemble.
- Reverse-engineered the Central Bank of The Gambia website's network behaviour by opening their FX rates page in Chrome devtools. Saw an undocumented JSON endpoint at `cbg.gm/ajax/indicative-exchange-rates/{CURRENCY}` returning 25 years of daily rates. Authoritative, free, no key required. Confirmed it worked across all major currencies before betting the project on it.
- GitHub Actions cron is the scheduler, not Vercel's. Vercel's Hobby cron wakes the function once per day at a non-customisable time. Actions gives precise scheduling and a free workflow log.
04
What I couldn't do
- All data sources had to be free. No Bloomberg terminal, no paid APIs, no licensed datasets.
- Forecast accuracy had to be honest about uncertainty (intervals, not point estimates).
- Dashboard had to load in seconds on a Gambian 3G connection, most users are on Tecno/Infinix phones, not iPhones.
- Could not call any paid API at runtime (per-user cost would crush the project).
- Had to be visually trustworthy. Financial data on a badly designed page reads as wrong even when it is not.
05
The decisions that shaped it
Decision 01
Reverse-engineer the CBG's undocumented JSON endpoint as the primary data source.
The Central Bank publishes daily indicative rates as a webpage with no documented API. Opened the network tab and found `cbg.gm/ajax/indicative-exchange-rates/{CURRENCY}` returning 25 years of daily rates as JSON, no auth required. Official, authoritative, free. Built the entire pipeline on it; cross-validated against `exchangerate.host` as a backup.
Decision 02
SARIMA only, and the holiday model is still unbuilt.
The plan was a Prophet and SARIMA ensemble: Prophet for the Ramadan and Eid remittance spikes, which drift 11 days a year against the Gregorian calendar and are therefore invisible to a month-of-year seasonal term, and SARIMA for the shorter cyclicality in the FX series. What ships is SARIMA(1,1,1)(1,1,1,12) alone. Prophet is named as the next step in the exploration notebooks and was never built, so the holiday model is the largest open item rather than a shipped feature.
Decision 03
Static export pre-rendered at build time, not server-rendered per request.
The data updates daily, not by user request. Pre-render once at build time with the latest forecast, ship as static HTML + JSON, host on Vercel free tier. Loads instantly anywhere, costs nothing per visitor. The build is triggered by the daily Actions job that refreshes the forecast.
Decision 04
Daily GitHub Actions refresh + auto-commit, not Vercel cron.
Vercel Hobby cron runs once per day but at a server-determined time. Actions cron runs at a precise schedule, has free unlimited minutes for public repos, and produces a visible workflow log. The Actions job: fetch CBG rates, then recompute Prophet/SARIMA, then commit `data/processed/*.csv`, then push, then Vercel auto-deploys the updated build. The ~25 commits visible in `git log` (`Refresh forecasts 2026-04-12`, `2026-04-13`, …) are this loop running on autopilot.
Decision 05
Bypass Next.js fetch cache + use browser-like headers when querying CBG.
First version had `/api/fx` returning year-2000 rates instead of latest. Spent half a day debugging, turned out Next.js's fetch cache was holding a stale CBG response from build time. Worse: CBG occasionally returned different data based on user-agent (presumably to discourage scraping). Fix was to set `cache: 'no-store'` AND send a normal browser User-Agent header. Two unrelated bugs on the same code path (commits 06a6d18, 4e2d1e2).
Decision 06
Plain-language interpretation alongside the chart.
A line chart with a forecast band is not enough for the average user. Added a plain-English interpretation paragraph: 'The Dalasi has weakened ~3% against the Pound this year. Forecasts suggest moderate stability through the next 6 months with a wider band around Eid. £100 today buys GMD 8,750, and the forecast suggests it will buy 8,400-9,100 next month.' The chart is for analysts; the prose is for everyone else (commit ac5e78f).
Decision 07
Live-status badge with CBG date stamp, polled every 15 minutes.
Users don't trust financial data without knowing when it last updated. Added a 'Live · CBG date 2026-05-08' badge that polls the API every 15 minutes. If the date is more than 24 hours stale, it visibly flags it (commit db5e7b1).
06
What broke and how I changed course
- First version was just FX. Added remittances as an afterthought. Realised they mattered MORE than FX for the typical Gambian family, most don't trade currencies, they receive transfers. Reframed the dashboard around remittances and made FX the supporting layer.
- Used `exchangerate.host` as the primary FX source initially. Then discovered the CBG endpoint by accident while inspecting the bank's website. Switched primary to CBG and kept exchangerate.host as a cross-validation backup.
- Original ETL pipeline had no cleaning layer, just fetched, plotted. Found that CBG had occasional duplicate rows from their backend, plus a methodology break around 2010 where the calculation changed and rates jumped 8% overnight. Wrote a cleaning script: dedupe, outlier removal (3-sigma), and a methodology-break correction factor for pre-2010 rates. The forecasts stopped having weird spikes (commit ba82a7e).
- Mobile UX broke because the currency selector pills wrapped onto a second line under the amount input on narrow screens, pushing content off-screen. Restructured the layout so currency pills sit above the amount field on mobile, side-by-side on desktop (commit 64e7bec).
07
What I didn't know, and how I learned
- I did not know how Prophet and SARIMA differed before this project. I read both papers and fitted SARIMA with walk-forward holdouts, but I never got Prophet running on the Dalasi series, so the comparison I set out to make is still unmade.
- I was new to GitHub Actions cron schedules. First version had the wrong cron syntax and the job ran every minute. Fortunately discovered before committing API-key usage to that.
- Time-series cross-validation is different from random-split CV. Shuffling time-ordered data leaks the future into the training set. The evaluation pipeline was rewritten around walk-forward validation. Forecast metrics dropped from optimistic to realistic.
- I underestimated how much pre-2010 Dalasi data was non-comparable to post-2010 data due to a methodology break. Adding the correction factor was a research task rather than a coding task. I had to read the CBG's methodology footnotes to find the conversion ratio.
08
What shipped
- Live FX dashboard for Dalasi vs USD, EUR, GBP, CHF, JPY
- 25 years of daily CBG rates
- 6-month-horizon forecasts with confidence intervals (SARIMA, walk-forward validated against a random-walk baseline)
- Bilateral remittance corridor breakdown (UK, US, Spain and Germany to GM)
- '£100 next month' calculator for diaspora users
- 60-day daily forecasts + monthly sending calendar
- Plain-language interpretation paragraph
- Daily auto-refresh via GitHub Actions, deploys on commit
- Static export, instant load on 3G
09
What's next
I'd add a free SMS-out for non-smartphone users, text the dashboard a query like 'GBP forecast' and get the answer back. Most of the audience that would benefit most is not on smartphones. Would need a free SMS gateway (Africa's Talking has limited free credits) or a Telegram bot as a stopgap. Adding next.
What I learned
The CBG endpoint was sitting in the network tab the whole time. For financial forecasts, uncertainty intervals, model ensembles, plain-language interpretation, and last-updated timestamps are what make the numbers usable.