Behio Storefront SDK
Cart & Checkout

Address Autocomplete

Address suggestions and structured address lookup for checkout forms

Autocomplete addresses during checkout — user selects country, starts typing, and gets structured suggestions (street, city, ZIP).

This is a paid feature. Usage is tracked per 15-minute interval and billed monthly based on request count.

How It Works

  1. Customer selects country (required, ISO 3166-1 alpha-2)
  2. Starts typing an address → debounced API call returns suggestions
  3. Customer picks a suggestion → full structured address is resolved
  4. Fields street, city, zip, country are auto-populated in your form

Framework Examples

Pick your stack — every example below is copy-paste ready:

SDK Client

Framework-agnostic — works in any JavaScript / TypeScript project.

// Search suggestions (country is required)
const { suggestions } = await storefront.addresses.autocomplete('Vodickova 12', 'CZ');

// Get full structured address from a suggestion
const address = await storefront.addresses.getDetail(suggestions[0].placeId);
// {
//   street: "Vodičkova 699/30",
//   city: "Praha",
//   zip: "11000",
//   country: "Czechia",
//   countryCode: "CZ",
//   lat: 50.0815,
//   lng: 14.4243,
// }

React Hook

The useAddressAutocomplete hook handles debouncing, caching, and selection out of the box. Works in any React app — Vite, CRA, Remix, Next.js, Astro React islands, whatever.

import { useAddressAutocomplete } from '@behio/storefront-sdk/react';

function AddressInput() {
  const {
    query,
    setQuery,
    suggestions,
    isLoading,
    select,
    selected,
    isSelecting,
    clear,
  } = useAddressAutocomplete({
    country: 'CZ',       // required — ISO 3166-1 alpha-2
    debounce: 300,        // ms (default: 300)
    minChars: 3,          // min characters before searching (default: 3)
  });

  return (
    <div>
      <input
        value={query}
        onChange={e => setQuery(e.target.value)}
        placeholder="Start typing your address..."
      />

      {isLoading && <div>Searching…</div>}

      {suggestions.length > 0 && (
        <ul>
          {suggestions.map(s => (
            <li key={s.placeId} onClick={() => select(s.placeId)}>
              {s.description}
            </li>
          ))}
        </ul>
      )}

      {selected && (
        <div>
          <p>Street: {selected.street}</p>
          <p>City: {selected.city}</p>
          <p>ZIP: {selected.zip}</p>
          <p>Country: {selected.country}</p>
        </div>
      )}
    </div>
  );
}

Checkout Form Example (React)

Combine with a country selector for a complete checkout address form:

import { useState } from 'react';
import { useAddressAutocomplete } from '@behio/storefront-sdk/react';

function CheckoutAddressForm({ onComplete }) {
  const [country, setCountry] = useState('CZ');
  const { query, setQuery, suggestions, select } = useAddressAutocomplete({
    country,
    debounce: 300,
  });

  // When user picks a suggestion, fill all fields.
  const handleSelect = async (placeId: string) => {
    const address = await select(placeId);
    onComplete({
      street: address.street,
      city: address.city,
      zip: address.zip,
      country: address.countryCode,
    });
  };

  return (
    <div>
      <select value={country} onChange={e => setCountry(e.target.value)}>
        <option value="CZ">Czech Republic</option>
        <option value="SK">Slovakia</option>
        <option value="DE">Germany</option>
        <option value="AT">Austria</option>
        <option value="PL">Poland</option>
      </select>

      <input
        value={query}
        onChange={e => setQuery(e.target.value)}
        placeholder="Street address"
      />

      {suggestions.map(s => (
        <div key={s.placeId} onClick={() => handleSelect(s.placeId)}>
          {s.description}
        </div>
      ))}
    </div>
  );
}

Vue 3 / Nuxt 3 Composable

The SDK ships a React hook; Vue users can drop the same logic into a composable using the client directly.

// composables/useAddressAutocomplete.ts
import { ref, watch } from 'vue';
import { useStorefront } from './useStorefront';
import type { AddressSuggestion, AddressDetail } from '@behio/storefront-sdk';

