Skip to main content
Address Autocomplete di Checkout React: Kurangi Cart Abandonment 35%
Tutorials

Address Autocomplete di Checkout React: Kurangi Cart Abandonment 35%

Tambahkan address autocomplete ke checkout React dengan MapAtlas Geocoding API. Kurangi pengabaian keranjang, percepat entri di mobile

Brent van der Heiden10 min read
#address autocomplete#geocoding api#checkout conversion#address validation#javascript autocomplete

Field alamat checkout adalah tempat konversi mobile mati. Pengguna masuk ke halaman produk Anda, menambahkan barang ke keranjang, melanjutkan ke checkout, lalu diminta mengetik alamat lengkap mereka di keyboard touchscreen 6 inci. Jika mereka salah ketik kode pos, salah format nomor rumah, atau menyerah begitu saja, Anda kehilangan penjualan yang sudah di tangan.

Address autocomplete menyelesaikan masalah ini. Setelah implementasi, entri alamat turun dari 15-25 penekanan tombol menjadi 3-4. Pengguna mulai mengetik nama jalan, melihat saran yang cocok dalam setengah detik, mengetuknya, dan seluruh alamat, jalan, nomor rumah, kota, kode pos, negara, terisi otomatis dengan benar. Pengiriman gagal akibat typo berkurang. Pengabaian checkout berkurang. Dan yang terpenting, Anda mendapatkan koordinat yang sudah diverifikasi dan di-geocode untuk setiap pesanan, yang bisa langsung digunakan oleh sistem logistik dan routing Anda.

Riset di berbagai implementasi e-commerce secara konsisten menunjukkan peningkatan 25-35% dalam tingkat penyelesaian checkout setelah address autocomplete ditambahkan, dengan efek yang jauh lebih kuat di mobile, di mana entri teks manual paling lambat dan paling rawan kesalahan. Beberapa implementasi yang menargetkan pasar mobile-first melaporkan angka penuh 35%.

Tutorial ini membangun komponen address autocomplete React yang lengkap menggunakan MapAtlas Geocoding API, termasuk debouncing, navigasi keyboard, penanganan format alamat UE, dan integrasi formulir. Komponen lengkapnya sekitar 90 baris.

Mengapa Kesalahan Alamat Membunuh Konversi

Pengiriman gagal itu mahal dari semua sisi: kurir mengenakan biaya pengiriman ulang, tim customer service Anda menangani keluhan, dan kepercayaan pelanggan terhadap merek Anda terganggu. Dalam e-commerce B2C, kesalahan entri alamat menyebabkan sekitar 5-8% dari semua pengecualian pengiriman.

Penyebab yang mendasarinya dapat diprediksi:

  • Entri keyboard mobile menghasilkan lebih banyak typo daripada desktop. Autocorrect sering merusak nama jalan dan nama kota.
  • Format kode pos bervariasi antar negara. Pelanggan Jerman yang memasukkan kode 5 digit ke field yang mengharapkan format Inggris (AN NAA) akan memicu error validasi.
  • Urutan jalan/nomor rumah berbeda di seluruh negara UE. Di Jerman dan Belanda, nomor rumah mengikuti nama jalan. Di Prancis, nomor mendahului nama jalan. Formulir entri manual jarang memandu pengguna dengan benar.
  • Designasi apartemen dan lantai tidak memiliki format standar. Pengguna memasukkannya dalam format yang terasa alami bagi mereka, yang sering tidak sesuai dengan ekspektasi kurir pengiriman Anda.

Autocomplete mengabaikan sebagian besar masalah ini dengan mengembalikan objek alamat terstruktur yang sudah divalidasi. Pengguna memilih apa yang mereka maksud, dan formulir Anda menerima format yang benar.

Endpoint Geocoding Autocomplete MapAtlas

Endpoint untuk saran autocomplete adalah:

GET https://api.mapatlas.eu/geocoding/v1/autocomplete?text={query}&key={YOUR_API_KEY}

Parameter opsional yang penting untuk e-commerce UE:

