Le champ d'adresse lors du paiement est l'endroit où les conversions mobiles vont mourir. Un utilisateur navigue vers votre page produit, ajoute un article à son panier, passe à la caisse, et se retrouve alors à devoir saisir son adresse complète sur un clavier tactile de 15 cm. S'il se trompe dans le code postal, inverse le numéro de rue, ou abandonne tout simplement, vous perdez une vente que vous aviez déjà gagnée.
L'autocomplétion d'adresse résout ce problème. Après intégration, la saisie d'adresse passe de 15 à 25 frappes à 3 ou 4. L'utilisateur commence à taper un nom de rue, voit une suggestion correspondante en moins d'une demi-seconde, la sélectionne, et l'adresse complète, rue, numéro, ville, code postal, pays, se remplit automatiquement et correctement. Les livraisons échouées dues aux fautes de frappe diminuent. L'abandon de panier diminue. Et surtout, vous disposez de coordonnées géocodées et vérifiées associées à chaque commande, directement utilisables par vos systèmes logistiques et de routage.
Les études menées sur les implémentations e-commerce montrent de manière constante une amélioration de 25 à 35 % des taux de finalisation de commande après ajout de l'autocomplétion, avec un effet nettement plus fort sur mobile, où la saisie manuelle est la plus lente et la plus sujette aux erreurs. Certaines implémentations ciblant des marchés à majorité mobile atteignent le plein 35 %.
Ce tutoriel crée un composant React complet d'autocomplétion d'adresse avec l'API de geocodage MapAtlas, incluant la temporisation (debouncing), la navigation au clavier, la gestion des formats d'adresses européens et l'intégration dans un formulaire. Le composant complet fait environ 90 lignes.
Pourquoi les erreurs d'adresse tuent les conversions
Les livraisons échouées coûtent cher dans tous les sens du terme : le transporteur facture un supplément de réacheminement, votre équipe support gère la réclamation, et la confiance du client envers votre marque en prend un coup. En e-commerce B2C, les erreurs de saisie d'adresse représentent environ 5 à 8 % de toutes les exceptions d'expédition.
Les causes sous-jacentes sont prévisibles :
- La saisie sur clavier mobile produit plus de fautes de frappe que sur ordinateur. La correction automatique déforme souvent les noms de rues et de villes.
- Les formats de code postal varient selon les pays. Un client allemand saisissant un code à 5 chiffres dans un champ attendant le format britannique (AN NAA) déclenchera une erreur de validation.
- L'ordre rue/numéro diffère selon les pays européens. En Allemagne et aux Pays-Bas, le numéro suit le nom de la rue. En France, il le précède. Les formulaires de saisie manuelle guident rarement les utilisateurs correctement.
- Les désignations d'appartement et d'étage n'ont pas de format standardisé. Les utilisateurs les saisissent dans le format qui leur semble naturel, ce qui ne correspond souvent pas à ce qu'attend votre transporteur.
L'autocomplétion contourne la plupart de ces problèmes en renvoyant un objet adresse pré-validé et structuré. L'utilisateur sélectionne ce qu'il entend, et votre formulaire reçoit le bon format.
L'endpoint d'autocomplétion de l'API de geocodage MapAtlas
L'endpoint pour les suggestions d'autocomplétion est :
GET https://api.mapatlas.eu/geocoding/v1/autocomplete?text={query}&key={YOUR_API_KEY}
Paramètres optionnels utiles pour l'e-commerce européen :
| Paramètre | Type | Description |
|---|---|---|
text | string | La requête d'adresse partielle |
focus.point.lon | number | Longitude de l'utilisateur (priorise les résultats proches) |
focus.point.lat | number | Latitude de l'utilisateur (priorise les résultats proches) |
boundary.country | string | Code pays ISO 3166-1 alpha-3 (ex. DEU, FRA, NLD) |
layers | string | Filtre les types de résultats : address, street, locality |
size | number | Nombre de résultats (défaut 10, max 20) |
Une réponse type :
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": { "type": "Point", "coordinates": [4.9041, 52.3676] },
"properties": {
"id": "address:node/1234567",
"label": "Damrak 1, 1012 LG Amsterdam, Netherlands",
"name": "Damrak 1",
"street": "Damrak",
"housenumber": "1",
"postalcode": "1012 LG",
"locality": "Amsterdam",
"region": "North Holland",
"country": "Netherlands",
"country_code": "NL",
"confidence": 0.98
}
}
]
}
Chaque résultat est renvoyé sous forme de feature GeoJSON avec des composants d'adresse structurés. Votre formulaire reçoit des données propres et validées que vous pouvez insérer directement dans chaque champ, ou stocker sous forme d'objet unique avec les coordonnées pour le routage et la planification des livraisons.
Construire le hook React d'autocomplétion
Commencez par extraire la logique API dans un hook réutilisable. Cela garde le composant propre et rend le hook testable indépendamment.
// hooks/useAddressAutocomplete.js
import { useState, useEffect, useRef } from 'react';
const API_BASE = 'https://api.mapatlas.eu/geocoding/v1/autocomplete';
const API_KEY = process.env.NEXT_PUBLIC_MAPATLAS_KEY;
const DEBOUNCE_MS = 300;
const MIN_CHARS = 3;
export function useAddressAutocomplete(countryCode = null) {
const [query, setQuery] = useState('');
const [suggestions, setSuggestions] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const debounceTimer = useRef(null);
useEffect(() => {
if (query.length < MIN_CHARS) {
setSuggestions([]);
return;
}
clearTimeout(debounceTimer.current);
debounceTimer.current = setTimeout(async () => {
setLoading(true);
setError(null);
try {
const url = new URL(API_BASE);
url.searchParams.set('text', query);
url.searchParams.set('key', API_KEY);
url.searchParams.set('size', '6');
url.searchParams.set('layers', 'address');
if (countryCode) {
url.searchParams.set('boundary.country', countryCode);
}
const res = await fetch(url.toString());
if (!res.ok) throw new Error(`API error: ${res.status}`);
const data = await res.json();
setSuggestions(data.features ?? []);
} catch (err) {
setError(err.message);
setSuggestions([]);
} finally {
setLoading(false);
}
}, DEBOUNCE_MS);
return () => clearTimeout(debounceTimer.current);
}, [query, countryCode]);
return { query, setQuery, suggestions, loading, error };
}
Le timer de temporisation se déclenche uniquement après que l'utilisateur ait cessé de taper pendant 300 ms. La garde MIN_CHARS empêche les appels API sur des saisies de 1 à 2 caractères où les résultats seraient trop larges pour être utiles. Ces deux mesures sont essentielles pour maintenir l'utilisation de l'API (et les coûts) proportionnellement à l'intention réelle de l'utilisateur.
Le composant d'autocomplétion
// components/AddressAutocomplete.jsx
import { useState, useRef } from 'react';
import { useAddressAutocomplete } from '../hooks/useAddressAutocomplete';
export function AddressAutocomplete({ onSelect, countryCode, placeholder }) {
const { query, setQuery, suggestions, loading } = useAddressAutocomplete(countryCode);
const [open, setOpen] = useState(false);
const [highlighted, setHighlighted] = useState(-1);
const inputRef = useRef(null);
function handleSelect(feature) {
const p = feature.properties;
setQuery(p.label);
setOpen(false);
setHighlighted(-1);
onSelect({
label: p.label,
street: p.street ?? '',
housenumber: p.housenumber ?? '',
postalcode: p.postalcode ?? '',
locality: p.locality ?? '',
region: p.region ?? '',
country: p.country ?? '',
country_code: p.country_code ?? '',
coordinates: feature.geometry.coordinates, // [lng, lat]
});
}
function handleKeyDown(e) {
if (!open || suggestions.length === 0) return;
if (e.key === 'ArrowDown') setHighlighted(h => Math.min(h + 1, suggestions.length - 1));
if (e.key === 'ArrowUp') setHighlighted(h => Math.max(h - 1, 0));
if (e.key === 'Enter' && highlighted >= 0) handleSelect(suggestions[highlighted]);
if (e.key === 'Escape') setOpen(false);
}
return (
<div style={{ position: 'relative' }}>
<input
ref={inputRef}
type="text"
value={query}
placeholder={placeholder ?? 'Start typing your address...'}
onChange={e => { setQuery(e.target.value); setOpen(true); setHighlighted(-1); }}
onKeyDown={handleKeyDown}
onBlur={() => setTimeout(() => setOpen(false), 150)}
style={{ width: '100%', padding: '10px 12px', fontSize: 16, borderRadius: 6, border: '1px solid #ccc' }}
autoComplete="off"
aria-autocomplete="list"
aria-haspopup="listbox"
aria-expanded={open && suggestions.length > 0}
/>
{loading && (
<span style={{ position: 'absolute', right: 12, top: '50%', transform: 'translateY(-50%)', fontSize: 12, color: '#888' }}>
Searching…
</span>
)}
{open && suggestions.length > 0 && (
<ul
role="listbox"
style={{
position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 999,
background: '#fff', border: '1px solid #ccc', borderTop: 'none',
borderRadius: '0 0 6px 6px', listStyle: 'none', margin: 0, padding: 0,
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
}}
>
{suggestions.map((feature, i) => (
<li
key={feature.properties.id}
role="option"
aria-selected={i === highlighted}
onMouseDown={() => handleSelect(feature)}
onMouseEnter={() => setHighlighted(i)}
style={{
padding: '10px 12px',
cursor: 'pointer',
fontSize: 14,
background: i === highlighted ? '#f0f7e6' : '#fff',
borderBottom: i < suggestions.length - 1 ? '1px solid #f0f0f0' : 'none',
}}
>
{feature.properties.label}
</li>
))}
</ul>
)}
</div>
);
}
Le composant gère la navigation complète au clavier (touches fléchées, entrée, échap), les attributs ARIA pour la compatibilité avec les lecteurs d'écran, et un délai de 150 ms à la perte de focus afin que les clics sur les suggestions s'enregistrent avant la fermeture de la liste.
Intégration avec un formulaire de paiement
// pages/checkout.jsx
import { useState } from 'react';
import { AddressAutocomplete } from '../components/AddressAutocomplete';
export default function CheckoutPage() {
const [address, setAddress] = useState({
street: '', housenumber: '', postalcode: '',
locality: '', country: '', coordinates: null,
});
function handleAddressSelect(selected) {
setAddress(selected);
// Coordinates are available for routing/delivery estimation
console.log('Delivery coordinates:', selected.coordinates);
}
return (
<form>
<h2>Delivery address</h2>
<AddressAutocomplete
onSelect={handleAddressSelect}
countryCode="NLD" // Restrict to Netherlands, remove for EU-wide
placeholder="Start typing your street address..."
/>
{/* Show structured fields after selection, allow manual edits */}
{address.street && (
<div style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: 8, marginTop: 12 }}>
<input value={address.street} onChange={e => setAddress(a => ({ ...a, street: e.target.value }))} placeholder="Street" />
<input value={address.housenumber} onChange={e => setAddress(a => ({ ...a, housenumber: e.target.value }))} placeholder="No." style={{ width: 80 }} />
<input value={address.postalcode} onChange={e => setAddress(a => ({ ...a, postalcode: e.target.value }))} placeholder="Postal code" />
<input value={address.locality} onChange={e => setAddress(a => ({ ...a, locality: e.target.value }))} placeholder="City" />
</div>
)}
<button type="submit" style={{ marginTop: 16 }}>
Continue to payment
</button>
</form>
);
}
Afficher des champs éditables individuels après l'autocomplétion est important pour l'accessibilité et les cas limites. L'adresse réelle d'un utilisateur peut inclure un numéro d'appartement ou un code d'accès que le résultat géocodé ne comprend pas. L'autocomplétion remplit l'adresse de base validée ; l'utilisateur complète le reste.
Considérations sur les formats d'adresses européens
Les différents pays européens ont des conventions d'adressage qui influencent à la fois l'affichage et l'ordre des champs du formulaire :
Allemagne (DEU) : La rue en premier, puis le numéro. Hauptstraße 42, 10115 Berlin. La propriété housenumber de l'API suit correctement la rue dans les résultats allemands.
France (FRA) : Le numéro avant la rue. 42 rue de Rivoli, 75001 Paris. La propriété label renvoie les adresses dans le format approprié au pays.
Pays-Bas (NLD) : Les codes postaux néerlandais comprennent 4 chiffres suivis de 2 lettres majuscules avec un espace : 1012 LG. Validez ce format si vous découpez le code postal pour votre système d'expédition.
Belgique (BEL) : Les régions bilingues peuvent renvoyer des adresses en français ou en néerlandais selon la commune.
L'API de geocodage MapAtlas gère tout cela correctement dans le champ label (lisible par l'humain, adapté au pays), tout en renvoyant les champs structurés street, housenumber et postalcode pour vous permettre de créer des mises en page de formulaire spécifiques à chaque pays si nécessaire.
Pour la validation en masse de bases d'adresses existantes, par exemple pour nettoyer un CRM historique avant le lancement d'un service de livraison, consultez Comment utiliser l'API de geocodage pour valider 10 000 adresses en masse.
Considérations de performance
L'implémentation ci-dessus génère environ un appel API toutes les 3 à 4 frappes en moyenne (la temporisation de 300 ms absorbant la frappe rapide). Pour un site e-commerce avec un volume de paiement significatif, configurez un proxy côté serveur devant l'API de geocodage afin que votre clé API n'apparaisse jamais dans le code côté client :
// pages/api/autocomplete.js (Next.js API route)
export default async function handler(req, res) {
const { text, countryCode } = req.query;
const url = new URL('https://api.mapatlas.eu/geocoding/v1/autocomplete');
url.searchParams.set('text', text);
url.searchParams.set('key', process.env.MAPATLAS_KEY); // Server-side env var
url.searchParams.set('size', '6');
url.searchParams.set('layers', 'address');
if (countryCode) url.searchParams.set('boundary.country', countryCode);
const response = await fetch(url.toString());
const data = await response.json();
res.json(data);
}
Mettez ensuite à jour le hook pour appeler /api/autocomplete au lieu de l'API MapAtlas directement. Cette approche vous permet également d'ajouter une mise en cache des requêtes au niveau edge (Vercel Edge Functions, Cloudflare Workers) pour réduire les appels API sur les requêtes fréquentes.
Consultez la page Tarifs MapAtlas pour les tarifs actuels de l'API de geocodage et les limites du niveau gratuit : pour la plupart des implémentations e-commerce, l'utilisation de l'autocomplétion s'inscrit confortablement dans le niveau gratuit pendant le développement.
Résumé
Un seul champ d'autocomplétion d'adresse peut faire évoluer significativement votre taux de conversion au paiement. L'implémentation est simple : une requête temporisée vers l'API de geocodage MapAtlas, un petit composant déroulant avec navigation au clavier, et une intégration de formulaire qui remplit les champs structurés à partir du résultat sélectionné.
Décisions clés :
- Temporisation à 300 ms pour éviter les appels API excessifs lors d'une frappe rapide.
- Exiger 3 caractères avant de déclencher les requêtes.
- Restreindre par pays si vous connaissez la géographie de votre base d'utilisateurs : cela améliore considérablement la pertinence des résultats.
- Toujours permettre la modification manuelle des champs autocompletés pour les numéros d'appartement, codes d'accès et corrections.
- Proxifier la clé API côté serveur en production pour éviter d'exposer les identifiants dans les bundles client.
Pour votre première intégration de carte associée au champ d'adresse, consultez Comment ajouter des cartes interactives à votre site web pour afficher l'emplacement de livraison sur une page de confirmation.
Créez un compte gratuit MapAtlas pour commencer à développer. L'API de geocodage est incluse dans le niveau gratuit, sans carte bancaire requise.

