OpenStreetMap Stats Generator. A tiny CLI (and Python library) that turns OSM history into per-user counts of nodes, ways, and relations created, modified, or deleted, written to parquet, csv, json, markdown, or Postgres.
A Project of OSGeo Nepal.
- Per-user create/modify/delete counts over any time window.
- Tag and hashtag breakdowns (e.g.
building,#hotosm). - Country and custom-boundary filters via Geofabrik.
- Cron-friendly resume with
--update. - Outputs you can query: parquet, csv, json, markdown, DuckDB, Postgres.
Pick the one that fits how you work.
uvx --from osmsg osmsg --last hour # zero-install, one-shot run
pip install osmsg # into your project
uv tool install osmsg # standalone CLI
docker run --rm -v "$PWD:/work" -w /work ghcr.io/osgeonepal/osmsg:latest --last houruvx can run osmsg in a throwaway environment , no install, no virtualenv to manage. Works
with any flag combination, e.g. uvx --from osmsg osmsg --last hour --tags building --summary -f parquet -f markdown.
osmsg --last hour # planet, last hour
osmsg --last day --tags building # last day with a tag breakdown
osmsg --hashtags hotosm --last day # only changesets tagged #hotosmThat's it. A stats.duckdb and a stats.parquet show up in your current folder.
osmsg --country nepal --last day--country resolves through Geofabrik and needs an OSM account. Set OSM_USERNAME and OSM_PASSWORD
in your shell or a .env file:
export OSM_USERNAME=you
export OSM_PASSWORD=secretosmsg --start "2026-04-01" --end "2026-04-08" \
--tags building --tags highway --summary--summary adds a daily rollup file alongside the per-changeset stats.
osmsg --country nepal --update # picks up where the last run stoppedDrop that into cron or a GitHub Actions schedule. State is stored inside the DuckDB file, so reruns are safe.
duckdb stats.duckdb -c "SELECT username, SUM(nodes_created) AS n
FROM users JOIN changeset_stats USING (uid)
GROUP BY username ORDER BY n DESC LIMIT 10"Same schema in DuckDB and Postgres: users, changesets, changeset_stats, state.
from datetime import datetime, UTC
from osmsg import RunConfig, run
result = run(RunConfig(
name="nepal",
countries=["nepal"],
start_date=datetime(2026, 4, 25, tzinfo=UTC),
end_date=datetime(2026, 4, 26, tzinfo=UTC),
))
print(result["files"]["parquet"])Same pipeline as the CLI.
osmsg --config nepal.yamlAny flag works as a YAML key. See docs/Manual.md for the full list.
Every run writes stats.duckdb (or <--name>.duckdb) plus the formats you ask for via
-f parquet|csv|json|markdown|psql. Parquet is the default. Open it with duckdb, polars, pandas, anything.
- Installation
- Manual (every flag, with examples)
- Version control / release notes
Pull requests are welcome. Quick path:
git clone https://github.com/osgeonepal/osmsg && cd osmsg
git switch develop
uv sync
uv run pre-commit install
uv run pytest -m "not network"Please read CONTRIBUTING.md and the Code of Conduct before opening a PR.
Use Conventional Commits (cz commit).
MIT © OSGeo Nepal contributors.