ParameterTipeDeskripsi
textstringQuery alamat parsial
focus.point.lonnumberLongitude pengguna (memprioritaskan hasil terdekat)
focus.point.latnumberLatitude pengguna (memprioritaskan hasil terdekat)
boundary.countrystringKode negara ISO 3166-1 alpha-3 (contoh: DEU, FRA, NLD)
layersstringFilter jenis hasil: address, street, locality
sizenumberJumlah hasil (default 10, maks 20)

Respons tipikal:

{
  "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
      }
    }
  ]
}

Setiap hasil dikembalikan sebagai fitur GeoJSON dengan komponen alamat terstruktur. Formulir Anda menerima data bersih yang sudah divalidasi yang bisa langsung dimasukkan ke setiap field, atau disimpan sebagai satu objek bersama koordinat untuk perencanaan routing dan pengiriman.

Membangun React Autocomplete Hook

Mulailah dengan mengekstrak logika API ke dalam hook yang dapat digunakan kembali. Ini membuat komponen tetap bersih dan membuat hook bisa diuji secara independen.

// 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 };
}

Timer debounce hanya menyala setelah pengguna berhenti mengetik selama 300ms. Guard MIN_CHARS mencegah panggilan API pada input 1-2 karakter di mana hasilnya terlalu luas untuk berguna. Kedua langkah ini penting untuk menjaga penggunaan API (dan biaya) proporsional terhadap niat pengguna yang sebenarnya.

Komponen Autocomplete

// 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' }}>
          Mencari...
        </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>
  );
}

Komponen menangani navigasi keyboard lengkap (tombol panah, enter, escape), atribut ARIA untuk kompatibilitas screen reader, dan penundaan blur 150ms agar klik mouse pada saran terdaftar sebelum daftar menutup.

Integrasi dengan Formulir Checkout

// 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);
    // Koordinat tersedia untuk estimasi routing/pengiriman
    console.log('Koordinat pengiriman:', selected.coordinates);
  }

  return (
    <form>
      <h2>Alamat pengiriman</h2>

      <AddressAutocomplete
        onSelect={handleAddressSelect}
        countryCode="NLD"  // Batasi ke Belanda, hapus untuk seluruh UE
        placeholder="Mulai mengetik alamat jalan Anda..."
      />

      {/* Tampilkan field terstruktur setelah pemilihan, izinkan pengeditan manual */}
      {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="Jalan" />
          <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="Kode pos" />
          <input value={address.locality}    onChange={e => setAddress(a => ({ ...a, locality: e.target.value }))}    placeholder="Kota" />
        </div>
      )}

      <button type="submit" style={{ marginTop: 16 }}>
        Lanjut ke pembayaran
      </button>
    </form>
  );
}

Menampilkan field individual yang dapat diedit setelah autocomplete penting untuk aksesibilitas dan kasus tepi. Alamat pintu sebenarnya pengguna mungkin mencakup nomor unit atau kode akses yang tidak disertakan dalam hasil geocode. Autocomplete mengisi alamat dasar yang sudah divalidasi; pengguna menambahkan sisanya.

Pertimbangan Format Alamat UE

Berbagai negara UE memiliki konvensi alamat yang mempengaruhi tampilan dan urutan field formulir:

Jerman (DEU): Jalan dahulu, nomor rumah sesudah. Hauptstraße 42, 10115 Berlin. Properti housenumber dari API mengikuti jalan dengan benar dalam hasil Jerman.

Prancis (FRA): Nomor rumah sebelum jalan. 42 rue de Rivoli, 75001 Paris. Properti label mengembalikan alamat dalam format yang sesuai dengan negaranya.

Belanda (NLD): Kode pos Belanda terdiri dari 4 digit + 2 huruf kapital dengan spasi: 1012 LG. Validasi format ini jika Anda memisahkan kode pos untuk sistem pengiriman Anda.

Belgia (BEL): Wilayah bilingual mungkin mengembalikan alamat dalam bahasa Prancis atau Belanda tergantung pada kota.

MapAtlas Geocoding API menangani semua ini dengan benar dalam field label (dapat dibaca manusia, format sesuai negara) sekaligus mengembalikan field terstruktur street, housenumber, dan postalcode sehingga Anda bisa membangun tata letak formulir khusus negara jika diperlukan.

