Why Your Shoppers Abandon at the Shipping Step
Every online store loses shoppers at the same moment: the second they see “Standard Shipping” with no arrival date. A delivery ETA widget fixes this by showing each shopper their exact delivery date before they even enter their postcode. No plugin required. No app store subscription. Just a lightweight script that calculates transit times based on your warehouse location and the customer’s shipping zone.
Here is how to build one from scratch in under an hour.
What You Need
- Access to your store theme files (or a custom HTML block in your theme editor)
- Your warehouse postcode or city
- A list of transit times by shipping zone (your carrier provides this for free)
- Basic understanding of HTML and JavaScript (copy-paste ready below)
Step 1: Map Your Shipping Zones and Transit Times
Open a spreadsheet and list every shipping zone you ship to. For each zone, note the minimum and maximum transit time in business days. Your carrier already publishes this data. For example:
- Zone 1 (local metro): 1 to 2 business days
- Zone 2 (regional): 2 to 3 business days
- Zone 3 (interstate): 3 to 5 business days
- Zone 4 (remote): 5 to 7 business days
You will encode this into a JavaScript object that the widget uses to calculate the arrival date.
Step 2: Add the Widget Container to Your Product Page
In your theme editor, open the product page template. Add a container div where you want the ETA to appear. The best placement is directly below the add-to-cart button, before the shipping policy text.
<div id="delivery-eta-widget" style="padding: 12px 16px; border: 1px solid #e0e0e0; border-radius: 8px; margin: 12px 0; background: #fafafa;">
<p id="eta-message" style="margin: 0; font-size: 14px; color: #333;">
Enter your postcode to see your delivery date.
</p>
<input type="text" id="eta-postcode" placeholder="Postcode" style="margin: 8px 0; padding: 6px 10px; border: 1px solid #ccc; border-radius: 4px; width: 120px;">
<button onclick="calculateETA()" style="padding: 6px 16px; background: #333; color: #fff; border: none; border-radius: 4px; cursor: pointer;">Check</button>
</div>Step 3: Add the JavaScript Logic
Add this script at the bottom of your product page template, just before the closing body tag or in a custom JavaScript block.
<script>
const shippingZones = {
"1000-1999": { min: 1, max: 2, label: "Sydney metro" },
"2000-2999": { min: 1, max: 2, label: "Sydney metro" },
"3000-3999": { min: 1, max: 2, label: "Melbourne metro" },
"4000-4999": { min: 2, max: 3, label: "Brisbane metro" },
"5000-5999": { min: 3, max: 5, label: "Adelaide metro" },
"6000-6999": { min: 3, max: 5, label: "Perth metro" },
"7000-7999": { min: 3, max: 5, label: "Hobart metro" },
};
function calculateETA() {
const postcode = document.getElementById("eta-postcode").value.trim();
if (!postcode || postcode.length < 4) {
document.getElementById("eta-message").innerHTML = "Please enter a valid postcode.";
return;
}
const prefix = parseInt(postcode.substring(0, 4));
let zone = null;
for (const range in shippingZones) {
const [min, max] = range.split("-").map(Number);
if (prefix >= min && prefix <= max) {
zone = shippingZones[range];
break;
}
}
if (!zone) {
document.getElementById("eta-message").innerHTML = "Contact us for delivery times to your area.";
return;
}
const today = new Date();
const minDate = addBusinessDays(today, zone.min);
const maxDate = addBusinessDays(today, zone.max);
const minStr = minDate.toLocaleDateString("en-AU", { weekday: "short", day: "numeric", month: "short" });
const maxStr = maxDate.toLocaleDateString("en-AU", { weekday: "short", day: "numeric", month: "short" });
document.getElementById("eta-message").innerHTML =
"Order today for delivery between " + minStr + " and " + maxStr + ".";
}
function addBusinessDays(date, days) {
const result = new Date(date);
let added = 0;
while (added < days) {
result.setDate(result.getDate() + 1);
if (result.getDay() !== 0 && result.getDay() !== 6) {
added++;
}
}
return result;
}
</script>Step 4: Style It to Match Your Brand
The widget above uses neutral colours that work on most stores. To match your brand, adjust the border colour, background, button colour, and font size. If your store uses a dark theme, swap the background to a dark tone and the text to white.
A few style tips:
- Use your brand accent colour for the button
- Keep the border subtle, you want it to feel like helpful information, not a popup
- Make the arrival date text bold so it stands out at a glance
- Add a small truck or calendar icon if your theme supports it
Step 5: Add a Fallback for Unknown Zones
Not every postcode will be in your shipping zones object. Add a fallback message that directs shoppers to contact support or check your shipping policy page. This prevents the widget from looking broken for remote or international postcodes.
if (!zone) {
document.getElementById("eta-message").innerHTML =
"Delivery times vary for " + postcode + ". <a href='/shipping-policy'>Check our shipping policy</a> or contact us for an estimate.";
return;
}Step 6: Test With Real Postcodes
Before you publish, test the widget with postcodes from each of your shipping zones. Verify that:
- The arrival date skips weekends correctly
- The date format reads naturally (e.g. "Wed 15 Oct" not "2026-10-15")
- The widget handles invalid input gracefully
- The fallback message appears for postcodes outside your zones
Optional: Auto-Detect Location
If you want to get fancy, you can use a free geolocation API to pre-fill the shopper's approximate location. This removes the postcode entry step entirely. The shopper sees their delivery date the moment they land on the product page.
// Optional: auto-detect via browser geolocation
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(pos) {
fetch('https://api.postcodes.io/reverse?lon=' + pos.coords.longitude + '&lat=' + pos.coords.latitude)
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.status === 200 && data.result) {
document.getElementById('eta-postcode').value = data.result[0].postcode.split(' ')[0];
calculateETA();
}
});
});
}Note: Always ask for geolocation permission. Some shoppers will decline, and that is fine. The manual postcode entry is the fallback.
Why This Works Without a Plugin
The widget is pure HTML, CSS, and JavaScript. It runs entirely in the shopper's browser. No server-side processing, no database queries, no API calls to a third-party service. The only data it needs is your shipping zone map, which you hardcode once and update when your carrier changes transit times.
This means:
- Zero impact on page load speed
- No monthly subscription fee
- No privacy concerns (no customer data leaves the browser)
- Full control over the design and messaging
What to Measure After You Add It
Watch your checkout conversion rate for the week after you add the widget. Most stores see a measurable lift because the number one question shoppers have ("when will it get here?") is answered before they have to look for it.
Also watch your "where is my order" support tickets. They should drop, because shoppers saw a specific delivery date before they bought, not a vague "3 to 5 business days" that they immediately forgot.
Want more like this? Join MOKU Club for free. Weekly resources, early access to new guides, and occasional templates you can actually use. Join below.


