Shopify Estimated Delivery Date Snippet

A business-day "arrives by" line that accounts for your cutoff time and holidays.

Describe the result you need. AI will set up the tool and ask for any missing details.

Configure with AI

Enter to submit · Shift + Enter for a new line

Sent to AI. Leave out passwords and private customer data.

Your details

Cutoff and processing

Orders placed after this time count as next business day.

days

Uses a number metafield named custom.processing_days, which you create per product.

Transit
days
days
Text

Your snippet file (snippets/estimated-delivery.liquid)

estimated-delivery.liquid
{%- comment -%}
  Estimated delivery date, calculated in the shopper's browser so it never goes stale on a cached page.

{%- endcomment -%}
{%- liquid
  assign processing_days = 1
  
-%}
<ea-estimated-delivery
  data-tz="America/New_York"
  data-cutoff="14:00"
  data-processing="{{ processing_days }}"
  data-transit-min="3"
  data-transit-max="5"
  data-skip-weekends="true"
  data-holidays="2026-11-26,2026-12-25,2027-01-01"
  data-template="Get it by {date} if you order today"
></ea-estimated-delivery>
<script>
  if (!customElements.get('ea-estimated-delivery')) {
    customElements.define('ea-estimated-delivery', class extends HTMLElement {
      connectedCallback() { this.render(); }
      partsIn(date, tz) {
        var map = {};
        new Intl.DateTimeFormat('en-US', { timeZone: tz, hourCycle: 'h23', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric' }).formatToParts(date).forEach(function (p) { map[p.type] = p.value; });
        return map;
      }
      render() {
        var tz = this.dataset.tz;
        var now;
        try { now = this.partsIn(new Date(), tz); } catch (e) { now = this.partsIn(new Date(), 'UTC'); }
        var cutoff = (this.dataset.cutoff || '14:00').split(':').map(Number);
        var afterCutoff = Number(now.hour) > cutoff[0] || (Number(now.hour) === cutoff[0] && Number(now.minute) >= cutoff[1]);
        var holidays = (this.dataset.holidays || '').split(',').filter(Boolean);
        var processingDays = Number(this.dataset.processing) || 0;
        var transitMin = Number(this.dataset.transitMin) || 0;
        var transitMax = Number(this.dataset.transitMax) || 0;
        var skipWeekends = this.dataset.skipWeekends === 'true';
        var startDays = processingDays + (afterCutoff ? 1 : 0);
        var base = new Date(Date.UTC(Number(now.year), Number(now.month) - 1, Number(now.day)));
        function addBusinessDays(date, days) {
          var d = new Date(date.getTime());
          var added = 0;
          var guard = 0;
          while (added < days && guard < 400) {
            d.setUTCDate(d.getUTCDate() + 1);
            guard++;
            var iso = d.toISOString().slice(0, 10);
            var dow = d.getUTCDay();
            if (skipWeekends && (dow === 0 || dow === 6)) continue;
            if (holidays.indexOf(iso) !== -1) continue;
            added++;
          }
          return d;
        }
        var minDate = addBusinessDays(base, startDays + transitMin);
        var maxDate = addBusinessDays(base, startDays + transitMax);
        var fmt = new Intl.DateTimeFormat(document.documentElement.lang || 'en-US', { weekday: 'short', month: 'short', day: 'numeric' });
        var text = transitMin === transitMax ? fmt.format(maxDate) : fmt.format(minDate) + '–' + fmt.format(maxDate);
        this.textContent = (this.dataset.template || 'Get it by {date}').replace('{date}', text);
      }
    });
  }
</script>

To install: in Shopify admin go to Online Store → Themes, click … next to your theme → Edit code. Under Snippets choose Add a new snippet, name it as shown above, paste this code and save. Add {% render 'estimated-delivery', product: product %} inside your product template, usually near the Buy buttons.

Label this clearly as an estimate. Carrier delays can still push delivery past this date.

Live preview

Why this runs in the visitor's browser

Shopify caches rendered product pages, so a date calculated when the page was last cached (using Liquid) would go stale, still showing yesterday's "arrives by" date to a shopper viewing the page today. This snippet works around that by calculating the date in the shopper's browser instead, every time the page loads, using your cutoff time, processing days, transit window and holiday list.

It skips weekends when you ask it to, skips any date in your holiday list, and compares the current time against your cutoff in the timezone you pick, not the shopper's own timezone, so the promise is accurate to your fulfillment schedule.

Adding it to a product page

  1. 01

    Add the snippet

    Online Store → Themes → Edit code → Snippets → Add a new snippet named estimated-delivery, paste the code, then add {% render 'estimated-delivery', product: product %} inside your product template, usually near the Buy buttons.

Questions people ask

Can different products have different processing times?

Turn on the per-product metafield option, then set a custom.processing_days number metafield on any product that needs a different value than your default.

Does it account for the shopper's own timezone?

No, on purpose: your cutoff time is about when your warehouse stops processing same-day orders, which happens in your timezone, not the shopper's.

What happens over a holiday?

Any date you list is skipped entirely, both as a possible cutoff day and when counting transit days, and treated like a closed day.

Is this legally binding shipping information?

Label it clearly as an estimate (the default text does this) and keep your written shipping policy as the source of truth. Delivery estimates can still be affected by carrier delays outside your control.

Want this builtinto your store?

I'm Emmanuel, a Shopify and WooCommerce developer. If this tool pointed at something you'd rather have fixed for you (a faster store, cleaner product data, a migration, a custom feature), send me a note.

Emmanuel Asika

Emmanuel Asika

Shopify & WooCommerce developer, Dublin

I build and fix online stores: new builds, migrations, speed, SEO and the custom bits apps can't do.

hello@emmanuelasika.com

Last reviewed 30 September 2026.