O campo de endereço no checkout é onde as conversões móveis morrem. O usuário navega até a página do produto, adiciona um item ao carrinho, avança para o checkout e então é solicitado a digitar o endereço completo num teclado touchscreen de 15 cm. Se errar o código postal, errar o formato do número da casa, ou simplesmente desistir, você perde uma venda que já estava ganha.
O autocompletar de endereço resolve isso. Após a implementação, o preenchimento do endereço cai de 15-25 toques para 3-4. O usuário começa a digitar o nome da rua, vê uma sugestão correspondente em meio segundo, toca nela, e o endereço completo, rua, número, cidade, código postal, país, é preenchido automaticamente e corretamente. Falhas nas entregas causadas por erros de digitação diminuem. O abandono no checkout diminui. E, crucialmente, você tem coordenadas geocodificadas e verificadas associadas a cada pedido, que seus sistemas de logística e roteamento podem usar diretamente.
Pesquisas em implementações de e-commerce mostram consistentemente melhorias de 25-35% nas taxas de conclusão do checkout após a adição do autocompletar de endereço, com efeito significativamente mais forte em dispositivos móveis, onde a digitação manual é mais lenta e propensa a erros. Algumas implementações voltadas para mercados mobile-first reportam os 35% completos.
Este tutorial cria um componente React completo de autocompletar de endereço usando a API de Geocodificação MapAtlas, incluindo debouncing, navegação por teclado, tratamento de formatos de endereço europeus e integração de formulário. O componente completo tem cerca de 90 linhas.
Por que Erros de Endereço Destroem Conversões
Entregas com falha são caras em todos os sentidos: a transportadora cobra uma taxa de reentrega, sua equipe de atendimento ao cliente lida com a reclamação, e a confiança do cliente na sua marca é afetada. No e-commerce B2C, erros na entrada de endereço representam aproximadamente 5-8% de todas as exceções de envio.
As causas subjacentes são previsíveis:
- Digitação no teclado móvel produz mais erros do que no desktop. A correção automática frequentemente corrompe nomes de ruas e cidades.
- Formatos de endereço nacionais variam muito na Europa. Alemanha: Straße antes do número. França: número antes da rua. Países Baixos: códigos postais de 4 dígitos com sufixo de 2 letras. Os usuários não sabem qual formato você espera.
- Campos de formulário longos sem validação ao vivo deixam os erros passarem pela confirmação do pedido. O usuário fica satisfeito. A falha na entrega acontece depois.
- Preenchimento automático do navegador muitas vezes insere endereços antigos ou desatualizados que o usuário não percebe.
O autocompletar de endereço por API elimina a maioria dessas categorias de erro na origem. O usuário seleciona de uma lista de sugestões verificadas, não digita de memória.
Configurando a API de Geocodificação MapAtlas
Antes de construir o componente, você precisa de uma chave de API. Cadastre-se em portal.mapmetrics.org/signup. O plano gratuito inclui 10.000 requisições por mês, mais do que suficiente para desenvolvimento e aplicações de pequeno porte.
A API de Geocodificação aceita uma string de consulta e retorna features GeoJSON com endereços estruturados:
GET https://api.mapatlas.eu/geocoding/v1/autocomplete?text=Herengracht&key=YOUR_API_KEY&lang=pt&country=NL
Parâmetros relevantes para checkout:
text: a string digitada pelo usuáriolang: código de idioma para rótulos de sugestões localizadoscountry: restringe os resultados a um país (ISO 3166-1 alfa-2), reduz resultados irrelevantes drasticamente para checkouts de país únicosize: número de sugestões a retornar (o padrão é 10; use 5 para dropdowns de checkout)
A resposta retorna features com geometry.coordinates (lat/lng) e properties contendo os campos de endereço estruturados.
O Componente React
O componente lida com toda a experiência: o campo de entrada, o dropdown de sugestões, a navegação por teclado e o preenchimento do formulário ao selecionar.
import { useState, useRef, useCallback } from 'react';
const GEOCODING_URL = 'https://api.mapatlas.eu/geocoding/v1/autocomplete';
const API_KEY = process.env.NEXT_PUBLIC_MAPATLAS_KEY;
export function AddressAutocomplete({ onSelect, country = 'NL' }) {
const [query, setQuery] = useState('');
const [suggestions, setSuggestions] = useState([]);
const [activeIndex, setActiveIndex] = useState(-1);
const [isOpen, setIsOpen] = useState(false);
const debounceRef = useRef(null);
const fetchSuggestions = useCallback(async (text) => {
if (text.length < 3) { setSuggestions([]); return; }
const url = new URL(GEOCODING_URL);
url.searchParams.set('text', text);
url.searchParams.set('key', API_KEY);
url.searchParams.set('size', '5');
url.searchParams.set('country', country);
try {
const res = await fetch(url);
const data = await res.json();
setSuggestions(data.features || []);
setIsOpen(true);
setActiveIndex(-1);
} catch {
setSuggestions([]);
}
}, [country]);
const handleChange = (e) => {
const value = e.target.value;
setQuery(value);
clearTimeout(debounceRef.current);
debounceRef.current = setTimeout(() => fetchSuggestions(value), 250);
};
const handleSelect = (feature) => {
const p = feature.properties;
onSelect({
street: `${p.street || ''} ${p.housenumber || ''}`.trim(),
city: p.city || p.locality || '',
postalCode: p.postalcode || '',
country: p.country_code?.toUpperCase() || country,
lat: feature.geometry.coordinates[1],
lng: feature.geometry.coordinates[0],
});
setQuery(p.label || '');
setIsOpen(false);
};
const handleKeyDown = (e) => {
if (!isOpen) return;
if (e.key === 'ArrowDown') setActiveIndex(i => Math.min(i + 1, suggestions.length - 1));
if (e.key === 'ArrowUp') setActiveIndex(i => Math.max(i - 1, 0));
if (e.key === 'Enter' && activeIndex >= 0) { e.preventDefault(); handleSelect(suggestions[activeIndex]); }
if (e.key === 'Escape') setIsOpen(false);
};
return (
<div style={{ position: 'relative' }}>
<input
type="text"
value={query}
onChange={handleChange}
onKeyDown={handleKeyDown}
onBlur={() => setTimeout(() => setIsOpen(false), 150)}
placeholder="Comece a digitar seu endereço..."
autoComplete="off"
style={{ width: '100%', padding: '10px 12px', fontSize: '16px',
border: '1px solid #d1d5db', borderRadius: '6px' }}
/>
{isOpen && suggestions.length > 0 && (
<ul style={{
position: 'absolute', top: '100%', left: 0, right: 0,
background: '#fff', border: '1px solid #d1d5db', borderRadius: '6px',
listStyle: 'none', margin: '4px 0 0', padding: 0,
boxShadow: '0 4px 16px rgba(0,0,0,0.12)', zIndex: 100,
}}>
{suggestions.map((f, i) => (
<li
key={f.properties.osm_id || i}
onMouseDown={() => handleSelect(f)}
style={{
padding: '10px 12px', cursor: 'pointer', fontSize: '14px',
background: i === activeIndex ? '#EFF6FF' : 'transparent',
}}
>
{f.properties.label}
</li>
))}
</ul>
)}
</div>
);
}
Integrando com o Formulário de Checkout
O componente chama onSelect com campos de endereço estruturados. Conecte-o ao estado do formulário de checkout:
import { useState } from 'react';
import { AddressAutocomplete } from './AddressAutocomplete';
export function CheckoutForm() {
const [address, setAddress] = useState({
street: '', city: '', postalCode: '', country: 'NL', lat: null, lng: null,
});
const [submitted, setSubmitted] = useState(false);
const handleAddressSelect = (selectedAddress) => {
setAddress(selectedAddress);
};
const handleSubmit = async (e) => {
e.preventDefault();
// address.lat e address.lng estão disponíveis para uso imediato em sistemas de logística
console.log('Dados de endereço:', address);
setSubmitted(true);
};
return (
<form onSubmit={handleSubmit} style={{ maxWidth: '480px', margin: '0 auto' }}>
<h2>Endereço de Entrega</h2>
<label style={{ display: 'block', marginBottom: '16px' }}>
<span style={{ fontSize: '14px', fontWeight: 600, color: '#374151' }}>
Endereço
</span>
<AddressAutocomplete
onSelect={handleAddressSelect}
country="NL"
/>
</label>
{address.street && (
<div style={{ background: '#F9FAFB', borderRadius: '8px', padding: '12px', marginBottom: '16px' }}>
<p style={{ margin: '0 0 4px', fontWeight: 600 }}>{address.street}</p>
<p style={{ margin: '0 0 4px', color: '#6B7280' }}>{address.postalCode} {address.city}</p>
<p style={{ margin: 0, color: '#6B7280' }}>{address.country}</p>
</div>
)}
<button
type="submit"
disabled={!address.street}
style={{
width: '100%', padding: '12px', background: '#2563EB', color: '#fff',
border: 'none', borderRadius: '6px', fontSize: '16px', fontWeight: 600,
cursor: address.street ? 'pointer' : 'not-allowed', opacity: address.street ? 1 : 0.5,
}}
>
Continuar para Pagamento
</button>
{submitted && <p style={{ color: 'green', marginTop: '8px' }}>Pedido enviado.</p>}
</form>
);
}
O campo lat/lng no objeto address é passado diretamente para a API de Roteamento MapAtlas para otimização de entrega, sem chamada de geocodificação adicional no momento do pedido.
Debouncing e Rate Limiting
O componente usa um debounce de 250ms, o que significa que a API só é chamada quando o usuário para de digitar por um quarto de segundo. Para um checkout ativo durante uma promoção, isso pode representar a diferença entre custos de API gerenciáveis e uma fatura inesperada.
Para aplicações de alto tráfego, faça a chamada geocoding passar pelo seu backend:
// Rota Next.js API: pages/api/geocode.js ou app/api/geocode/route.js
export async function GET(request) {
const { searchParams } = new URL(request.url);
const text = searchParams.get('text');
const country = searchParams.get('country') || 'NL';
const url = new URL('https://api.mapatlas.eu/geocoding/v1/autocomplete');
url.searchParams.set('text', text);
url.searchParams.set('key', process.env.MAPATLAS_KEY); // chave do servidor, não exposta ao cliente
url.searchParams.set('size', '5');
url.searchParams.set('country', country);
const res = await fetch(url);
const data = await res.json();
return Response.json(data);
}
Esta abordagem também mantém sua chave de API fora do código do lado do cliente e permite cache no servidor de resultados frequentes.
Formatos de Endereço Europeus
A API de Geocodificação MapAtlas lida com formatos de endereço por país automaticamente, mas há algumas particularidades que valem a pena conhecer:
Países Baixos: Os códigos postais holandeses têm o formato 1234 AB. A API retorna ambas as partes no campo postalcode. Seu formulário deve aceitar código postal com e sem espaço.
Alemanha: As ruas alemãs frequentemente ficam antes do número da casa na formatação local, mas a API normaliza para o formato Strasse Hausnummer.
França: O arrondissement de Paris é incluído na localidade, por exemplo, "Paris 8e Arrondissement". Se você quiser mostrar apenas "Paris", filtre pelo campo city em vez de locality.
UK: Os postcodes britânicos têm dois segmentos. A API retorna o postcode completo como SW1A 1AA. Certifique-se de que o campo do formulário tenha espaço suficiente.
Para casos de uso de checkout, passar o parâmetro country específico do usuário (por exemplo, com base na seleção de país de envio) melhora significativamente a relevância das sugestões.
O que Vem Depois
- Adicione validação de endereço em massa para auditar o histórico de pedidos por erros de endereço acumulados
- Integre as coordenadas retornadas com o tutorial de mapa de rastreamento de motorista ao vivo para exibir atualizações de entrega em tempo real
- Explore a solução de indústria de Varejo e Comércio para ver como plataformas de e-commerce usam dados de geolocalização para logística e cobertura de entrega
Perguntas frequentes
Por que usar a API de Geocodificação em vez do preenchimento automático do navegador?
O preenchimento automático do navegador usa o histórico de entrada do usuário, que pode estar desatualizado, em formato incorreto ou pertencer a um endereço diferente. A API de Geocodificação retorna endereços verificados e atuais com coordenadas precisas, formatos normalizados para cada país, e garante que cada pedido tenha um endereço de entrega válido e localizável.
O componente funciona em aplicações que não sejam React?
A lógica central, a chamada fetch, o debouncing e a construção do dropdown, são JavaScript vanilla. O exemplo do React é o padrão mais comum, mas o mesmo padrão pode ser adaptado para Vue, Svelte, ou JavaScript puro em qualquer renderização HTML.
Como restrinjo sugestões a uma área específica?
Use o parâmetro country para restringir por país, e o parâmetro bbox (bounding box) para restringir a uma área geográfica: &bbox=minLng,minLat,maxLng,maxLat. Isso é útil para checkout de entrega local onde você serve apenas uma região.