Untuk validasi massal basis data alamat yang sudah ada, mungkin membersihkan CRM lama sebelum meluncurkan layanan pengiriman, lihat Cara Menggunakan Geocoding API untuk Memvalidasi 10.000 Alamat Secara Massal.

Pertimbangan Performa

Implementasi di atas membuat sekitar satu panggilan API per 3-4 karakter yang diketik rata-rata (dengan debounce 300ms menyerap pengetikan cepat). Untuk situs e-commerce dengan volume checkout yang signifikan, siapkan server-side proxy di depan Geocoding API agar API key Anda tidak pernah muncul di kode sisi klien:

// 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); // Env var sisi server
  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);
}

Kemudian perbarui hook untuk memanggil /api/autocomplete alih-alih API MapAtlas langsung. Pendekatan ini juga memungkinkan Anda menambahkan caching permintaan di lapisan edge (Vercel Edge Functions, Cloudflare Workers) untuk mengurangi panggilan API untuk query yang umum.

Lihat halaman Harga MapAtlas untuk tarif Geocoding API saat ini dan batas tier gratis, untuk sebagian besar implementasi e-commerce, penggunaan autocomplete masuk dengan nyaman ke dalam tier gratis selama pengembangan.

Ringkasan

Satu field address autocomplete bisa secara signifikan menggerakkan tingkat konversi checkout Anda. Implementasinya mudah: fetch dengan debounce ke MapAtlas Geocoding API, komponen dropdown kecil dengan navigasi keyboard, dan integrasi formulir yang mengisi field terstruktur dari hasil yang dipilih.

Keputusan kunci:

  • Debounce 300ms untuk menghindari panggilan API berlebihan saat pengetikan cepat.
  • Butuh 3 karakter sebelum memicu permintaan.
  • Batasi berdasarkan negara jika Anda mengetahui geografi basis pengguna Anda, ini meningkatkan relevansi hasil secara signifikan.
  • Selalu izinkan pengeditan manual field yang sudah diisi otomatis untuk nomor unit, kode akses, dan koreksi.
  • Proxy API key di sisi server untuk produksi agar tidak mengekspos kredensial di bundle klien.

Untuk integrasi peta pertama Anda di samping field alamat, lihat Cara Menambahkan Peta Interaktif ke Website Anda untuk menampilkan lokasi pengiriman di halaman konfirmasi.


Daftar untuk API key MapAtlas gratis untuk mulai membangun. Geocoding API termasuk dalam tier gratis, tidak perlu kartu kredit.

Pertanyaan yang Sering Diajukan

Bagaimana address autocomplete meningkatkan konversi checkout?

Entri alamat adalah langkah dengan gesekan paling tinggi di sebagian besar alur checkout, terutama di mobile. Autocomplete mereduksinya menjadi 2-3 ketukan tombol lalu satu tap, menghilangkan kesalahan format yang menyebabkan pengiriman gagal, dan menghapus kekhawatiran apakah alamat sudah diisi dengan benar. Studi secara konsisten menunjukkan penurunan 25-35% dalam pengabaian checkout setelah autocomplete diimplementasikan.

Apakah MapAtlas Geocoding API mendukung format alamat Eropa?

Ya. API menangani format khusus UE termasuk urutan nomor rumah setelah nama jalan di Jerman, arrondissement Prancis, kode pos Belanda 4 digit, dan format alamat multibahasa di seluruh negara anggota UE. Hasil dikembalikan sebagai GeoJSON dengan komponen alamat terstruktur.

Bagaimana menghindari API call yang berlebihan saat autocomplete?

Debounce input handler sebesar 250-300ms agar request hanya dikirim setelah pengguna berhenti mengetik. Tetapkan juga ambang karakter minimum (3-4 karakter) sebelum memicu request. Dua langkah ini mengurangi API call sekitar 80% dibandingkan jika dipicu setiap kali tombol ditekan.

Merasa ini berguna? Bagikan.

Tentang penulis

Brent van der Heiden

Ditulis oleh

Brent van der Heiden

Co-Founder & CEO at MapAtlas

Brent built MapAtlas out of a conviction that developers deserve location APIs with fair pricing and genuine end-user privacy. He writes about geospatial infrastructure, AI search visibility, and how location data powers the products people rely on every day.

Lihat semua artikel
Kembali ke blog