A dependency-light, standards-based Monitoring & Evaluation toolkit for public health, development, and campaign programmes.
No server. No DHIS2 instance required. No framework lock-in. Just correct, tested formulas for the calculations every M&E team does by hand in Excel — coverage math, RDQA scoring, data quality checks, logframe tracking, campaign-day performance tiering, and DHIS2 interoperability — as a single JavaScript library you can drop into a spreadsheet tool, a Firebase app, a CLI, or a Node backend.
Most open-source M&E tooling falls into one of two camps: fully DHIS2-locked (powerful, but requires a running instance and admin access most district-level and NGO teams don't have), or ad-hoc Excel macros that live on one person's laptop and die when they leave. This toolkit is neither — it's the calculation layer, extracted and made portable, so you can build whatever interface you need on top of it.
Built out of real field use: day-by-day tiering logic from live polio SIA rounds, RDQA scoring from routine facility data quality assessments, and logframe tracking from an active Ebola virus disease M&E plan — generalized into reusable, tested functions.
npm install me-indicator-toolkitOr clone directly:
git clone https://github.com/<your-username>/me-indicator-toolkit.git
cd me-indicator-toolkit
npm install
npm test| Module | What it does |
|---|---|
coverage |
Administrative & survey coverage, dropout rate, target population estimation, coverage gap, facility-level rollups with tiering |
rdqa |
Routine Data Quality Assessment — Verification Factor scoring, batch verification, system dimension (availability/completeness/timeliness/accuracy) scoring |
dataQuality |
Report completeness, timeliness, missing facility detection, z-score outlier detection, period-over-period change flags |
tiering |
Day-by-day SIA/campaign performance tiering, pro-rated daily targets, redeployment candidate identification, end-of-campaign projection |
Logframe / Indicator |
Baseline/target/actual tracking with automatic percent-achievement and status classification, for any results framework |
dhis2 |
Convert to/from DHIS2 dataValueSet import/export format, period string builders, payload validation |
statistics |
Sample size calculation (Cochran's formula, with finite population correction and design effect), sample size for comparing two proportions, Wilson score confidence intervals, two-proportion z-test, LQAS decision rule |
sampling |
PPS (probability proportional to size) cluster allocation, proportional and equal stratified allocation, systematic sampling interval calculation |
economics |
Cost per output, cost per beneficiary, incremental cost-effectiveness ratio (ICER), budget utilization rate, cost per coverage point gained |
TheoryOfChange / ResultsChainNode / contributionScore |
Build and validate a results chain (input→activity→output→outcome→impact), catch orphaned outcomes and backward links, score plausibility of programme contribution using contribution-analysis logic |
qualitative |
Thematic code frequency tallying, code co-occurrence detection, thematic saturation tracking for mixed-methods M&E |
indicators.immunization |
FIC rate, DTP1→DTP3 dropout, vaccine wastage, cold chain functionality |
indicators.hiv |
ART coverage, viral load suppression/coverage, UNAIDS 95-95-95 cascade, retention rate, MTCT rate |
indicators.tb |
Treatment success rate, case notification rate, TB/HIV testing rate, loss to follow-up rate |
indicators.maternalHealth |
ANC4+ coverage, skilled birth attendance, institutional delivery rate, maternal mortality ratio, PNC coverage |
indicators.nutrition |
GAM prevalence with severity classification, stunting prevalence, SPHERE-standard recovery/default rates, exclusive breastfeeding rate |
indicators.malaria |
Test positivity rate, ITN ownership/use rate, incidence rate, case fatality rate, IRS coverage |
indicators.wash |
JMP service ladder classification, basic water/sanitation access, open defecation rate, handwashing facility coverage, water point functionality |
indicators.familyPlanning |
mCPR, unmet need, demand satisfied, couple-years of protection (CYP) with standard FP2030 conversion factors |
const met = require('me-indicator-toolkit');
// Coverage
met.coverage.administrativeCoverage(950, 1000); // 95
// Campaign day tiering (from a live 7-day SIA)
met.tiering.tierDayBatch(
[
{ facility: 'Molepolole Clinic', cumulativeDoses: 450, targetPopulation: 1000 },
{ facility: 'Lentsweletau Clinic', cumulativeDoses: 60, targetPopulation: 1000 }
],
3, // day 3
7 // of a 7-day campaign
);
// => redeploymentCandidates: ['Lentsweletau Clinic']
// Logframe tracking
const { Logframe } = met;
const lf = new Logframe('EVD Response M&E Plan 2026');
const ind = lf.addIndicator({ name: 'RDQA completion rate', baseline: 0, target: 100 });
ind.logActual('2026-Q2', 65);
ind.status(); // 'at_risk'
// RDQA verification factor
met.rdqa.verificationFactor(98, 100); // { vf: 98, classification: 'match' }
// UNAIDS 95-95-95 cascade
met.indicators.hiv.cascade9595(1000, 950, 900, 855);
// Push clean data into DHIS2
met.dhis2.toDataValueSet({
dataSet: 'abc123',
orgUnit: 'ou456',
period: met.dhis2.toDhis2Period(new Date(), 'Monthly'),
values: [{ dataElement: 'de1', value: 42 }]
});
// Sample size for a coverage survey (95% CI, ±5% margin, design effect 2 for cluster sampling)
met.statistics.sampleSizeForProportion(0.5, 0.05, 95, null, 2);
// Is the difference between baseline and endline coverage statistically significant?
met.statistics.twoProportionZTest(320, 500, 410, 500); // baseline vs endline successes/n
// Allocate survey clusters proportional to population (PPS)
met.sampling.ppsClusterAllocation(
[{ area: 'Molepolole', population: 70000 }, { area: 'Thamaga', population: 15000 }],
20
);
// Cost-effectiveness comparison between two delivery approaches
met.economics.incrementalCostEffectivenessRatio(10000, 10, 15000, 20);
// Build and validate a Theory of Change
const toc = new met.TheoryOfChange('EVD Response ToC');
toc.addNode({ id: 'act1', level: 'activity', description: 'Train 40 CHWs', linksTo: ['out1'] });
toc.addNode({ id: 'out1', level: 'output', description: 'CHWs trained', linksTo: ['outcome1'] });
toc.addNode({ id: 'outcome1', level: 'outcome', description: 'Faster alert response' });
toc.validate(); // flags orphaned outcomes, backward links, missing targets
// Score plausibility of programme contribution to an observed outcome
met.contributionScore({
resultsChainPlausible: true,
activitiesImplemented: true,
otherFactorsAssessed: true,
outcomeObserved: true
});
// Thematic saturation from a sequence of interviews
met.qualitative.saturationTracker([
{ interview: 'I1', newCodesIntroduced: 5 },
{ interview: 'I2', newCodesIntroduced: 0 },
{ interview: 'I3', newCodesIntroduced: 0 },
{ interview: 'I4', newCodesIntroduced: 0 }
], 3);See examples/ for fuller worked examples, including a full SIA campaign-day workflow and an EVD logframe setup.
For non-developers, the most common reports are available as command-line commands against a CSV file — no JavaScript required.
npm install -g me-indicator-toolkit
# or, from a cloned repo: node bin/cli.js <command> ...
me-toolkit coverage-rollup facilities.csv --target=90
# Expected columns: facility,dosesAdministered,targetPopulation
me-toolkit rdqa-batch rdqa-data.csv
# Expected columns: indicator,sourceCount,reportedCount
me-toolkit completeness reporting.csv
# Expected columns: facility,reported (1/0 or true/false)
me-toolkit sample-size --p=0.5 --margin=0.05 --confidence=95 --deff=2
me-toolkit --helpSample CSVs to try these against are in examples/sample-data/.
- Pure functions. No I/O, no global state, no side effects. Every function takes plain data in and returns plain data out — easy to test, easy to embed anywhere.
- Cited formulas. Every indicator formula follows a named, documented standard (WHO EPI, PEPFAR MER 2.0, UNAIDS 95-95-95, SPHERE, WHO RDQA methodology) — not an invented approximation.
- Fails loud, not silent. Bad input (negative numbers, missing fields, out-of-range values) throws immediately rather than returning
NaNorundefinedthat quietly corrupts a downstream report. - Zero runtime dependencies. The only dependency in this repo is
jest, and only for testing. - DHIS2-adjacent, not DHIS2-dependent. You can use every module without ever touching a DHIS2 instance. The
dhis2module is there for teams that need to push data upstream once it's clean.
npm test # run the full suite
npm run test:coverage # run with coverage report170 tests across 13 suites.
Indicator formulas are the highest-value contribution area — if your programme area (malaria, WASH, education, food security, etc.) isn't covered yet, open an issue with the standard formula and its source (WHO/UNAIDS/Global Fund/SPHERE/etc.) and a PR is very welcome. Keep new functions pure and add tests alongside them.
- No NLP or auto-coding.
qualitative.jsaggregates codes a human analyst has already applied — it doesn't do sentiment analysis or automatic theme extraction. That's a defensible line, not a gap: automated qualitative coding without human judgment is a credibility risk in this field. - No discounting or DALY/QALY modeling in
economics.js. Full health economic evaluation is its own discipline; this module covers what an M&E officer is routinely asked for, not what a health economist would build. - No live DHIS2 round-trip test out of the box — the
dhis2module's payload shape follows the documented API format, but ships untested against a running instance. Runscripts/verify-dhis2.jsyourself against your own instance (or the public DHIS2 demo) to confirm before relying on it in production. Credentials are read from environment variables only — see the script's header for exact usage. Never commit or paste credentials anywhere; the script defaults to a read-only dry-run. - No visualization layer. Pure calculation — pair it with your own charting/dashboard layer.
MIT — see LICENSE.
Built by Kabo "Rogue" Onamile, a Public Health M&E professional working within Botswana's district health system, out of tooling originally developed for live nOPV2 polio SIA rounds and Ebola virus disease M&E planning at Kweneng District Health Management Team.