Address autocomplete
LiveSelected address output can feed delivery, CRM, and service workflows.
- Output
- Structured address
- Use case
- Checkout form
- Workflow
- Cleaner form data
- Full demo
- Address Autocomplete section
NZ address workflow tools for developers
StreetKit helps teams add New Zealand address autocomplete, delivery checks, service-area rules, and distance or travel-time estimates to everyday web workflows.
It is free to use, subject to fair-use limits, so developers can try the tools without login while still keeping shared public access sustainable.
Quick demo
Switch between Address Autocomplete, Radius, Drive Zones, and Live Routing here, or jump to the full demo suite for the complete workflows.
Address Autocomplete
Type a partial address and choose a structured suggestion for forms or checkout.
19 Ormiston Road, Ōtara, Auckland is the origin.
Choose a destination from 19 Ormiston Road.
Type at least 3 characters to search addresses.
Selected address output can feed delivery, CRM, and service workflows.
Solutions
Choose the workflow first, then add the StreetKit feature that maps to it. Each option links to a focused page with the right next step.
Address Autocomplete
Add address suggestions to forms and checkouts so downstream delivery, CRM, and service workflows start with cleaner data.
Realistic use case
Pania's Pet Supplies uses Address Autocomplete so customers can pick the correct NZ delivery address before checkout creates a messy order.
Free to use with fair-use limits. Read rate limits.
Relevant docs: NZ address autocomplete, quick start, widget configuration, address object format, Webflow address autocomplete, WooCommerce address autocomplete.
Demo
Type at least three characters, then select a live StreetKit suggestion to see the structured output shape.
Type to search StreetKit addresses.
Selected address
Select a live address to preview the selected-address payload.
Copy-paste starter
Use the browser widget directly, or wrap it in the framework your site already uses.
<link rel="stylesheet" href="https://streetkit.smp.kiwi/widget/streetkit.css" />
<input id="delivery-address" autocomplete="off" />
<script src="https://streetkit.smp.kiwi/widget/streetkit.js"></script>
<script>
StreetKit.init({
input: "#delivery-address",
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1",
onSelect(address) {
console.log(address.label, address.components);
}
});
</script>
import { useEffect, useRef } from "react";
export function DeliveryAddress() {
const inputRef = useRef(null);
useEffect(() => {
const widget = window.StreetKit?.init({
input: inputRef.current,
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1",
onSelect(address) {
console.log(address.label, address.components);
}
});
return () => widget?.destroy?.();
}, []);
return <input ref={inputRef} autoComplete="off" placeholder="Delivery address" />;
}
<template>
<input ref="input" autocomplete="off" placeholder="Delivery address" />
</template>
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
const input = ref(null);
let widget;
onMounted(() => {
widget = window.StreetKit?.init({
input: input.value,
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1",
onSelect(address) {
console.log(address.label, address.components);
}
});
});
onUnmounted(() => widget?.destroy?.());
</script>
<!-- Add this in a Webflow Embed near your address field. -->
<link rel="stylesheet" href="https://streetkit.smp.kiwi/widget/streetkit.css" />
<input id="delivery-address" autocomplete="off" />
<script src="https://streetkit.smp.kiwi/widget/streetkit.js"></script>
<script>
window.Webflow ||= [];
window.Webflow.push(() => {
StreetKit.init({
input: "#delivery-address",
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1",
onSelect(address) {
console.log(address.label, address.components);
}
});
});
</script>
Radius
Radius is useful when a straight-line distance threshold is enough for a delivery, service, or civic coverage rule.
Realistic use case
Frank's Building Supplies offers free delivery within 15 km of the warehouse. Radius checks the selected customer address before checkout promises free delivery.
Free to use with fair-use limits. Read rate limits.
Relevant docs: delivery radius checker, Radius, and address object format.
Demo
Select an origin and destination from the live address index. Radius uses estimated straight-line distance from the selected address coordinates.
Select both addresses to calculate the radius result.
Choose an origin and destination from live StreetKit suggestions.
Copy-paste starter
Add a simple distance rule around a known shop, depot, or service base.
<link rel="stylesheet" href="https://streetkit.smp.kiwi/widget/streetkit.css" />
<input id="delivery-address" autocomplete="off" />
<p id="delivery-message"></p>
<script src="https://streetkit.smp.kiwi/widget/streetkit.js"></script>
<script>
StreetKit.init({
input: "#delivery-address",
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1",
radiusRules: {
mode: "straight_line",
origins: [
{
id: "warehouse",
label: "Warehouse",
lat: -36.9001,
lon: 174.8852
}
],
rules: [
{
id: "free-delivery",
label: "Free delivery within 15 km",
radiusKm: 15,
message: "Free delivery available."
}
]
},
onSelect(address, context) {
const match = context.radius?.matchedRules?.[0];
document.querySelector("#delivery-message").textContent =
match?.message ?? "Delivery quote required.";
}
});
</script>
import { useEffect, useRef, useState } from "react";
const radiusRules = {
mode: "straight_line",
origins: [{ id: "warehouse", label: "Warehouse", lat: -36.9001, lon: 174.8852 }],
rules: [{ id: "free-delivery", label: "Free delivery within 15 km", radiusKm: 15 }]
};
export function DeliveryRadiusCheck() {
const inputRef = useRef(null);
const [message, setMessage] = useState("");
useEffect(() => {
const widget = window.StreetKit?.init({
input: inputRef.current,
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1",
radiusRules,
onSelect(_address, context) {
setMessage(context.radius?.matchedRules?.[0]?.label ?? "Delivery quote required.");
}
});
return () => widget?.destroy?.();
}, []);
return (
<>
<input ref={inputRef} autoComplete="off" placeholder="Delivery address" />
<p>{message}</p>
</>
);
}
<template>
<input ref="input" autocomplete="off" placeholder="Delivery address" />
<p>{{ message }}</p>
</template>
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
const input = ref(null);
const message = ref("");
let widget;
const radiusRules = {
mode: "straight_line",
origins: [{ id: "warehouse", label: "Warehouse", lat: -36.9001, lon: 174.8852 }],
rules: [{ id: "free-delivery", label: "Free delivery within 15 km", radiusKm: 15 }]
};
onMounted(() => {
widget = window.StreetKit?.init({
input: input.value,
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1",
radiusRules,
onSelect(_address, context) {
message.value = context.radius?.matchedRules?.[0]?.label ?? "Delivery quote required.";
}
});
});
onUnmounted(() => widget?.destroy?.());
</script>
<!-- Add this in a Webflow Embed near your delivery form. -->
<link rel="stylesheet" href="https://streetkit.smp.kiwi/widget/streetkit.css" />
<input id="delivery-address" autocomplete="off" />
<p id="delivery-message"></p>
<script src="https://streetkit.smp.kiwi/widget/streetkit.js"></script>
<script>
window.Webflow ||= [];
window.Webflow.push(() => {
StreetKit.init({
input: "#delivery-address",
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1",
radiusRules: {
mode: "straight_line",
origins: [{ id: "warehouse", label: "Warehouse", lat: -36.9001, lon: 174.8852 }],
rules: [{ id: "free-delivery", label: "Free delivery within 15 km", radiusKm: 15 }]
},
onSelect(_address, context) {
const match = context.radius?.matchedRules?.[0];
document.querySelector("#delivery-message").textContent =
match?.label ?? "Delivery quote required.";
}
});
});
</script>
Drive Zones
Managed service-area setup for teams with fixed depots, branches, clinics, offices, or service bases. Drive Zones are built with sensible coverage limits so road-aware checks stay fast and practical.
Realistic use case
Frank's Building Supplies also wants a practical road-travel rule: free delivery if the address is inside a 20-minute drive zone from the warehouse.
Managed setup
Drive Zones need a short setup conversation so we can agree the origins, drive-time thresholds, region, update frequency, and checkout or reporting needs before enabling them.
When to use Live Routing instead
If your product compares any two addresses, such as a booking form checking whether same-day service is realistic, Live Routing is the more flexible fit. Drive Zones are strongest for fixed-origin service eligibility.
Drive Zones are scoped before use so limits stay sensible. Contact us to discuss a setup.
Relevant docs: Drive Zones, Drive Zones docs, and Drive Zones setup.
Demo
19 Ormiston Road is the managed origin. Choose a destination address to preview how a bounded service-area rule can classify delivery or field-service coverage.
Choose a destination to preview the road-aware coverage rule.
19 Ormiston Road is fixed as the managed origin for this demo.
Managed feature
We will help scope the origins, coverage limits, performance target, and update pattern so the result is useful without becoming too broad or heavy for the job.
Live Routing
Live Routing helps teams compare estimated travel time and distance for online booking, quoting, delivery, and field-service workflows.
Realistic use case
A plumbing or appliance-repair website estimates travel time to the customer's address before showing same-day service options or asking the customer to request a quote.
Free to use with fair-use limits. Read rate limits.
Relevant docs: routing distance, Live Routing, and rate limits.
Coming soon
Live Routing is unavailable in the public demo while we finish the service. It is coming soon for teams that need address-to-address distance and travel-time estimates.
Live Routing is unavailable in the public demo, but it is coming soon.
We are preparing Live Routing for booking, quoting, delivery, and field-service workflows.
Copy-paste starter
Prepare the form pattern now; Live Routing API access is coming soon.
<link rel="stylesheet" href="https://streetkit.smp.kiwi/widget/streetkit.css" />
<input id="route-origin" autocomplete="off" placeholder="Origin" />
<input id="route-destination" autocomplete="off" placeholder="Destination" />
<button id="route-button" type="button">Estimate route</button>
<p id="route-summary"></p>
<script src="https://streetkit.smp.kiwi/widget/streetkit.js"></script>
<script>
const streetkitOptions = {
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1"
};
let origin = null;
let destination = null;
StreetKit.init({
...streetkitOptions,
input: "#route-origin",
onSelect(address) {
origin = address;
}
});
StreetKit.init({
...streetkitOptions,
input: "#route-destination",
onSelect(address) {
destination = address;
}
});
document.querySelector("#route-button").addEventListener("click", async () => {
if (!origin || !destination) {
document.querySelector("#route-summary").textContent =
"Choose both addresses first.";
return;
}
const point = (address) => ({
lat: address.location.lat,
lon: address.location.lon
});
const response = await fetch("https://routing.streetkit.smp.kiwi/v1/routes", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
origin: point(origin),
destination: point(destination),
mode: "driving",
options: { units: "metric" }
})
});
const result = await response.json();
const km = (result.route.distanceMeters / 1000).toFixed(1);
const minutes = Math.round(result.route.durationSeconds / 60);
document.querySelector("#route-summary").textContent =
`${km} km in about ${minutes} minutes`;
});
</script>
import { useEffect, useRef, useState } from "react";
const routeUrl = "https://routing.streetkit.smp.kiwi/v1/routes";
const streetkitOptions = {
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1"
};
export function RouteEstimate() {
const originRef = useRef(null);
const destinationRef = useRef(null);
const origin = useRef(null);
const destination = useRef(null);
const [summary, setSummary] = useState("");
useEffect(() => {
const originWidget = window.StreetKit?.init({
...streetkitOptions,
input: originRef.current,
onSelect(address) {
origin.current = address;
}
});
const destinationWidget = window.StreetKit?.init({
...streetkitOptions,
input: destinationRef.current,
onSelect(address) {
destination.current = address;
}
});
return () => {
originWidget?.destroy?.();
destinationWidget?.destroy?.();
};
}, []);
async function estimateRoute() {
if (!origin.current || !destination.current) {
setSummary("Choose both addresses first.");
return;
}
const point = (address) => ({
lat: address.location.lat,
lon: address.location.lon
});
const response = await fetch(routeUrl, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
origin: point(origin.current),
destination: point(destination.current),
mode: "driving",
options: { units: "metric" }
})
});
const result = await response.json();
setSummary(`${(result.route.distanceMeters / 1000).toFixed(1)} km in about ${Math.round(result.route.durationSeconds / 60)} minutes`);
}
return (
<>
<input ref={originRef} autoComplete="off" placeholder="Origin" />
<input ref={destinationRef} autoComplete="off" placeholder="Destination" />
<button type="button" onClick={estimateRoute}>Estimate route</button>
<p>{summary}</p>
</>
);
}
<template>
<input ref="originInput" autocomplete="off" placeholder="Origin" />
<input ref="destinationInput" autocomplete="off" placeholder="Destination" />
<button type="button" @click="estimateRoute">Estimate route</button>
<p>{{ summary }}</p>
</template>
<script setup>
import { onMounted, onUnmounted, ref } from "vue";
const routeUrl = "https://routing.streetkit.smp.kiwi/v1/routes";
const originInput = ref(null);
const destinationInput = ref(null);
const origin = ref(null);
const destination = ref(null);
const summary = ref("");
let originWidget;
let destinationWidget;
onMounted(() => {
const options = {
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1"
};
originWidget = window.StreetKit?.init({
...options,
input: originInput.value,
onSelect(address) {
origin.value = address;
}
});
destinationWidget = window.StreetKit?.init({
...options,
input: destinationInput.value,
onSelect(address) {
destination.value = address;
}
});
});
onUnmounted(() => {
originWidget?.destroy?.();
destinationWidget?.destroy?.();
});
async function estimateRoute() {
if (!origin.value || !destination.value) {
summary.value = "Choose both addresses first.";
return;
}
const point = (address) => ({
lat: address.location.lat,
lon: address.location.lon
});
const response = await fetch(routeUrl, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
origin: point(origin.value),
destination: point(destination.value),
mode: "driving",
options: { units: "metric" }
})
});
const result = await response.json();
summary.value = `${(result.route.distanceMeters / 1000).toFixed(1)} km in about ${Math.round(result.route.durationSeconds / 60)} minutes`;
}
</script>
<!-- Add this in a Webflow Embed near your route fields. -->
<link rel="stylesheet" href="https://streetkit.smp.kiwi/widget/streetkit.css" />
<input id="route-origin" autocomplete="off" placeholder="Origin" />
<input id="route-destination" autocomplete="off" placeholder="Destination" />
<button id="route-button" type="button">Estimate route</button>
<p id="route-summary"></p>
<script src="https://streetkit.smp.kiwi/widget/streetkit.js"></script>
<script>
window.Webflow ||= [];
window.Webflow.push(() => {
const options = {
publicMode: true,
indexBaseUrl: "https://index.streetkit.smp.kiwi/public/v1"
};
let origin = null;
let destination = null;
StreetKit.init({ ...options, input: "#route-origin", onSelect: (address) => { origin = address; } });
StreetKit.init({ ...options, input: "#route-destination", onSelect: (address) => { destination = address; } });
document.querySelector("#route-button").addEventListener("click", async () => {
if (!origin || !destination) {
document.querySelector("#route-summary").textContent = "Choose both addresses first.";
return;
}
const point = (address) => ({ lat: address.location.lat, lon: address.location.lon });
const response = await fetch("https://routing.streetkit.smp.kiwi/v1/routes", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ origin: point(origin), destination: point(destination), mode: "driving", options: { units: "metric" } })
});
const result = await response.json();
document.querySelector("#route-summary").textContent =
`${(result.route.distanceMeters / 1000).toFixed(1)} km in about ${Math.round(result.route.durationSeconds / 60)} minutes`;
});
});
</script>
Works with the web
Start with the browser widget, then wrap it for the platform you already use. HTML and JavaScript are available now; Webflow, React, and Vue have guide paths; WooCommerce is available only as a beta plugin preview for controlled checkout testing. Shopify Plus checkout is a private prototype scaffold only, not public support or a generic checkout script-tag install. Compare integration options.
Build with StreetKit
Start with the copy-paste snippet, then use the docs for the next decision: mapping fields, handling selected-address data, adding Radius or Drive Zones rules, preparing Live Routing workflows, and setting clear limits for users.
Registered access
Request a site ID when a production form, checkout, booking flow, or internal tool needs better soft limits and a clear integration label.
Support StreetKit
StreetKit is useful because it saves time on real forms, checkouts, service-area checks, and routing workflows. These options are sized around the kinds of people and teams likely to rely on it.
Free
Try StreetKit, build demos, and use the public tools within fair-use limits.$15/month
For solo builders, freelancers, and developers using StreetKit on small projects.$39/month
For small sites, checkouts, booking forms, and civic tools using address search regularly.$99/month
For teams using Radius, Drive Zones, or selected-address data in everyday operations.$249/month
For agencies and product teams using StreetKit across multiple client or internal projects.$750+/month
For organisations backing ongoing NZ address data refreshes, quality work, docs, and demos.Sponsorship helps keep StreetKit available. It does not remove fair-use limits or create a private support contract unless agreed separately.