Postal Codes Dataset for United Kingdom, GB

348
Updated:
Files:1
Size:235 MB
Rows:1,749,109
Formats:csv

Postal Codes Dataset for United Kingdom, GB including name of the city, town, or place, various administrative divisions and alternative city names.

Part of a Data Solution

  • Postal Codes Solution

    Every worldwide postal-code dataset in one bundle — the ultimate global reference for precise postal codes.

    Explore →

Premium

You're viewing a free sample

Get the complete dataset — all rows and files — delivered instantly after checkout, with lifetime access to the latest version.

  • Secure checkout via Stripe
  • Instant download after payment
  • Lifetime access to the latest version
  • Open Government Licence v3.0 license
20% off
$99.90$79.92
one-time payment

API Access

Access dataset files directly from scripts, code, or AI agents.

Browse dataset files
Dataset Files

Each file has a stable URL (r-link) that you can use directly in scripts, apps, or AI agents. These URLs are permanent and safe to hardcode.

/logistics/postal-codes-gb/
https://datahub.io/logistics/postal-codes-gb/_r/-/.licensing-notes.md
https://datahub.io/logistics/postal-codes-gb/_r/-/.migration-notes.md
https://datahub.io/logistics/postal-codes-gb/_r/-/ATTRIBUTION.txt
https://datahub.io/logistics/postal-codes-gb/_r/-/README.md
https://datahub.io/logistics/postal-codes-gb/_r/-/datapackage.yaml
Key Files

Start with these files — they give you everything you need to understand and access the dataset.

datapackage.yaml— metadata & schema
https://datahub.io/logistics/postal-codes-gb/_r/-/datapackage.yaml
README.md— documentation
https://datahub.io/logistics/postal-codes-gb/_r/-/README.md
Typical Usage
  1. 1. Fetch datapackage.yaml to inspect schema and resources
  2. 2. Download data resources listed in datapackage.yaml
  3. 3. Read README.md for full context

Data Files

postal-codes-gb-sample


About this dataset

Great Britain (GB): migration notes

Internal record of the P5 migration from the old scripts to the producer: the discrepancies found, their causes, and who decided what. This is a dated record, so the numbers are as of the migration and not kept current. It is not shipped in the zip.

  • Issue: pc-28e.7.23 (closed 2026-10-03)
  • Commit: 20284af (worktree commit 4c32157), landed in batch 5
  • Parity verdict: unexplained (the gate blocks on any unclassified cell); accepted as upstream drift plus two user decisions
  • Producer: custom, refresh disabled

Sources

InputURLNotes
OS Code-Point Open (CSV)https://api.os.uk/downloads/v1/products/CodePointOpen/downloads?area=GB&format=CSV&redirectOS Downloads API's stable latest-release URL, no account or key. 2026-08 release at migration time
ONS Local Authority Districts (April 2025) Names and Codes, V2https://open-geography-portalx-ons.hub.arcgis.com/api/download/v1/items/5779a9578f0e48ccacef6af41546b56b/csv?layers=0
ONS Counties (December 2025) Names and Codes in ENsame pattern, item 646a11ad90574e949fd0e9b12199f35f
ONS Wards Names and Codes: May 2024, Dec 2022, Dec 2023, May 2025, May 2026same pattern, items 8b712468c9d1491e9d3d023c8408e1ea, 6d3a1a1cf24d4543965a9fef1dcf9c9d, 8e206a9475a9426491b68f096568cb8b, db1e8af0f59f4aaf8ec5d21afe8f26b0, 06bf0a5d7bc14148a347aa8517b2a945May 2026 is new (see Decisions)
GeoNames GB gazetteer dumphttps://download.geonames.org/export/dump/GB.zipNearest populated place (feature class P)
  • The old scripts read hand-fetched files from sources/; no download URL was recorded. The agent found the OS Downloads API URL and the ONS item ids through the ArcGIS search API.
  • The ONS lookups are fixed vintages, so their URLs don't move. A future Code-Point release on newer ward codes makes the producer stop with "ward code … isn't in the ONS lookups" until someone adds that vintage to WARD_URLS.

Parity against the live zip (2026-10-03)

Rows: 1,747,841 live and 1,749,109 fresh. 2,237 only in live, 3,505 only in fresh. 157,082 rows changed, 332,536 cells, all unclassified. Line endings change from CRLF to LF.

Changed cells by column: admin_code3 120,103; admin_name3 59,577; latitude 37,802; longitude 38,087; easting 36,833; northing 36,726; place_name 2,874; accuracy 362; admin_code2 / admin_name2 68 each; admin_county_code / admin_county_name 16 each; admin_code1 / admin_name1 2 each.

How the agent showed the logic reproduces the old build:

  • On every row whose easting/northing is unchanged, latitude/longitude match exactly (the pyproj BNG→WGS84 conversion matches).
  • On every row whose GSS codes are unchanged, the district, ward and county names match (lookups and ward load order match).
