Japanese Postal Code to Address Auto-Fill, Built From Japan Post's Free Data (No API Key)

2026-11-14来源 dev.toEnglish

In Japan, address forms start with the postal code (郵便番号). Users type 7 digits, and the prefecture, city and town fill in by themselves. When a form doesn't do this, Japanese users notice right away — it's one of the clearest signs that a checkout "wasn't made for Japan".

I'm a native Japanese developer and I built a checkout plugin for Japanese online stores, so I've written this feature more than once. You don't need a paid API or a third-party script on your checkout page. Japan Post publishes the data for free, and a small build step turns it into static JSON files.

This post covers the data, its quirks, a build script and the front-end code. (For the rest of a Japanese checkout form — name order, furigana, tax-included prices — see my earlier post: How to Build a Checkout Form That Works in Japan.)

1. The data: one CSV from Japan Post

Japan Post publishes the postal code data on its download page. Use the newer UTF-8, one-record-per-line file, utf_ken_all.zip (about 2 MB zipped). It has been published since the June 2023 update.

Why the newer file:

  • It's UTF-8. The classic KEN_ALL.CSV is Shift_JIS.
  • Each postal code is one line. In the classic file, long town names are split across several records, which you have to stitch back together.
  • Readings are full-width katakana (the classic file uses half-width).

About using it: Japan Post's readme says it does not claim copyright on the postal code data and that it may be freely distributed. Still, read the readme yourself before you ship.

The data is updated monthly, with add/delete diff files each month. More on updating at the end.

2. The columns you need

Each line has 15 columns. A row looks roughly like this:

13101,"100","1000001","トウキョウト","チヨダク","チヨダ","東京都","千代田区","千代田",0,0,0,0,0,0 

For auto-fill you only need four of them:

# Column Example
3 Postal code (7 digits) 1000001
7 Prefecture 東京都
8 City / ward 千代田区
9 Town 千代田

Columns 4–6 are the readings in katakana (handy if you also want furigana for addresses). Column 13 is a flag that means one postal code covers two or more towns — keep that case in mind, it comes back in section 5.

One more thing: open this file in Excel and the postal codes lose their leading zeros (0600042 becomes 600042). Always treat them as strings.

3. The quirks: town names that aren't town names

The town column isn't always a real town. Japan Post's readme lists a few special values:

  • 以下に掲載がない場合 ("if not listed below") — a catch-all code for the city. It does not identify a town.
  • ○○の次に番地がくる場合 — the block number comes directly after the city name.
  • ○○一円 — the whole municipality, with no town name.

Inserting any of these into a user's address is a bug. Clear them instead.

