Part of a Data Solution
- Explore →
Postal Codes Solution
Every worldwide postal-code dataset in one bundle — the ultimate global reference for precise postal codes.
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
- Creative Commons Attribution 4.0 International license
API Access
Access dataset files directly from scripts, code, or AI agents.
Browse dataset files
API Access
Access dataset files directly from scripts, code, or AI agents.
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.
Start with these files — they give you everything you need to understand and access the dataset.
- 1. Fetch datapackage.yml to inspect schema and resources
- 2. Download data resources listed in datapackage.yml
- 3. Read README.md for full context
Data Files
Postal Codes Data Resource for China, CN
| Field | Description | Title |
|---|---|---|
| country_code | ISO 3166-1 alpha-2 code for the country. | Country Code |
| postal_code | Postal code for the location. | Postal Code |
| place_name | Name of the city, town, or place. | Place Name |
| admin_name1 | Primary administrative division (e.g., state, region). | Administrative Name 1 |
| admin_code1 | Code for the primary administrative division. | Administrative Code 1 |
| admin_name2 | Secondary administrative division (e.g., county, district). | Administrative Name 2 |
| admin_code2 | Code for the secondary administrative division. | Administrative Code 2 |
| admin_name3 | Tertiary administrative division (e.g., municipality, borough). | Administrative Name 3 |
| admin_code3 | Code for the tertiary administrative division. | Administrative Code 3 |
| latitude | Latitude coordinate of the place. | Latitude |
| longitude | Longitude coordinate of the place. | Longitude |
| accuracy | Accuracy level of the latitude and longitude coordinates. | Accuracy |
| alternative_city_name | Alternative name(s) for the city or place. | Alternative City Name |
Download
Download sample CSVAbout
- Last updated
- 17 September 2026
- Total rows
- ...
- Format
- CSV
- File size
- 222 kB
About this dataset
China (CN) — internal licensing notes
Source research, 2026-09-17 — first proper audit of this country
No .licensing-notes.md existed for CN before this pass. datapackage.yml
carries the old-style placeholder sources: [{title: "Multiple sources", path: https://datahub.io/collections/postal-codes-datasets}] — the same
non-informative pattern already flagged as a defect elsewhere in this
project (see feedback_datapackage_no_sources) — and no licenses: array
at all. is_premium: true but nothing in the repo records what cn/cn.csv
actually is. Same starting condition CH/PR/CO were in before their
2026-09-16 audits.
Also stale in datapackage.yml: the declared resource is bytes: 9241, modified: '2024-11-07'. The real R2 object is 230,741 bytes, modified
2026-07-30 — the metadata describes neither the size nor the date of the
file customers actually get. See §4 for what the 9,241-byte figure
actually corresponds to.
1. What the current R2 file (cn/cn.csv, 230,741 bytes, 2026-07-30) actually is — VERIFIED
Fetched directly from the main postal-codes R2 bucket (read-only,
R2_ACCESS_KEY/R2_SECRET_KEY from this repo's own .env).
Row count: 2,352 data rows. Not a coincidence and not a subset build — this is essentially the complete GeoNames China postal file, because GeoNames' own China coverage is truncated at source (see below). 230 KB for "China postal codes" looks tiny only if you assume GeoNames covers China at real 6-digit/township granularity. It doesn't.
Confirmed via GeoNames' own readme.txt
(https://download.geonames.org/export/zip/readme.txt):
For China we have only the first digits of the full postal codes ending
with 00
This is the exact "for copyright reasons"-style truncation caveat the task
asked me to check for — China sits in the same readme paragraph as Chile,
Ireland, Malta, Argentina and Brazil, all of which GeoNames explicitly
ships in truncated form. Verified directly: every one of the 2,352
postal codes in both the R2 file and raw GeoNames CN.txt ends in 00
(2,349 distinct codes). Real Chinese postal codes are 6-digit and reach
township/delivery-office granularity (China's actual system has on the
order of tens of thousands of assigned codes); this file only ever
carries the first 4 significant digits + 00, i.e. prefecture/county-level
granularity at best, never a real township-level code. This is a
GeoNames-side ceiling, not something introduced by this repo's pipeline —
no rebuild against GeoNames can fix it; a real per-township product needs
a different source entirely (see §3).
Fetched https://download.geonames.org/export/zip/CN.zip (CC BY 4.0)
directly for comparison: CN.txt also has exactly 2,352 rows, and the
R2 file is a straight tab-to-comma conversion of it, carrying forward
several defects:
GeoNames: CN 230000 Hefei Anhui 01 Hefei Shi 3401 31.8639 117.2808 4
R2 file: CN,230000,Hefei,Anhui,1,Hefei Shi,3401.0,nan,,31.8639,117.2808,4.0,Hefei
Defect A — literal string "nan" in admin_name3 (225 rows)
Wherever GeoNames' own admin3 code/name field is empty, the R2 file
contains the literal 4-character string nan instead of an empty cell —
a classic pandas NaN-to-str() bug. Confirmed on 225 of 2,352 rows.
This is not a stale-conversion artifact — it is reproduced in the
pipeline's own live output. cn/geonames/latest/0.csv and
cn/geonames/2026-09-01/0.csv (both already sitting in the same R2
bucket, produced by scripts/geonames/geonames_parse_to_R2.py's automated
GeoNames refresh job, most recently run 2026-09-01) carry the identical
225-row "nan" defect and the identical float-accuracy defect below.
The bug is in the shared ingestion script
(clean_and_normalize/df.to_csv in geonames_parse_to_R2.py never
.fillna('')s the postal-code frame the way it does for
alternatenames), not something specific to the currently-shipped cn.csv
snapshot. This audit is scoped to CN only, so I have not checked whether
other countries' shipped files inherit the same bug from the same script —
flagging it as a likely-systemic root cause, not asserting its blast
radius.
Defect B — accuracy is float-formatted (612 rows 4.0, 1,726 rows 1.0, 1 row 3.0, 13 blank)
Same class of bug already fixed-forward in datasets/lk/scripts/publish_r2.py
(if r["accuracy"].endswith(".0"): abort) and flagged in the CH audit.
GeoNames' own file has plain integers (4, 1, 3); the R2 file has
4.0, 1.0, 3.0.
Defect C — admin_code1 is GeoNames' own internal ordinal, not any real China admin code
All 31 distinct admin_code1 values in the file are 1–33 (skipping 17
and 27) — a GeoNames-internal sequential enumeration in roughly the order
GeoNames itself lists provinces, e.g. 1=Anhui, 2=Zhejiang, 22=Beijing, 31=Hainan, 33=Chongqing. This does not match either of China's two real
numbering schemes:
- ISO 3166-2:CN — two-digit codes derived from GB/T 2260 (e.g.
CN-11Beijing,CN-12Tianjin,CN-34Anhui,CN-46Hainan,CN-50Chongqing). - GB/T 2260 itself — the same two-digit province prefix used inside the 6-digit county code.
Under either real scheme Anhui is 34/CN-34, not GeoNames' 1; Beijing
is 11/CN-11, not GeoNames' 22. This is the standard GeoNames
admin-code "false friend" this project has flagged repeatedly elsewhere —
China is not an exception the way Switzerland turned out to be.
Defect D — admin_code2 is a mix of a real (truncated) official code and, for 79 rows, a GeoNames internal ID with no administrative meaning at all
For the 2,271 rows that have a normal prefecture layer, admin_code2
(e.g. 3401 for Hefei-Shi under Anhui) lines up with the first four
digits of the real GB/T 2260 prefecture code (Hefei's actual code is
340100) — genuinely informative, just truncated and float-suffixed
(3401.0).
But for 79 rows — the four direct-administered municipalities (Beijing,
Tianjin, Shanghai, Chongqing) and a set of county-level cities/districts
that sit directly under their province with no intervening prefecture
(e.g. Shennongjia, Xiantao, Tianmen, Qianjiang in Hubei; Wujiaqu in
Xinjiang; Jiyuan in Henan) — GeoNames has no 4-digit prefecture code to
put there, and falls back to its own internal 7–8 digit geonameId
(e.g. Beijing → 11876380, Chongqing → 8739734, Shennongjia →
1795614). These numbers are meaningless as administrative codes — they
are GeoNames' own gazetteer row IDs — but nothing in the file distinguishes
them from the genuine truncated GB/T 2260 codes in the other 2,271 rows
except length. A consumer treating admin_code2 as a uniform administrative
code column would silently ingest 79 fake codes alongside 2,271 real
(if truncated) ones.
Defect E — the free/sample distribution channel is cleaner than the paid file
https://postal.datahub.io/cn/cn.csv (the public sample referenced by
README.md's "first 100 rows" claim, and matching datapackage.yml's
bytes: 9241 figure closely — live fetch returned 9,199 bytes / 100 rows,
last-modified: 2026-07-30, same day as the full R2 object) does not
carry the literal "nan" string — those cells are genuinely empty in the
sample. A row-for-row diff of the sample against the first 100 rows of
the paid cn/cn.csv shows every other field identical; only the "nan"
cells differ. The paying customer's file is measurably lower quality
than the free sample the same customer evaluates before buying. This
is worth fixing regardless of what source is used going forward.
Verdict on the current file: it is a legitimate-if-defective GeoNames
CC BY 4.0 extract of what is itself a heavily-truncated GeoNames China
dataset (prefecture/county granularity ending in 00, never real 6-digit
township codes), carrying four packaging defects (nan strings,
float-formatted accuracy, GeoNames-internal admin_code1, and 79 rows of
GeoNames-internal admin_code2 masquerading as administrative codes) on
top of a source-level granularity ceiling that no repackaging of GeoNames
can lift.
2. Coverage note — no conflation of Hong Kong / Macau / Taiwan found (disclosure only, not a judgment call)
Checked explicitly, as requested. The current file contains zero rows
for Hong Kong, Macau, or Taiwan — no admin_name1 value matches any of
those names, and GeoNames itself carries them under separate country
files (HK.txt, TW.txt; Macau has no ZIP entry in GeoNames' postal
export at all). So the existing product does not conflate them with
mainland administrative structure — it simply omits them entirely, which
is consistent with how GeoNames scopes its own CN.txt (31 mainland
province-level divisions only).
Stated factually, without taking a position on the underlying status question: these three are administered under postal/administrative systems that are procedurally distinct from mainland China's GB/T 2260 + China Post scheme, not variants of it:
- Hong Kong has no postal code system in ordinary civilian use;
Hongkong Post's own guidance is to leave the postcode field blank.
Mainland China's own postal system reserves a placeholder code
999077for mail addressed to Hong Kong from the mainland, but this is not a real Hong Kong postcode and Hongkong Post does not use it. - Macau likewise has no postal code system; Macao Post (CTT) routes
by descriptive street/building/floor address only. A
999078placeholder exists in the same mainland-originated scheme, similarly not used by Macau's own carrier. - Taiwan has its own real, actively-administered postal code system
run by Chunghwa Post (3-digit from 1970, 3+2-digit from 1985, current
3+3-digit format since 2020-03-03), entirely independent of GB/T 2260.
A code range in the mainland's own numbering (
000000–009999) was nominally reserved for "Taiwan" in the PRC scheme but is not populated or used; mail between the mainland and Taiwan is handled with Taiwan's own codes.
If a future build for CN is scoped to include any of these three, the schema/licensing/source questions would need to be worked out separately for each — they are not a drop-in extension of the mainland admin hierarchy this file uses.
3. Official tier-1/2 sources checked FIRST, per the standing GeoNames-is-fallback rule
China Post (11185.cn / chinapost.com.cn) — checked, no bulk channel found
11185.cn(China Post's consumer site) anddey.11185.cn(its postcode lookup tool) expose single-address lookup only — type an address, get one postcode back. No bulk download, no public API, no open-data section found.data.chinapost.com.cn— China Post Group's own "data center" domain, the most plausible candidate for an official bulk channel — is currently unreachable (DNS does not resolve). Cannot confirm it ever offered public downloads, only that nothing is there now.- No terms-of-use text could be retrieved from China Post's own domains in this pass (fetch failures on the JS-heavy pages), so no licence posture is confirmed for China Post as a source, on top of the fact that no bulk data was found there to license in the first place.
Conclusion: no confirmed official/tier-1 postal-code bulk source exists. This is a genuine gap, not a "we didn't look" gap — unlike CH, KOR, or PHL where an official channel existed and just hadn't been used yet, China Post does not appear to publish one at all.
National Bureau of Statistics (NBS, stats.gov.cn) — CONFIRMED, real official admin-code source, but ADMIN ONLY, not postal
https://www.stats.gov.cn/sj/tjbz/tjyqhdmhcxhfdm/2023/— "2023年统计用区划代码和城乡划分代码" (2023 Statistical Administrative Division Codes and Urban-Rural Classification Codes), NBS's own annually-republished crosswalk.- Format: a 12-digit statistical division code (province/prefecture/ county/township/village) whose first 6 digits are the classic GB/T 2260 province+prefecture+county code, plus a 3-digit urban/rural classification suffix. Delivered as an HTML drill-down directory tree (province → prefecture → county → township pages), not a single downloadable file.
- Scope: 31 mainland province-level divisions — explicitly excludes Taiwan, Hong Kong SAR, and Macao SAR from this statistical series (a separate, independent confirmation of §2, from the admin-code side rather than the postal side).
- Licence/terms (from NBS's own terms-of-service page,
stats.gov.cn/wzgl/202302/t20230217_1912857.html): content is copyrighted by NBS; reuse/reprinting is permitted if attributed back to stats.gov.cn, not distorted, and used for legitimate/good-faith informational purposes. This is a permissive-with-attribution posture, not a formal open licence — no SPDX identifier applies. Per this project's provenance-gate convention, anylicence_statusbuilt on this source should use acustom:id (e.g.custom:nbs-stats-gov-cn-terms) anddecision: "unresolved"until a human confirms that posture is acceptable for a resold commercial product — NBS's own language ("legitimate purposes," no explicit commercial-resale carve-out) is not self-evidently compatible with reselling the derived crosswalk at a $49–99 tier. - This would only ever solve the admin-code side. GB/T 2260 codes
reach province/prefecture/county; NBS's data does not itself contain
postal codes, so it cannot fix the GeoNames postal-granularity ceiling
in §1 — it could only replace the fake
admin_code1/partially-fakeadmin_code2values with the real ones, joined against whatever postal layer is used.
GitHub community repos — evaluated, none are primary sources, licensing is mixed/absent
Checked via gh api for reliable licence metadata (README claims alone
were not trusted):
| Repo | Contains | Licence | Notes |
|---|---|---|---|
| tombcato/china-zipcode-data | Postal codes ↔ admin (adcode) | MIT | Most current (pushed 2026-02-13); states it's revised to 2023 NBS admin codes, but itself credits Amap + other GitHub projects as sources — a re-aggregation, not primary |
| mumuy/data_post | 6-digit postal codes, 4-tier down to delivery office | MIT | Pushed 2024-05-28, no stated primary source |
| khaeru/gb2260 | GB/T 2260 admin codes only | GPLv3 (in-repo, not GitHub-detected) | Sources from the same NBS page above; stale (2018) |
| grezbo/cn_zipcode | Postal codes → admin | none declared | Claims 800k+ rows, explicitly "scraped from the web"; stale (2015) |
| phoenixgao/ChinaPostcodes | Postcodes | Unlicense | Stale (2016), not verified in depth |
| CallMeNP/GB2260 | Admin codes, multi-year historical | none declared | Stale (2019) |
None of these is a primary/official source. The best-licensed and most current one (tombcato, MIT) is itself downstream of Amap (a Chinese commercial mapping company) and unnamed "other GitHub projects" — using it would mean reselling a re-aggregation of an unlicensed upstream, which this project's provenance gate treats as unresolved at best. A for-sale commercial dataset ("170万条邮政编码信息" / ~1.7M postal-code records, Access database, jamesqi.com) also surfaced in search — not evaluated further, as it is a paid third-party product, not a research source to verify against.
4. What this means for the current product
- The granularity ceiling is real and cannot be fixed by rebuilding
against GeoNames. GeoNames' China export is capped at "first digits +
00" by GeoNames' own admission — no amount of re-processing produces real 6-digit township codes from it. - No official tier-1 bulk postal source was found to replace it with. China Post appears not to publish one; its most likely data-center domain is dead.
- A real official tier-2 admin-code source exists (NBS GB/T 2260/
statistical codes) but only fixes the admin-code columns, not the
postal-code granularity, and its own reuse terms are permissive-
with-attribution rather than a clean open licence — would need explicit
decisionsign-off before use in a resold product, not an automatic "compatible." - Every community postal-code repo checked is either unlicensed or is itself a re-aggregation of unlicensed/commercial upstreams (Amap and others) — none is a clean substitute source.
- Independent of any sourcing decision, defects A/B/C/D/E above are pure packaging bugs (nan-strings, float-accuracy, fake admin codes passed through unlabeled, a worse-quality paid file than the free sample) that should not survive any republish of this file regardless of which source is ultimately used.
Verdict
This is not a "GeoNames is good enough" case, and it is also not a
straightforward "here is the official upgrade" case like CH. China
differs from Switzerland in the opposite direction: GeoNames' own China
coverage is source-capped at prefecture/county-level truncated codes, no
confirmed official bulk postal source exists to replace it with, and the
one confirmed official source that does exist (NBS) covers admin codes
only, not postal codes, under attribution-only terms that still need a
human licensing decision before resale. A rebuild would raise data
correctness (fix defects A–D, drop or clearly label the 79 fake
admin_code2 values, fix Defect E) without being able to raise data
granularity — that would require either an unverified/unlicensed
community aggregation or a commercial third-party purchase, both outside
what this audit was scoped to resolve.
Not done in this pass, by design: no script written, no
datapackage.yml change, no R2 write, no git commit. This file is the
audit record only.
Build, 2026-09-17 — packaging fix (local only, not published)
Rebuilt per the plan above. datasets/cn/scripts/build_postal_codes_product.py
downloads https://download.geonames.org/export/zip/CN.zip fresh
(2,352 rows, matches the audit exactly) and writes
datasets/cn/data/{cn.csv, datapackage.json, README.md, ATTRIBUTION.txt, cn.zip} directly with csv (no pandas), so none of the shared script's
bugs can reappear.
Coverage: unchanged, 2,352 rows, same GeoNames source. This was a
packaging fix, not a granularity upgrade, per the task scope — every
postal_code still ends in 00 (source-level truncation, confirmed
again: all 2,352 rows end 00).
Defect A ("nan" strings) — fixed, and not present in this build's own
output pipeline. Reading GeoNames' raw tab file directly with csv
never introduces a pandas NaN → str() conversion, so the 225 originally-
blank admin_name3 rows stay genuinely empty. A belt-and-braces guard
(if value == "nan": value = "") and a post-write assertion are in the
script anyway, in case a future edit reintroduces pandas.
Defect B (float-formatted accuracy) — fixed, same reasoning. The raw
GeoNames file already has plain integers (4, 1, 3, or blank); this
build never coerces through a numeric dtype, so no .0 suffix appears.
Guarded with the same belt-and-braces strip + assertion.
Defect C (admin_code1) — fixed via a verified NAME-based crosswalk,
with one important correction to the audit's own framing. Fetched
en.wikipedia.org/wiki/ISO_3166-2:CN directly on 2026-09-17, including
its "Changes" history section. Finding: ISO 3166-2:CN's numeric codes
(CN-11, CN-34, …, which do match GB/T 2260's province digits) were
superseded on 2017-11-23 by the current alpha-2 codes (CN-BJ, CN-AH,
…). The audit's illustrative example ("real Beijing=CN-11 … real
Anhui=CN-34") was correct for the pre-2017 numeric standard but is not
the code ISO 3166-2:CN uses today. Per the task's own instruction to
verify against the live Wikipedia page rather than assume, and consistent
with this project's standing rule to confirm current ISO registers rather
than carry forward an assumed one (see the IDN registry row in CLAUDE.md),
this build ships the current alpha form — e.g. CN-BJ (Beijing),
CN-AH (Anhui) — as the real, verified ISO 3166-2:CN code. All 31 mainland
province-level names present in the GeoNames source matched the crosswalk
with zero unmapped names. GeoNames' own admin_code1 (an internal 1–33
ordinal) matches neither the current alpha codes nor the superseded
numeric ones — confirmed false-friend, now fixed either way you read the
audit's claim.
Defect D (admin_code2) — fixed by digit-count detection, not by
NBS join. Confirmed 2,271 rows carry a genuine 4-digit truncated GB/T
2260 prefecture code (kept as-is) and exactly 79 rows carry a 7–8
digit GeoNames-internal geonameId instead (Beijing, Tianjin, Shanghai,
Chongqing, plus Shennongjia/Xiantao/Tianmen/Qianjiang/Jiyuan/Wujiaqu/
Shihezi) — matches the audit's count exactly. These 79 are now blanked
(admin_code2 = ""), disclosed by name in ATTRIBUTION.txt, rather than
shipped as a fake-looking administrative code. 2 rows had no
admin_code2 in the source to begin with and remain blank. No NBS data
was fetched or joined — that source's licensing remains unresolved per
§3 of the audit and was correctly out of scope for a packaging-only fix.
Defect E (paid file worse than free sample) — resolved as a side effect. This rebuild's output has none of defects A/B, so the paid file is no longer measurably worse than the free sample on those fields.
Coverage disclosure (§2 of the audit) — carried into ATTRIBUTION.txt and README.md verbatim as a factual coverage-boundary statement: zero HK/ Macau/Taiwan rows, GeoNames scopes them as separate files, no position taken on the underlying status question.
Validation: frictionless validate datapackage.json run from inside
datasets/cn/data/ (the delivered artifact, not a working copy) →
VALID. Post-write script assertions also confirm: 0 "nan" leaks, 0
float-formatted accuracy values, 0 non-4-digit admin_code2 values, 0
malformed admin_code1 values, 0 duplicate (postal_code, place_name)
pairs, exactly 79 blanked admin_code2 rows.
Local only, as instructed: no R2 upload, no git commit, no changes to
_meta/catalog.json or datapackage.yml. Only
datasets/cn/scripts/build_postal_codes_product.py,
datasets/cn/sources/postal_raw/{CN.txt,CN.zip,readme.txt},
datasets/cn/data/*, and this note were touched.