# Vietnam Address Converter (2025 Administrative Reform) (`ducnv91/vietnam-address-converter`) Actor

Convert old Vietnamese addresses (63 provinces, 3 levels) to the new 34-province, 2-level units in force since 1 July 2025. Offline, fast, with ward codes, coordinates and split-ward warnings.

- **URL**: https://apify.com/ducnv91/vietnam-address-converter.md
- **Developed by:** [Đức Việt](https://apify.com/ducnv91) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 address converteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Vietnam Address Converter — old to new provinces and wards (2025 reform)

**Vietnam Address Converter** turns Vietnamese addresses written in the **old 3-level format** (63 provinces → district → ward) into the **new 2-level administrative units in force since 1 July 2025** (34 provinces → ward/commune). Paste a list of addresses, call it from the API, or point it at any Apify dataset. You get back the new ward and province, official codes, coordinates, and a clear warning whenever an old ward was split between several new wards.

> **Chuyển đổi địa chỉ Việt Nam cũ (63 tỉnh, có quận/huyện) sang đơn vị hành chính mới từ 1/7/2025 (34 tỉnh thành, 2 cấp, bỏ cấp huyện).** Hỗ trợ địa chỉ có dấu, không dấu, viết tắt (P., Q., TP HCM, Tx., TT., H.).

### What does Vietnam Address Converter do?

On 1 July 2025 Vietnam merged its 63 provinces into 34 and abolished the district level. More than 10,000 old wards and communes were consolidated into 3,321 new ones. Every CRM, delivery database, KYC record and scraped dataset collected before that date now holds addresses that no longer match official units.

This Actor fixes them in bulk:

| Old address | New address (from 1 July 2025) |
| --- | --- |
| `123 Lê Lợi, P. Bến Nghé, Q.1, HCM` | `123 Lê Lợi, Phường Sài Gòn, Thành phố Hồ Chí Minh` |
| `phuong 9 quan 3 tp hcm` | `Phường Nhiêu Lộc, Thành phố Hồ Chí Minh` |
| `TT. Phùng, H. Đan Phượng, Hà Nội` | `Xã Đan Phượng, Thành phố Hà Nội` |
| `Thôn 3, Xã Ea Kao, TP Buôn Ma Thuột, Đắk Lắk` | `Thôn 3, Phường Ea Kao, Tỉnh Đắk Lắk` |
| `Bình Dương` | `Thành phố Hồ Chí Minh` (province merged) |

### Why use it?

- ⚡ **Fast and fully offline**: 1,500–3,500 addresses per second. No calls to Google Maps or any geocoder, so results are deterministic and your data never leaves the run.
- 🎯 **Measured accuracy**: tested on every one of the 10,035 old wards: **100%** recognised with diacritics, **99.6%** without.
- 🧹 **Messy input welcome**: diacritics optional, abbreviations understood (`P.`, `Q.1`, `TP HCM`, `TP.HCM`, `Tx.`, `TT.`, `H.`), house numbers, alleys and floors kept as the street part, postal codes and "Việt Nam" ignored.
- 🔀 **Honest about ambiguity**: 4.7% of old wards were split. Those rows come back with `wardWasSplit: true`, `confidence: "medium"` and every possible new ward in `candidateNewWards`, instead of a silent guess.
- 🗺️ **District-only addresses**: if only the old district is readable (`KCN VSIP, Thuận An, Bình Dương`), you get the province plus the list of new wards that district now spans.
- 🔁 **Mixed datasets**: addresses already in the new format are recognised (`already_new`) and standardised.
- 🔗 **Chain with any scraper**: feed the dataset of a Google Maps, real-estate or e-commerce scraper and keep the original item for joining back.
- 🔒 **Limited permissions**: the Actor only reads the dataset you pick. Nothing else in your account is touched.
- 💸 **Pay only for results**: addresses that cannot be recognised at all are free.

### Who is it for?

- **E-commerce and logistics teams** updating shipping addresses and re-grouping orders, warehouses and delivery zones by the new provinces.
- **CRM, sales and marketing ops** cleaning customer and lead databases.
- **Fintech, banking and insurance** normalising KYC addresses.
- **Data engineers and analysts** standardising scraped Vietnamese business, property and job data before analysis.
- **Developers and AI agents** validating addresses in checkout or onboarding forms through the API or MCP.

### How to use it

1. Click **Try for free** (or **Start**).
2. Paste addresses into **Addresses**, one per line, **or** pick a dataset in **Or: dataset ID** and set **Address field** (dotted paths such as `location.address` work).
3. Click **Start**. Results appear in the **Output** tab in seconds. Download them as Excel, CSV, JSON or XML, or fetch them via the API.

#### Input example

```json
{
  "addresses": [
    "59 Nguyễn Thị Minh Khai, Phường Bến Thành, Quận 1, TP Hồ Chí Minh",
    "Số 10 ngõ 5 Láng Hạ, phường Thành Công, quận Ba Đình, Hà Nội"
  ]
}
```

Convert an existing dataset and keep each original item:

```json
{ "datasetId": "YOUR_DATASET_ID", "addressField": "location.address", "includeSourceItem": true }
```

| Field | Type | Description |
| --- | --- | --- |
| `addresses` | array of strings | Addresses to convert. |
| `datasetId` | dataset | Dataset to convert instead of, or in addition to, `addresses`. |
| `addressField` | string | Field holding the address in the dataset. Default `address`. |
| `includeSourceItem` | boolean | Copy the original dataset item into `sourceItem`. Default `false`. |
| `maxItems` | integer | Stop after this many addresses. `0` means no limit. |

### Output

One row per input address, in the same order (`index`):

```json
{
  "index": 1,
  "input": "Số 10 ngõ 5 Láng Hạ, phường Thành Công, quận Ba Đình, Hà Nội",
  "status": "converted",
  "confidence": "medium",
  "newAddress": "Số 10 Ngõ 5 Láng Hạ, Phường Giảng Võ, Thành phố Hà Nội",
  "street": "Số 10 Ngõ 5 Láng Hạ",
  "newWard": "Phường Giảng Võ",
  "newWardCode": "00025",
  "newProvince": "Thành phố Hà Nội",
  "newProvinceCode": "01",
  "latitude": 21.0275,
  "longitude": 105.814,
  "oldWard": "Phường Thành Công",
  "oldDistrict": "Quận Ba Đình",
  "oldProvince": "Thành phố Hà Nội",
  "oldWardCode": "00034",
  "oldDistrictCode": "001",
  "oldProvinceCode": "01",
  "wardWasSplit": true,
  "candidateNewWards": ["Phường Giảng Võ", "Phường Ô Chợ Dừa"],
  "error": null
}
```

| `status` | Meaning | Charged |
| --- | --- | --- |
| `converted` | Old ward found and mapped to its new ward. `confidence` is `high`, or `medium` if the old ward was split. | Yes |
| `already_new` | The address already uses the 2025 units; it was recognised and standardised. | Yes |
| `province_only` | Only the province could be determined. If the old district was readable, `candidateNewWards` lists the new wards it spans. | Yes |
| `not_found` | No Vietnamese administrative unit recognised. | **No** |

`latitude` and `longitude` are the centre of the new ward, not the exact street location. A run summary with counts per status is saved under `OUTPUT` in the key-value store.

### How much does it cost?

You pay **$2 per 1,000 converted addresses** ($0.002 each), and nothing for addresses that are not recognised. There is no extra platform-usage charge on top. Converting a 100,000-row customer table costs about $200 and finishes in a couple of minutes.

To cap spending, set **Maximum cost per run** in the run options. The Actor stops cleanly when the limit is reached and the results produced so far are kept.

### Integrations and API

- **API**: call `run-sync-get-dataset-items` to convert addresses and get the results in one HTTP request. See the **API** tab for ready-made code in Python, JavaScript and cURL.
- **No-code**: use the Apify integrations for **Make, n8n, Zapier**, Google Sheets and webhooks.
- **AI agents**: available through the Apify MCP server, so Claude, ChatGPT, Cursor and other MCP clients can convert addresses on request.
- **Scraper pipelines**: run it after a Google Maps or real-estate scraper with an Apify integration, passing the scraper's dataset as `datasetId`.

### FAQ

**Which official data is used?**
The mapping is the open, MIT-licensed [vietnamadminunits](https://github.com/tranngocminhhieu/vietnamadminunits) dataset, which follows the National Assembly and government resolutions on the 2025 reorganisation. Codes follow the official administrative unit codes.

**What happens when an old ward was split?**
You get the official default new ward in `newWard`, `confidence: "medium"`, and all possible new wards in `candidateNewWards`. Check the street if the exact ward matters, for example for legal documents.

**Does it verify that the street or house number exists?**
No. The street part is kept exactly as written. The Actor converts the administrative units only.

**Is my data stored or shared?**
No external service is called. Data stays in your own Apify run storage, under your account's retention settings.

**Can I convert addresses that are already in the new format?**
Yes. They come back as `already_new` with standardised names and codes, so mixed old and new data can go through in a single run.

### Limitations

- Split wards return the official default; see `candidateNewWards` for the alternatives.
- Very short or ambiguous inputs (only a ward name with no province) may not be resolvable and return `province_only` or `not_found`.
- Coordinates are ward centroids.

### Feedback and support

Found an address that was converted wrongly? Open an issue in the **Issues** tab with the input text and the expected result. Fixes are usually released within a few days.

***

Built on the MIT-licensed [vietnamadminunits](https://github.com/tranngocminhhieu/vietnamadminunits) dataset and parser by Hieu Tran.

# Actor input Schema

## `addresses` (type: `array`):

Vietnamese addresses in the old format (with district / quận / huyện). Accents optional, abbreviations like 'P.', 'Q.1', 'TP HCM' are understood.

## `datasetId` (type: `string`):

Pick a dataset to convert, for example the output of a Google Maps or real-estate scraper. The Actor only gets read access to the dataset you pick.

## `addressField` (type: `string`):

Field holding the address. Dotted paths work, e.g. 'location.address'.

## `includeSourceItem` (type: `boolean`):

Copy each source item into the output under 'sourceItem', so results can be joined back.

## `maxItems` (type: `integer`):

Stop after this many addresses (0 = no limit).

## Actor input object example

```json
{
  "addresses": [
    "59 Nguyễn Thị Minh Khai, Phường Bến Thành, Quận 1, TP Hồ Chí Minh",
    "Số 10 ngõ 5 Láng Hạ, phường Thành Công, quận Ba Đình, Hà Nội",
    "phuong 9 quan 3 tp hcm"
  ],
  "addressField": "address",
  "includeSourceItem": false,
  "maxItems": 0
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset of converted addresses.

## `summary` (type: `string`):

Counts per status and whether the run stopped at the spending limit.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "addresses": [
        "59 Nguyễn Thị Minh Khai, Phường Bến Thành, Quận 1, TP Hồ Chí Minh",
        "Số 10 ngõ 5 Láng Hạ, phường Thành Công, quận Ba Đình, Hà Nội",
        "phuong 9 quan 3 tp hcm"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ducnv91/vietnam-address-converter").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "addresses": [
        "59 Nguyễn Thị Minh Khai, Phường Bến Thành, Quận 1, TP Hồ Chí Minh",
        "Số 10 ngõ 5 Láng Hạ, phường Thành Công, quận Ba Đình, Hà Nội",
        "phuong 9 quan 3 tp hcm",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("ducnv91/vietnam-address-converter").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "addresses": [
    "59 Nguyễn Thị Minh Khai, Phường Bến Thành, Quận 1, TP Hồ Chí Minh",
    "Số 10 ngõ 5 Láng Hạ, phường Thành Công, quận Ba Đình, Hà Nội",
    "phuong 9 quan 3 tp hcm"
  ]
}' |
apify call ducnv91/vietnam-address-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ducnv91/vietnam-address-converter"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Ckryr4j9EjGpyZOMk/builds/ez59Dapipeyjs9PwF/openapi.json
