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 Morocco, MA
| 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
- 106 kB
About this dataset
Morocco (MA) — internal licensing notes
Source research, 2026-09-17 — first proper audit of this country
No .licensing-notes.md existed for MA before this pass. datapackage.yml
carries the same old-style placeholder already flagged elsewhere in this
project (sources: [{title: "Multiple sources", path: https://datahub.io/collections/postal-codes-datasets}], see
feedback_datapackage_no_sources) and no licenses: array or
licence_status block at all. README.md claims the data is "sourced from
official and publicly available records" — a generic, unverified claim.
The datapackage.yml resource metadata is also stale on basic facts: it
declares bytes: 9268 and modified: '2024-11-07', but the file actually
live on R2 is 107,941 bytes and was last written 2026-07-30 — the
descriptor was never regenerated against the real object.
Audit scope note: research/audit only. No R2 write, no git commit, no
datapackage.yml change, no .env value printed. Same ground rules as the
CH/PR/CO audits this pass follows.
1. What the current R2 file (ma/ma.csv, 107,941 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). 1,325 data
rows + header.
Listing the ma/ prefix also shows the automated monthly GeoNames job is
already running against this country and landing in the same bucket:
ma/ma.csv 107941 bytes 2026-07-30 <- the shipped product
ma/geonames/latest/0.csv 107941 bytes 2026-09-01 <- monthly job output
ma/geonames/2026-09-01/0.csv 107941 bytes 2026-09-01 <- same, dated
Byte-identical sizes across the shipped file and the current monthly
GeoNames pull confirm ma/ma.csv is (and continues to be) sourced from
scripts/geonames/geonames_parse_to_R2.py, the same shared script that
produces every other {cc}/geonames/latest/0.csv in this bucket.
Fetched https://download.geonames.org/export/zip/MA.zip (CC BY 4.0)
directly for comparison: MA.txt also has exactly 1,325 rows, and a
row-by-row diff confirms the R2 file is a straight tab-to-comma
conversion of raw GeoNames MA.txt, run through
geonames_parse_to_R2.py, with that script's own transforms visible:
GeoNames: MA 32000 Al Hoceima Tanger-Tetouan-Al Hoceima 01 Al-Hoceima 051 35.2516 -3.9372 4
R2 file: MA,32000,Al Hoceima,Tanger Tetouan Al Hoceima,1,Al Hoceima,51,nan,,35.2516,-3.9372,4,Al Hoceima
Confirmed defects, all traced to scripts/geonames/geonames_parse_to_R2.py
-
Literal string
"nan"inadmin_name3on every single row (1,325/1,325). GeoNames' ownMA.txtleavesadmin name3/admin code3blank for Morocco (no locality/community tier is supplied) — a genuinely empty tab field.pd.read_csv()reads that asNaN; the script'sclean_and_normalize()then doesdf[column].astype(str)onadmin_name3before checking for null, which stringifiesNaNto the literal four-character text"nan", and the following regex steps (which only strip parens and non-word characters) do not remove it because"nan"contains only word characters. This is the exact defect class already flagged in this project'spostal_codes CSV typingreference note, just manifesting on a name field instead of a numeric one. Every downstream consumer seesadmin_name3as the 4-country town "Nan" rather than empty. -
admin_code1andadmin_code2lose their leading zeros. GeoNames' raw values are zero-padded strings —01..12foradmin_code1,051/121/066etc. foradmin_code2. The script'sadd_leading_zero()re-pad step is applied only topostal_code(line 176-177 ofgeonames_parse_to_R2.py);admin_code1/admin_code2pass throughpd.read_csv()with nodtype=str, so pandas infers them as integers and the leading zero is silently dropped ("01"→1,"051"→51). This matters concretely here (see §2):01is the real ISO 3166-2:MA region suffix, so the shipped value fails to match the official code as published, even though the correct digits are present. -
admin_code2values (e.g.1,51,301,311) are GeoNames- internal sequence numbers, not an official Moroccan province code. Morocco's ISO 3166-2 register defines codes only at the 12-region level (confirmed against Wikipedia's ISO 3166-2:MA table, see §2) — there is no ISO, HCP, or other official numeric code for the 82 provinces/prefectures, so there is no official replacement value to substitute; the honest fix is to stop presenting these numbers as if they were an administrative code (drop the column or clearly label itgeonames_internal). -
admin_name2carries inconsistent, unfiltered GeoNames gazetteer naming — e.g.Settat Province,Khouribga Province,Kelaa Des Sraghna(missing article/accents) alongside plain names likeFes,Nadorwith no suffix — i.e. some province names carry a literal "Province" suffix and most don't, an artefact of GeoNames' own admin2 name field rather than something introduced by this project's script. -
alternative_city_nameis low-value GeoNames alternate-name noise, not a curated alias list: 455/1,325 rows have a value, and a large share of them either just repeatplace_nameverbatim (Al Hoceima→Al Hoceima) or supply a French administrative-unit gloss rather than a real alternate spelling (Izemmouren→Caidat d'Izemmouren,Rouadi→Caidat de Rouadi) — same failure mode already documented for CH'salternative_city_name, caused by the sameget_non_numerical_name()/ asciiname-keyed dict-merge logic in the shared script.
No float-formatted accuracy bug here (unlike CH) — accuracy values
are clean 1 / 4 strings in both the raw GeoNames file and the R2 file,
matching GeoNames' documented scale (1=estimated, 4=geonameid). No
duplicate (postal_code, place_name) pairs; postal_code itself is not
affected by the leading-zero bug (Morocco's postal codes are 5 digits with
no leading zero to lose).
Verdict on the current file: a raw, unmodified-content GeoNames CC BY 4.0
extract from a stale underlying vintage (see §3), degraded further in
packaging by the shared script's admin_name3→"nan"-string bug and the
admin_code1/admin_code2 zero-stripping bug. Not fabricated data, but
materially worse than what Morocco's own postal authority currently
publishes for free.
2. ISO 3166-2:MA region codes — VERIFIED against Wikipedia
Morocco has 12 regions, each with an official two-digit ISO 3166-2:MA code (region reorganisation per Decree No. 2.15.10, 20 Feb 2015):
| Code | Region |
|---|---|
| MA-01 | Tanger-Tétouan-Al Hoceïma |
| MA-02 | L'Oriental |
| MA-03 | Fès-Meknès |
| MA-04 | Rabat-Salé-Kénitra |
| MA-05 | Béni Mellal-Khénifra |
| MA-06 | Casablanca-Settat |
| MA-07 | Marrakech-Safi |
| MA-08 | Drâa-Tafilalet |
| MA-09 | Souss-Massa |
| MA-10 | Guelmim-Oued Noun |
| MA-11 | Laâyoune-Sakia El Hamra |
| MA-12 | Dakhla-Oued Ed-Dahab |
GeoNames' admin_code1 for Morocco (01..12 in the raw file) is
genuinely the real ISO 3166-2:MA numeric suffix — not a false-friend
internal code, matching the CH finding that GeoNames sometimes gets
admin1 right. The defect is entirely downstream: the R2 file strips the
leading zero (1 instead of 01), so a consumer matching against the
published ISO list byte-for-byte gets zero hits unless they re-pad it
first. This should be fixed regardless of which postal source is used —
it is a pure packaging bug on a field GeoNames already got right.
admin_code2 (province) has no ISO or other official numeric code to
fall back on — see defect 3 above.
3. Official tier-1/2 sources checked FIRST, per the standing GeoNames-is-fallback rule
Barid Al-Maghrib / Poste Maroc, via Morocco's national open data portal (data.gov.ma) — CONFIRMED, and it is a real upgrade
Morocco's postal operator publishes its own postal-code reference data
directly on data.gov.ma (organisation: poste-maroc), under the
"Codes postaux des localités" dataset. Confirmed licence on the
dataset page: Open Data Commons Open Database License (ODbL),
data.gov.ma's stated "Open Definition"-compliant licence for this
resource. (ODbL is share-alike, same family as OSM's licence — flag for a
licence decision before shipping, per the OSM/ODbL gate philosophy in this
project's standing rules, even though this is a different upstream than
OSM.)
Fetched and inspected all four resources directly:
| Resource | Format | Rows (data) | Notes |
|---|---|---|---|
codes-postaux-des-localites-fev-2011-...csv | CSV | 1,325 | This is what GeoNames' MA.txt — and therefore the current R2 file — is built from. Row count matches exactly; columns are REGION_POSTALE, PROVINCE, LOCALITE, NOUVEAU CODE POSTAL. |
codes-postaux-des-localites-postemaroc-fev-2011.xls | XLS | 1,325 | Same 2011 vintage, alternate format. |
codes-postaux-localites-2018.xlsx | XLSX | 1,773 | The postal authority's own 2018 update — 448 more rows than 2011, 1,770 distinct postal codes vs. 1,325 today. |
codes-postaux-des-villes-2018.xlsx | XLSX | 34 | "Multi-code cities" index (large cities like Agadir, Casablanca, Fès with more than one postal code) — locality names only, cross-referenced against the main 2018 file rather than carrying codes itself. |
This is a materially better, currently-unused, freely-licensed source:
- The shipped product is running ~7 years stale. Comparing distinct postal codes: 463 codes exist in the 2018 official file that are absent from the 2011 file GeoNames (and therefore this project) currently serves; 18 codes present in 2011 were retired/renumbered by 2018 and no longer appear.
- The 2018 file uses the real, current (post-2015-reform) region names
directly from the postal authority (
BENI MELLAL KHENIFRA,SOUSS MASSA,TANGER TETOUAN AL HOCEIMA, etc.) matching the 12 ISO regions in §2 — with one labelling defect in the source itself, noted honestly rather than silently fixed: 3 rows are taggedGRAND CASABLANCA SETTAT(a name that does not correspond to any of the 12 official regions) for provinces (Sidi Bennour, Benslimane, Berrechid) that appear correctly under plainCASABLANCA SETTATelsewhere in the same file — an apparent data-entry inconsistency in Poste Maroc's own spreadsheet, not something introduced by this project. A rebuild would need to normalise those 3 rows. - Real province names, not a GeoNames-internal number — the 2018 file gives 82 named provinces/prefectures directly, which is the intended fix for defect 3 above (there is still no official numeric province code, but the name itself would be authoritative rather than GeoNames-derived).
- Publisher-declared update history is transparent: dataset page shows "last modified 2021-12-13", data current to September 2018 — older than ideal, but still a full postal-authority refresh cycle ahead of what ships today.
Licence caveat to resolve before any rebuild, not resolved in this
pass: ODbL is a share-alike licence. Whether that is compatible with
this product's resale model (the postal-codes R2/datahub.io channel,
where — per this project's own standing rule — attribution/licence
disclosure is required and expected, unlike the FedEx delivery-folder
product) needs a licence_status decision (decision: "unresolved" is
the correct interim state) rather than silent adoption. This is a
materially different situation from the GeoNames CC BY 4.0 baseline
(attribution-only, no share-alike) currently implied by the unshipped
licenses block.
HCP (Haut-Commissariat au Plan) — CONFIRMED as the tier-2 admin reference, not fetched row-by-row this pass
HCP publishes the official administrative structure and, most recently,
population counts by region/province/prefecture/commune from the 2024
census (Decree No. 2.24.1009, adopted per HCP's own site, resources at
hcp.ma). The 12-region structure itself traces to Decree No. 2.15.10
(20 February 2015) — the same regions independently confirmed via
Wikipedia's ISO 3166-2:MA table in §2, so the two sources agree. HCP also
publishes commune-level administrative boundary/reference files
("Découpage administratif", "Maroc des régions" downloads). Licensing
terms for HCP's own downloads were not fetched/verified in this pass —
would need checking before use, same as any new official source.
4. Disputed-territory disclosure — Western Sahara, factual only, no determination made
Both the currently shipped file and Poste Maroc's own 2018 update assign postal codes to localities inside Western Sahara, a territory whose sovereignty is internationally disputed (administered by Morocco over roughly 80% of the territory since 1975-76; also claimed by the Sahrawi Arab Democratic Republic / Polisario Front; the UN continues to list Western Sahara as a Non-Self-Governing Territory and MINURSO maintains an active mandate there).
In the currently shipped R2 file: 9 of 1,325 rows carry admin_code1
11 (Laâyoune Sakia El Hamra, 7 rows: Boujdour, Es-Semara, Foum El Oued,
Dcheira Tafoudart, Tarfaya, Daoura, Akhfennir) or 12 (Dakhla Oued Ed Dahab, 2 rows: Aousserd, Dakhla) — all under country_code: MA, with no
separate flag or EH (Western Sahara's own ISO 3166-1 code) anywhere in
the file.
In Poste Maroc's own 2018 update, this grows to 31 of 1,773 rows (18
under LAAYOUNE SAKIA EL HAMRA, 13 under DAKHLA OUED EDDAHAB) — the
postal authority's own current reference data assigns these localities
Moroccan postal codes and Moroccan region/province names on exactly the
same footing as undisputed Moroccan territory, with no distinguishing
marker.
GeoNames itself has no separate EH.zip/EH.txt postal file — Western
Saharan localities exist in GeoNames' data only via MA.txt, i.e. GeoNames
also treats them as part of Morocco for postal-code purposes, not as a
separate entity.
Note on Tarfaya specifically, for anyone relying on this note later:
Tarfaya sits just north of the Western Sahara territory as usually defined
(it reverted to Morocco in 1958, well before the 1975-76 Spanish
withdrawal that created the modern dispute over the territory to its
south), yet both sources file it under the Laâyoune-Sakia El Hamra
region, which straddles undisputed Morocco and disputed Western Sahara —
worth knowing if a future pass wants a locality-level rather than
region-level disputed-territory flag.
No determination is made here about sovereignty. This section records, factually, what both the current file and its likely replacement contain, following the same neutral disclose-don't-decide treatment already used in this project for Crimea/Sevastopol (Russia) and Israel's disputed territories: if a rebuild happens, this fact should be disclosed in the delivered dataset's documentation (a factual note that these localities' Moroccan administrative assignment reflects Morocco's own postal/civil administration and is disputed internationally), not silently carried or silently stripped.
Verdict
A real official upgrade exists and is not currently used. This is not a "GeoNames is good enough" case: Barid Al-Maghrib publishes its own postal-code reference data on Morocco's national open data portal, it is directly fetchable, it is ~7 years newer than the vintage GeoNames (and therefore this project) currently serves, it carries 448 more distinct postal codes, and it uses the real post-2015-reform region names instead of a GeoNames-internal numbering scheme for at least the region tier.
Concrete defects in what ships today, independent of which source is used going forward:
admin_name3is the literal string"nan"on 100% of rows — apd.read_csv()/astype(str)ordering bug in the sharedgeonames_parse_to_R2.pyscript.admin_code1(1-12) is missing its leading zero relative to the real ISO 3166-2:MA code (01-12) — same script,add_leading_zero()applied only topostal_code, not to the admin code columns.admin_code2is a GeoNames-internal sequence number mislabeled as an administrative code column; no official province-level numeric code exists to replace it with (only province names are official).datapackage.ymlresource metadata (bytes: 9268,modified: '2024-11-07') does not match the live R2 object (107,941 bytes, 2026-07-30) — stale even on basic file facts, independent of any licensing question.- No
licence_status, nolicensesarray, no sourcing disclosure anywhere in the shipped metadata — the same gap already found and fixed for other countries in this project's 2026-09 audit pass.
Recommended next step (not executed in this pass — research/audit only):
- Rebuild from Barid Al-Maghrib's
codes-postaux-localites-2018.xlsxas the postal_code/place_name/region/province backbone, normalising the 3GRAND CASABLANCA SETTATrows toCASABLANCA SETTAT. - Re-pad
admin_code1to the real ISO 3166-2:MA two-digit form (01-12) if a GeoNames-derived region tier is kept at all, or map directly from the 12 official region names in §2. - Drop or clearly relabel
admin_code2— there is no official numeric code at province level to ship in its place. - Fix the
admin_name3/"nan"-string bug at the source (the sharedgeonames_parse_to_R2.pyscript), or, if the postal authority's own file is adopted instead, note that it has no locality/community tier either (2018 file stops at province+locality, same as GeoNames) — soadmin_name3should ship empty, never"nan". - Resolve the ODbL licence question explicitly
(
custom:data-gov-ma-odblor similar,decision: "unresolved"until a human signs off,channel: "postal-codes-r2") before any republish — do not silently carry forward the GeoNames CC BY 4.0 assumption implied by the current unshippedsourcesplaceholder, since the better source has a different, share-alike licence. - Disclose the Western Sahara postal-code inclusion factually in any rebuild's documentation, per §4 — do not silently drop or silently ship those rows without a note either way.
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, GeoNames only, local only
Per explicit instruction: this is a packaging fix on GeoNames (CC BY
4.0), NOT a source upgrade. Poste Maroc's richer 2018 dataset
(codes-postaux-localites-2018.xlsx, 1,773 rows, ODbL) was deliberately
not used — that licence question stays unresolved pending an
explicit human decision, out of scope here. Local build only: no R2
upload, no git commit/push, _meta/catalog.json and datapackage.yml
left untouched.
Fetched https://download.geonames.org/export/zip/MA.zip fresh —
1,325 rows, matching the expected count and the audit above exactly.
Wrote datasets/ma/scripts/build_postal_codes_product.py (csv module
only, no pandas — modelled on datasets/ke/ and datasets/lk/'s build
scripts). Confirmed against the raw tab-delimited source before any
transform:
admin_code1in the raw file is already zero-padded (^\d{2}$, 01–12) and already the genuine ISO 3166-2:MA region code (§2 above) — no crosswalk needed, only re-padding + anMA-prefix (MA-01..MA-12).admin_code2in the raw file is already zero-padded (^\d{3}$) — the only reason it lost its zero in the previously shipped file waspd.read_csv()with nodtype=strin the sharedgeonames_parse_to_R2.py. Reading withcsv.readeravoids that entirely. Value is kept unprefixed (not given anMA-/ISO-style prefix) and is labelled in the schema (datapackage.jsonfield description),README.md, andATTRIBUTION.txtas a "GeoNames-internal identifier, NOT an official Moroccan province code" — Morocco's ISO 3166-2:MA register only defines codes at region level, so there is no official value to substitute.admin_name3/admin_code3are genuinely blank in the raw source (asserted in the build script) —csv.readerpreserves that as"", never the literal string"nan".- Disputed-territory rows (Western Sahara localities under
MA-11Laâyoune-Sakia El Hamra andMA-12Dakhla-Oued Ed-Dahab) carried through completely unchanged — 9/1,325 rows, exactly matching the audit's count (7 under MA-11: Boujdour, Es-Semara, Foum El Oued, Dcheira Tafoudart, Tarfaya, Daoura, Akhfennir; 2 under MA-12: Aousserd, Dakhla). A neutral, factual disclosure paragraph was added toATTRIBUTION.txt(same disclose-don't-decide treatment as this project's Crimea/Sevastopol note in the Russia build) — no row added, removed, or modified.
Result: datasets/ma/data/ma.csv — 1,325 rows, 12/12 ISO regions
covered, 59 distinct admin_code2 values, 0 duplicate (postal_code, place_name) pairs, 0 literal "nan" strings, 0 float-formatted
accuracy values. licence_status.decision: compatible
(licence_id: CC-BY-4.0, channel: postal-codes-r2), with an explicit
note recording that the ODbL 2018 source exists and was deliberately
not adopted this pass.
Frictionless validation: run from inside datasets/ma/data/ against
datapackage.json (the delivered artifact, not the working copy) —
report.valid == True, 0 errors, 0 warnings.
Files written: datasets/ma/scripts/build_postal_codes_product.py,
datasets/ma/data/ma.csv, datasets/ma/data/datapackage.json,
datasets/ma/data/README.md, datasets/ma/data/ATTRIBUTION.txt,
datasets/ma/data/ma.zip. datasets/ma/sources/postal_raw/MA.txt and
readme.txt saved as the raw source snapshot. No other files touched.