Rows / cellsChangeCause
2,237 only in live, 3,505 only in fresh (e.g. live-only AB10 1WS, AB11 8TU; fresh-only AB12 9HJ, AB15 8RG)Postcodes terminated / addedCode-Point Open drift: live was built from an older release than 2026-08 (the live datapackage says created 2026-08-25)
120,103 admin_code3, 59,577 admin_name3New ward codesCode-Point drift. 119,895 rows carry May 2026 ward codes that live has none of, e.g. B14 4LJ: live E05001298 "Shirley West" → fresh E05016430
~36.8k easting/northing, ~38k lat/lonCoordinates movedCode-Point drift, e.g. AB10 1JR 393970,806184 → 393977,806177 (lat 57.146503 → 57.146440)
362 accuracyPositional quality changedCode-Point drift, e.g. 325 × 50→10, 17 × 20→10, 12 × 50→20, 5 × 10→50
68 admin_code2/name2, 16 county, 2 admin_code1/name1Code changesCode-Point drift (covered by the "names match where codes unchanged" check; the individual rows were not examined)
1,659 place_nameFollows moved coordinatesCode-Point drift
562 place_name on unchanged coordinatese.g. BA15 1AA "Bradford-on-Avon" → "Bradford on Avon" (GeoNames renamed it 2026-09-14); B30 1JT Selly Oak → Bournville (Bournville entry modified 2026-09-21)GeoNames dump drift. The agent ran the old SciPy cKDTree algorithm on today's dump; it also disagrees with live on these rows
653 place_name on unchanged coordinatese.g. AB37 9ES "Delnabo" → "Easter Gaulrig" (both at 57.21667, -3.38333); AB39 3AG Newtonhill → SkaterawTie-break between GeoNames places with identical coordinates (55 groups). The new code takes the first in file order; cKDTree's pick had no pattern (35 last, 17 first, 3 middle)

1,659 + 562 + 653 = 2,874 place_name cells.

Decisions

DecisionByBasis
Accept the Code-Point Open and GeoNames driftStanding rule (upstream drift traced to source, user, 2026-10-03)Evidence above; recorded in the batch 5 sign-off in docs/parity/p5.md
Add the ONS Wards (May 2026) lookupUser, 2026-10-03 (session d33e1b7e, "Add May 2026 wards")Without it, 119,895 rows (6.9%) fail the new unresolved-code check; the old builder would have left those ward names blank
Deterministic first-in-file tie-break for co-located GeoNames places, instead of matching SciPy's cKDTreeUser, 2026-10-03 (session d33e1b7e, "Deterministic first-in-file")SciPy isn't in the venv or requirements; cKDTree's tie pick is arbitrary and can shift with each dump. Changes 653 cells
Exact nearest-place grid search in NumPy (chord distance) rather than SciPyAgentAvoids adding scipy to requirements-producers.txt; agrees with cKDTree except on exact ties
Ward vintages unioned in the old build's actual load order (May 2024, Dec 2022, Dec 2023, May 2025, then May 2026; later wins)Agent: a faithful portThe old code comment claimed a different order; the sorted-file-name order is what actually ran
Unresolved district/ward/county codes and a missing country now stop the buildAgentNew ProducerError checks
Drop scripts/README.md and publish_r2.py; remove counts and the DATA_DICTIONARY.md / gb.zip entries from the README contents tableAgentCounts rule; the built zip doesn't contain those files

Transforms carried over

Folded from parse_codepoint.py → enrich_uk.py → fill_place_name.py → data_integrity_checker.py (restored 2026-08-25):

  • Rows from every Data/CSV/*.csv in the Code-Point zip, in sorted file order; cells stripped.
  • admin_code1 = CY, mapped to England / Scotland / Wales; admin_code2 = DC; admin_code3 = WC; admin_county_code = CC; accuracy = PQ; easting/northing verbatim.
  • BNG (EPSG:27700) → WGS84 with pyproj, 6 decimals. Positional-quality 90 rows (0,0) get blank coordinates.
  • Names joined on GSS code from the ONS lookups; the ONS UTF-8 BOM is stripped.
  • place_name = nearest GeoNames populated place from the 6-decimal coordinate; rows without a coordinate have none. alternative_city_name is always empty.
  • Old checker gates are ProducerErrors: postcode pattern, unique postcode, known country code, GB bounding box. New: all three countries present, every district/ward/county code resolves.

Open questions

  • None recorded from the agent beyond the two answered above.
  • ATTRIBUTION.txt still has counts ("1,747,841 unit postcodes", "865 of 1,747,841", "31.9% of rows"), and .licensing-notes.md has historical counts. Left alone; they belong to the pc-hfz sweep.

Provenance

Reconstructed 2026-10-05 from the agent transcript d33e1b7e-5027-498a-a97f-ba914ee2524e/subagents/agent-ada3531935232a997.jsonl, the orchestrator session d33e1b7e-… (AskUserQuestion answers and close), the commit message, the bd close reason and the batch 5 sign-off in docs/parity/p5.md.