Flutter Address Autocomplete for Vietnam (suggest + resolve)
Build a Vietnam address input in Flutter: debounce, call /v1/suggest for predictions and /v1/place/resolve for coordinates, proxy to hide your API key — with full Dart code.
Almost every delivery, ride-hailing, or at-home services app in Vietnam needs a
smart address input: the user types a few characters, the app suggests the right
address, and once they pick one you immediately have the coordinates to drop
a pin or compute a route. This post builds that input in Flutter, pairing two
GoGoDuk endpoints — /v1/suggest for predictions and
/v1/place/resolve to get clean coordinates for
the chosen address — with runnable Dart code.
If you work on the web in React/Next.js, see the same architecture in Address autocomplete component for React/Next.js. This post is the mobile/Dart version of the same idea.
Why Vietnamese mobile apps need their own address autocomplete
Vietnamese addresses are written many ways: with or without diacritics, "Q.1" or "Quận 1", "P. Bến Nghé", house numbers with alleys. A good address input has to match those variants and return a standardized form. Building an address list inside the app is practically impossible; calling a geocoding API tuned for Vietnam is far simpler.
The common mistake is to put a TextField and call the API directly on every
keystroke. Three frequent problems:
- Leaked API key. Embedding
X-API-Keydirectly in the Dart app means anyone who decompiles the APK/IPA or inspects traffic can grab your key. - No debounce. Fast typing fires a storm of racing requests, results jump around, and you burn quota.
- No billing session. Each keystroke is a separate request, never stitched into a single "type → pick" session.
Architecture: app → proxy → GoGoDuk
The golden rule for mobile: the API key never lives in the app. The app calls
your own backend proxy; the proxy attaches X-API-Key and calls GoGoDuk.
This is the same architecture the React post uses — only the client is Dart instead of JavaScript. The proxy can be any backend you already run (Node, Go, Firebase Cloud Functions…); it just forwards the query and attaches the key.
Step 1: a Dart client calling suggest through the proxy
/v1/suggest needs input of at least 2 characters, accepts lang (default
vi), country (only VN), and optional focus.lat/focus.lon to prioritize
results near a location. Each response returns a predictions array; every item
has placeId, text, mainText, secondaryText.
The proxy simply forwards these query params to
https://api.gogoduk.com/v1/suggest with an X-API-Key header. The logic is
identical to the proxy route in the React post — just in your backend language.
Step 2: TextField + debounce + dropdown
In Flutter we wrap a TextField with a Timer to debounce ~300ms: only call
suggest when the user pauses typing, avoiding a request per keystroke. A single
sessionToken per session (type → pick) groups billing.
Step 3: resolve a placeId into coordinates
predictions only carry a placeId, not coordinates yet. When the user picks a
suggestion, call /v1/place/resolve with id
set to that placeId (pass the same sessionToken to close the billing
session). The result response has lat, lon, name, address, and
district/city (may be null).
Now inside AddressField's onSelected you have coordinates to drop a map pin,
save to an order, or compute a distance-based shipping fee.
Production notes
- Never embed the API key in the app. APK/IPA can be decompiled; a key in the binary is effectively public. Always go through a server-side proxy.
- Group the billing session. Use one
sessionTokenfor the whole "type → pick" session, then rotate after resolve. Suggest and resolve with the same token count as one session. - Debounce + cancel stale requests. 250–300ms is reasonable on mobile. Remember
to
cancel()the timer indispose()to avoidsetStateafter unmount. focus.lat/focus.lon. If you already have the user's GPS, pass it to suggest to prioritize nearby addresses — noticeably better suggestions.- Handle errors & empties. Mobile networks are flaky; always branch for empty
predictionsand HTTP errors so the dropdown never hangs.
When to use the SDK vs raw calls
GoGoDuk ships a TypeScript SDK that wraps suggest and placeResolve —
handy if your proxy backend is Node/TS. But the Dart app never calls GoGoDuk
directly (it must hide the key), so the client always talks to your proxy over
plain HTTP as above. In other words: the SDK (if used) lives in the proxy tier,
and Flutter only needs http.
If your app needs to go from GPS coordinates to province/district/ward (e.g. a driver app), see reverse geocoding to identify province/district from coordinates and the overview What is geocoding. For how Vietnamese address autocomplete works under the hood, see Vietnam Address Autocomplete API.
Conclusion
A good address autocomplete in Flutter needs just three pieces: debounce for smooth typing, a proxy to hide the key, and the suggest + resolve pair to turn a few typed characters into clean coordinates. The architecture is identical to the web version, so if your team ships both web and mobile, the same backend proxy serves both.
Create a free API key at app.gogoduk.com to get started, and read the two endpoint references at suggest docs and place resolve docs. Questions, or want an architecture review? Join the dev community on Telegram.
Want to use GoGoDuk?
Free forever — 100 requests/day per account, no credit card. Higher limits on request.
Sign up →