
A failed delivery costs a store owner twice. Once for the outbound shipment that never arrived, and again for the return, the re-ship, or the refund. Somewhere in between there's a support conversation, and at the end of it there's a customer who is, at best, mildly annoyed at you for something they typed wrong.
The address was wrong at checkout. It stayed wrong through payment, fulfillment, packing, and handoff to the carrier. Nobody looked at it until a driver stood in front of a building that didn't match.
The fix seems obvious: check the address while the customer is still on the page. That's what DeliverSure does. But building it taught us that “check the address” hides a much harder question, and getting that question wrong is worse than not checking at all.
The question nobody asks first
What makes an address valid?
The intuitive answer is that it's real — a place a driver could actually go. But run a few real addresses through a validation service and you'll find the service has opinions you didn't expect.
An apartment building where the customer didn't type a unit number: real, deliverable, and incomplete. A rural property where the street exists in the mapping database but the specific house number doesn't: real, deliverable, and unconfirmed. A new-build development finished last spring: real, deliverable, and entirely absent from a database updated last winter. A UK address where the customer skipped the county and the service filled it in: real, deliverable, and inferred.
Every one of those is a legitimate order from a paying customer. Every one of them will trip a naive validation check.
And this is where address validation becomes dangerous rather than merely useless. A validator that's too strict doesn't produce a slightly worse checkout — it produces a checkout that rejects real customers at the moment they're trying to give you money. The failure mode is invisible to the store owner, because the customer who got blocked doesn't file a support ticket. They just leave.
We took the strictness problem seriously from the start. We still got it wrong on the first pass, in a way worth describing in detail, because the trap is well hidden.
The addressComplete trap
DeliverSure validates against Google's Address Validation API. The API returns a verdict object describing what it found — how precisely it resolved the address, whether components were inferred or corrected, whether anything went unconfirmed.
One of those fields is addressComplete. It reads like exactly what you want. If the address is complete, accept it; otherwise, flag it. Our first implementation did precisely that.
Two things make this wrong, and they compound.
The first is semantic. addressComplete is only true when Google finds zero missing components, zero unresolved tokens, and zerounexpected ones. That's a much higher bar than “deliverable.” An apartment without a unit number fails it. An address where Google inferred the postal code fails it. The field answers “is this address data pristine?” — which is a data-quality question, not a delivery question.
The second is structural. The API serializes in proto3 JSON, where a boolean that's false is simply omitted from the response rather than sent as false. So the field being absent and the field being false look identical from the outside. Any code that checks addressComplete === truetreats “Google didn't mention it” the same as “Google said no.”
Together, these mean a perfectly deliverable address — the kind that arrives at real doors every day — comes back looking like a rejection. Our early version would have blocked a meaningful fraction of good addresses, and the store owner would never have known why their conversion rate looked the way it did.
The fix was to stop asking whether the data was pristine and start asking how precisely Google resolved it. The API reports a validationGranularity: whether it got down to a specific sub-unit, a building, a street, a block, or only as far as a city, region, or country. That's the deliverability signal. If Google resolved to a building, a driver can find it, regardless of whether the customer typed the apartment number. If Google only got as far as the city, there's nothing to deliver to.
Same API, same response, completely different question — and the difference between an app that helps and an app that quietly costs you sales.
If you're integrating this API yourself: check the current field semantics in Google's documentation before relying on any of this. The behavior above is what we observed, but APIs move.
Three states, not two
Once we were reading granularity instead of completeness, a second design decision fell out of it.
Most validation is binary: valid or invalid. Addresses don't work that way. There's a real middle — addresses Google resolved to a street but not a building, addresses where components were inferred, addresses that look right but carry some uncertainty. Forcing those into “invalid” recreates the strictness problem. Forcing them into “valid” makes the check pointless.
So DeliverSure works in three states internally: deliverable, uncertain, and unresolvable. Only the last one is treated as a problem the customer needs to fix. The middle state is recorded but not surfaced at checkout — which brings us to the decision we spent the most time on.
Knowing when to say nothing
The hardest problem in checkout validation isn't accuracy. It's timing.
A checkout form is a live thing. The platform re-evaluates the order on every change, which means a validation plugin gets called constantly — after the street, after the city, after the postcode, after every correction. At almost every one of those moments the address is genuinely incomplete, because the customer is still typing it.
An app that reports what it sees will therefore spend most of the checkout telling the customer their address is wrong. Which it is. Because they haven't finished. This produces an error message that appears before the customer has entered anything meaningful, disappears, reappears, and reads to them as a broken store.
We landed on a hard rule: DeliverSure emits nothing until every field it intends to evaluate is already filled in. Not a softer warning during entry. Nothing.
That's only safe to do because of something worth stating plainly: Wix's checkout form already enforces required fields per country. A store owner physically cannot receive an order missing the fields their region requires. Checking for incompleteness ourselves would duplicate the platform and generate a hundred percent of the premature-message noise for zero merchant benefit.
So we drew the line there. Completeness is the platform's job. Realness is ours. Once we stopped trying to own both, the timing problem dissolved — the app is silent through the entire typing phase and speaks exactly once, when there's something real to say.
Failing open, on purpose
DeliverSure calls an external service. External services time out, rate-limit, and have bad afternoons.
Every failure path in the app resolves to the same outcome: the checkout proceeds. Validation service unreachable, settings unreadable, quota exhausted, an unexpected response shape — all of it passes silently and the order completes.
This is a deliberate trade and worth being explicit about, because it means the app will occasionally miss a bad address. We think that's obviously correct. The cost of missing one bad address is a delivery problem you already have today. The cost of blocking checkout during an outage is every order, for as long as the outage lasts. No address check is worth that, and any tool that sits in the payment path should be built so its worst day is invisible rather than catastrophic.
Telling the customer why
One more decision that turned out to matter more than we expected.
Store owners can restrict which countries they ship to. When an address falls outside that list, the customer needs to be told — and what they're told changes the outcome.
A generic “this address cannot be used” reads as a malfunction. The customer assumes the store is broken, tries again, and leaves. The same block phrased as “we don't currently deliver to Germany” reads as a policy. It's disappointing, but it's information, and it's the difference between a customer who thinks your store is broken and one who understands they're outside your shipping zone.
So blocked-country messages name the country explicitly, and store owners can edit the wording. It's a small thing that costs nothing and changes how a rejection lands.
What it does
Concretely: DeliverSure checks shipping addresses at checkout, before the order is placed. If an address can't be resolved to a real location, the customer sees a message asking them to check it — as a dismissible warning or a hard block, depending on configuration. Store owners can restrict delivery to specific countries and edit every message the customer sees.
It's live on the Wix App Market with a free tier.
Where it fits
This is the third app we've shipped for Wix, alongside Checkout Links and Checkout Add-ons & Fees. Each takes a moment in the checkout flow that's more awkward than it needs to be. Checkout Links shortens the path tocheckout. Add-ons & Fees handles money that doesn't fit the product model. DeliverSure catches bad data before it becomes a delivery problem.
All three run on the same backend — a single Cloudflare Worker in front of Neon Postgres handling tier enforcement and usage metering across the portfolio. That's a post for another day.
What we'd tell anyone building this
Three things, if you're integrating address validation into a checkout yourself:
Read the API's field semantics before trusting a field name. addressComplete means something specific and narrower than it sounds. So does almost everything else in that response.
Decide what the platform already handles, and don't duplicate it. Most of our premature-message problem came from checking something the checkout form was already enforcing.
Default to silence. In a live form, saying nothing is almost always safer than saying something premature. The bar for interrupting a customer who is actively trying to pay you should be very high.
Baseplate Digital builds practical software for Wix and Shopify merchants. More field notes at The Build Log.