Town names can also have a note in full-width parentheses, such as 大通西(1~19丁目) ("Ōdōri-nishi, 1st–19th chōme"). The note describes which block numbers belong to the code; the user types their own block number anyway. Keep the part before (:

const cleanTown = (town) => { if (town === '以下に掲載がない場合') return ''; if (/の次に番地がくる場合$/.test(town)) return ''; if (/一円$/.test(town)) return ''; return town.replace(/(.*$/, ''); // "大通西(1~19丁目)" → "大通西" }; 

4. Build step: CSV → small JSON files

More than 100,000 lines is too much to send to every visitor. Split the data by the first three digits of the postal code. The browser then loads only the small file it needs, such as /zip/100.json.

// build-zip.mjs // Usage: node build-zip.mjs utf_ken_all.csv public/zip import { readFileSync, mkdirSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; const [, , csvPath, outDir] = process.argv; const cleanTown = (town) => { if (town === '以下に掲載がない場合') return ''; if (/の次に番地がくる場合$/.test(town)) return ''; if (/一円$/.test(town)) return ''; return town.replace(/(.*$/, ''); }; // Fields don't contain ASCII commas, so a plain split is enough here. // Use a CSV library if you want to be extra safe. const parseLine = (line) => line.split(',').map((f) => f.replace(/^"|"$/g, '')); const files = {}; // { "100": { "1000001": [["東京都", "千代田区", "千代田"]] } } for (const line of readFileSync(csvPath, 'utf8').split(/\r?\n/)) { if (!line) continue; const c = parseLine(line); const zip = c[2]; const entry = [c[6], c[7], cleanTown(c[8])]; const bucket = (files[zip.slice(0, 3)] ??= {}); const list = (bucket[zip] ??= []); // After cleaning, two rows can become identical — keep one. if (!list.some((e) => e.join() === entry.join())) list.push(entry); } mkdirSync(outDir, { recursive: true }); for (const [prefix, data] of Object.entries(files)) { writeFileSync(join(outDir, `${prefix}.json`), JSON.stringify(data)); } console.log(`${Object.keys(files).length} files written to ${outDir}`); 

Each postal code maps to a list, because one code can cover several towns. Serve the folder as static files — no server code, no API key.

5. The form: fill in, but don't fight the user

The HTML, with autocomplete attributes so browser autofill still works:

<label>郵便番号 <input name="postal_code" autocomplete="postal-code" inputmode="numeric" placeholder="123-4567"></label> <label>都道府県 <select name="prefecture" autocomplete="address-level1"> <option value="">選択してください</option> <option>北海道</option><option>青森県</option><!-- … all 47 … --> </select></label> <label>市区町村 <input name="city" autocomplete="address-level2"></label> <label>町名 <input name="town"></label> <label>番地 <input name="address_line1" autocomplete="address-line1"></label> <label>建物名・部屋番号 <input name="address_line2" autocomplete="address-line2"></label> 

(Many Japanese forms put the town at the start of the 番地 field instead of a separate field. Either works — keep it consistent with how you store addresses.)

The script:

const form = document.querySelector('form'); // "〒100-0001" → "1000001" (full-width digits, hyphens, the 〒 mark) const normalizeZip = (v) => v.normalize('NFKC').replace(/[^0-9]/g, ''); const cache = {}; async function lookup(zip) { const key = zip.slice(0, 3); cache[key] ??= fetch(`/zip/${key}.json`).then((r) => (r.ok ? r.json() : {})); return (await cache[key])[zip] ?? []; } // Never overwrite what the user typed themselves. const edited = new Set(); for (const name of ['prefecture', 'city', 'town']) { form.elements[name].addEventListener('input', () => edited.add(name)); } async function fill() { const zip = normalizeZip(form.elements.postal_code.value); if (zip.length !== 7) return; const hits = await lookup(zip); if (hits.length === 0) return; // unknown code: leave the fields alone const [prefecture, city, town] = hits[0]; const set = (name, value) => { if (!edited.has(name)) form.elements[name].value = value; }; set('prefecture', prefecture); set('city', city); // One code, several towns: don't guess. set('town', hits.length === 1 ? town : ''); form.elements.address_line1.focus(); // the user continues with the block number } form.elements.postal_code.addEventListener('input', fill); 

A few choices worth explaining:

  • Normalize first. Japanese keyboards often type full-width digits (123-4567). NFKC turns them into 123-4567, then we drop everything that isn't a digit. Don't show an error for full-width input — fix it.
  • Don't guess when there are several towns. If one code covers two or more towns, fill the prefecture and city only, and let the user type the town (or show the choices in a small list).
  • Don't overwrite. If the user has already corrected the city, a late lookup shouldn't put the old value back.
  • Move the cursor to 番地. After the auto-fill, the next thing the user types is the block number.
  • Unknown code = no change. Large businesses and PO boxes have their own postal codes in a separate Japan Post file, so a valid code can be missing from this data. Don't block the form; let the user type the address.

6. Keep it up to date

Postal codes change a little every month (city mergers, new developments, corrections). The simplest approach: re-download utf_ken_all.zip once a month and run the build again. A scheduled CI job works well for this. If you'd rather apply only the changes, Japan Post also publishes monthly add/delete files.

Checklist

  • [ ] Use utf_ken_all.zip (UTF-8, one record per line)
  • [ ] Treat postal codes as strings (leading zeros)
  • [ ] Clear 以下に掲載がない場合 / ○○の次に番地がくる場合 / ○○一円
  • [ ] Cut the (…) note from town names
  • [ ] One code can mean several towns — store a list, don't guess
  • [ ] Normalize input with NFKC; accept hyphens, full-width digits and 〒
  • [ ] Never overwrite fields the user edited; focus 番地 afterwards
  • [ ] Rebuild monthly

Postal-code auto-fill is a small feature, but it's the moment a Japanese user decides whether your form "gets it". The good news: it's an afternoon of work, with no API key and no runtime dependency.

If you're getting a product ready for Japan, there's a free 31-point checklist (language, names, addresses, checkout, layout and store pages): Free Japan-Ready Checklist. And if you'd like a native Japanese developer to look at your actual screens, I do reviews on Fiverr.

原文:https://www.a8q9.cn/en/article/japanese-postal-code-to-address-auto-fill-built-from-japan-post-s-free-data-no-a-d94a32.html

相关文章