export function useAddressAutocomplete(opts: {
  country: string;
  debounce?: number;
  minChars?: number;
}) {
  const storefront = useStorefront();
  const query = ref('');
  const suggestions = ref<AddressSuggestion[]>([]);
  const selected = ref<AddressDetail | null>(null);
  const isLoading = ref(false);
  const isSelecting = ref(false);

  const debounce = opts.debounce ?? 300;
  const minChars = opts.minChars ?? 3;
  let timer: ReturnType<typeof setTimeout> | null = null;

  watch(query, (q) => {
    if (timer) clearTimeout(timer);
    if (q.length < minChars) {
      suggestions.value = [];
      return;
    }
    timer = setTimeout(async () => {
      isLoading.value = true;
      try {
        const res = await storefront.addresses.autocomplete(q, opts.country);
        suggestions.value = res.suggestions;
      } finally {
        isLoading.value = false;
      }
    }, debounce);
  });

  async function select(placeId: string) {
    isSelecting.value = true;
    try {
      selected.value = await storefront.addresses.getDetail(placeId);
      return selected.value;
    } finally {
      isSelecting.value = false;
    }
  }

  function clear() {
    query.value = '';
    suggestions.value = [];
    selected.value = null;
  }

  return { query, suggestions, selected, isLoading, isSelecting, select, clear };
}

Vue template

<script setup lang="ts">
import { useAddressAutocomplete } from '~/composables/useAddressAutocomplete';

const { query, suggestions, isLoading, selected, select } = useAddressAutocomplete({
  country: 'CZ',
});
</script>

<template>
  <input v-model="query" placeholder="Start typing your address…" />
  <div v-if="isLoading">Searching…</div>
  <ul v-if="suggestions.length">
    <li v-for="s in suggestions" :key="s.placeId" @click="select(s.placeId)">
      {{ s.description }}
    </li>
  </ul>
  <p v-if="selected">{{ selected.formattedAddress }}</p>
</template>

Next.js — Server Action + Client Input

For Next.js App Router users who want to keep the API key private and call the SDK from a Server Action:

// app/actions/address.ts
'use server';

import { BehioStorefront } from '@behio/storefront-sdk';

const storefront = new BehioStorefront({ apiKey: process.env.BEHIO_SDK_KEY! });

export async function searchAddress(query: string, country: string) {
  if (query.length < 3) return [];
  const { suggestions } = await storefront.addresses.autocomplete(query, country);
  return suggestions;
}

export async function resolveAddress(placeId: string) {
  return storefront.addresses.getDetail(placeId);
}
// app/checkout/AddressInput.tsx
'use client';

import { useState, useTransition } from 'react';
import { searchAddress, resolveAddress } from '../actions/address';

export function AddressInput({ country }: { country: string }) {
  const [query, setQuery] = useState('');
  const [suggestions, setSuggestions] = useState<any[]>([]);
  const [isPending, startTransition] = useTransition();

  function onChange(value: string) {
    setQuery(value);
    startTransition(async () => {
      setSuggestions(await searchAddress(value, country));
    });
  }

  async function onPick(placeId: string) {
    const detail = await resolveAddress(placeId);
    console.log('Resolved:', detail);
  }

  return (
    <div>
      <input value={query} onChange={(e) => onChange(e.target.value)} />
      {isPending && <span>Searching…</span>}
      {suggestions.map((s) => (
        <div key={s.placeId} onClick={() => onPick(s.placeId)}>
          {s.description}
        </div>
      ))}
    </div>
  );
}

Hook Options

OptionTypeDefaultDescription
countrystringrequiredISO 3166-1 alpha-2 country code
debouncenumber300Debounce delay in ms
minCharsnumber3Min characters before searching
enabledbooleantrueDisable the hook

Hook Return

PropertyTypeDescription
querystringCurrent input value
setQuery(value: string) => voidInput onChange handler
suggestionsAddressSuggestion[]Current list of suggestions
isLoadingbooleanFetching suggestions
select(placeId: string) => Promise<AddressDetail>Resolve a suggestion to a full address
selectedAddressDetail | nullResolved structured address
isSelectingbooleanResolving place detail
clear() => voidReset everything

Address Detail Fields

After calling select():

FieldTypeExample
streetstring"Vodičkova 699/30"
streetNumberstring"699/30"
citystring"Praha"
zipstring"11000"
countrystring"Czechia"
countryCodestring"CZ"
formattedAddressstring"Vodičkova 699/30, 110 00 Praha 1, Czechia"
latnumber50.0815
lngnumber14.4243

On this page