A city autocomplete is a few lines: debounce the input, query the cities API, render the matches. No key, no library.
The query
curl "https://countries.dev/cities?q=san&limit=6"[
{ "name": "San Antonio", "countryCode": "US", "population": 1469845 },
{ "name": "San Diego", "countryCode": "US", "population": 1394928 }
]Matches are ranked by population and accent-insensitive (zurich finds Zürich), so the most likely city is first.
A minimal autocomplete
let timer;
input.addEventListener('input', () => {
clearTimeout(timer);
timer = setTimeout(async () => {
const cities = await fetch(
`https://countries.dev/cities?q=${encodeURIComponent(input.value)}&limit=6`,
).then((r) => r.json());
list.innerHTML = cities.map((c) => `<li>${c.name}, ${c.countryCode}</li>`).join('');
}, 200);
});Scope it, or go deeper
Add &country=US to restrict to one country. Each result carries coordinates and a GeoNames id, so a click can open the full place record. See it working on the cities API page, read the docs, or list the largest cities in the world.
Written by
Dov Azencot
At
Fri Jun 26 2026