
Free Shipping Thresholds
- 62 installs
- 41 repo stars
- Updated March 13, 2026
- finsilabs/awesome-ecommerce-skills
Increase average order value with a dynamic cart progress bar that nudges shoppers to add items to unlock free shipping.
About
Adds a free-shipping progress bar that updates as items are added, via native settings or apps per platform. A developer uses it to lift AOV, run tier-based thresholds, or A/B test the threshold amount.
- Per-platform tool recommendation table
- Dynamic 'add $X more' messaging with zone- and tier-based rules
Free Shipping Thresholds by the numbers
- 62 all-time installs (skills.sh)
- Ranked #1,194 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill free-shipping-thresholdsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 62 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 13, 2026 |
| Repository | finsilabs/awesome-ecommerce-skills ↗ |
What it does
Increase average order value with a dynamic cart progress bar that nudges shoppers to add items to unlock free shipping.
Files
Free Shipping Thresholds
Overview
A free shipping threshold motivates customers to add more to their cart to avoid paying for shipping — one of the highest-converting tactics for increasing average order value. The key is showing a dynamic progress bar ("Add $12 more for free shipping") that updates as items are added. Most platforms support this natively or via an app without writing any code.
When to Use This Skill
- When adding a free shipping banner or cart progress bar to increase average order value
- When different customer tiers should have different free shipping thresholds
- When A/B testing different threshold amounts to find the AOV sweet spot
- When you want to surface "add $X more to unlock free shipping" messages dynamically
- When free shipping rules should vary by shipping zone (domestic vs. international)
Core Instructions
Step 1: Determine your platform and choose the right tool
| Platform | Recommended Tool | Why |
|---|---|---|
| Shopify | Built-in shipping settings + Hextom Free Shipping Bar app | Shopify handles the rule; Hextom or similar apps add the visible progress bar |
| WooCommerce | WooCommerce Shipping (built-in free shipping method) + WooCommerce Free Shipping Bar plugin | WooCommerce has native free shipping rules; plugins handle the bar UI |
| BigCommerce | Built-in free shipping promotion + free shipping bar app | BigCommerce has native promotional rules for free shipping thresholds |
| Custom / Headless | Build a rule resolver + progress bar component | Full control over threshold logic, per-segment rules, and UI |
Step 2: Set up the free shipping rule
Shopify
Create the free shipping rate (required first): 1. Go to Settings → Shipping and delivery → Manage rates 2. Under your shipping zone, click Add rate 3. Name it "Free Shipping" and set the price to $0.00 4. Under Conditions, check "Only available if order meets conditions" → Based on order price → set the minimum order price (e.g., $75) 5. Save
Add the progress bar (Hextom Free Shipping Bar app — free tier available): 1. Install Hextom: Free Shipping Bar from the Shopify App Store 2. The app automatically detects your free shipping threshold from Shopify settings 3. Customize the bar text: "You're {{amount}} away from free shipping!" where {{amount}} is replaced dynamically 4. Place the bar on cart pages and/or the mini-cart via the app's theme editor 5. For tiered thresholds (e.g., lower threshold for loyalty members): use the paid tier of Hextom which supports customer-tag-based conditions
Alternative — Shopify Plus: use Scripts for per-segment thresholds:
- Shopify Scripts (Plus only) let you write Ruby-like code to apply different shipping rates based on customer tags
- Go to Online Store → Scripts → Shipping to set up segment-specific free shipping rules
WooCommerce
Create the free shipping method: 1. Go to WooCommerce → Settings → Shipping → [Your shipping zone] → Add shipping method 2. Select Free Shipping and click Add shipping method 3. Click on Free Shipping to configure it 4. Set "Free shipping requires..." to A minimum order amount and enter the threshold (e.g., $75) 5. Optionally check Coupon to also allow free shipping coupons to trigger this rule 6. Save changes
Add the progress bar:
- Install WooCommerce Free Shipping Bar by WPFactory (free on WordPress.org) or Iconic WooCommerce Free Gifts (paid, with bar feature)
- The WPFactory plugin automatically reads your free shipping threshold and shows the bar in the cart
- Configure the bar message in the plugin settings: "Add {{amount_remaining}} more to get free shipping!"
For customer-tier-based thresholds:
- Install the WooCommerce Role-Based Pricing plugin or use conditional logic in the Advanced Shipping plugin to apply different thresholds to different user roles
- A common approach: create a "Wholesale" user role with a custom free shipping method that triggers at a lower minimum order
BigCommerce
Create the free shipping promotion: 1. Go to Marketing → Promotions → Create a promotion 2. Choose Shipping promotion type 3. Set condition: "Cart subtotal is greater than or equal to [amount]" 4. Set action: "Free shipping" 5. Enable the promotion and set start/end dates if it's temporary
Add the progress bar:
- Install a free shipping bar app from the BigCommerce App Marketplace (search "free shipping bar")
- Rebolt ‑ Free Shipping Bar is available for BigCommerce and reads your promotion settings automatically
For geographic variation (domestic vs. international):
- Create separate shipping promotions for different shipping zones in BigCommerce
- Each promotion can be restricted to specific shipping zones
Step 3: Configure the progress bar message and upsell behavior
Regardless of platform, these messaging best practices apply:
1. Before threshold: "Add $12.50 more for FREE shipping!" — always show the specific dollar amount, not a percentage 2. Just before threshold ($5–$15 away): Consider showing product suggestions that fill the gap — "These popular items could qualify you:" (many apps support this) 3. At threshold: "You've unlocked FREE shipping!" with a congratulatory style — green color, checkmark icon 4. Place the bar on both the cart page and mini-cart drawer — customers who see it in the mini-cart have higher AOV
Custom / Headless
// Server-side: resolve free shipping status for a cart
function resolveShippingThreshold(params: {
cartSubtotalCents: number;
shippingCountry: string;
customerTags: string[];
thresholdRules: ShippingThresholdRule[];
}): { isFree: boolean; thresholdCents: number; amountNeededCents: number; progressPct: number } {
// Find the highest-priority matching rule
const rule = params.thresholdRules
.filter(r => r.isActive)
.filter(r => !r.countries?.length || r.countries.includes(params.shippingCountry))
.filter(r => !r.customerTags?.length || r.customerTags.some(t => params.customerTags.includes(t)))
.sort((a, b) => b.priority - a.priority)[0];
if (!rule) return { isFree: false, thresholdCents: 0, amountNeededCents: 0, progressPct: 0 };
const isFree = params.cartSubtotalCents >= rule.thresholdCents;
const amountNeededCents = Math.max(0, rule.thresholdCents - params.cartSubtotalCents);
const progressPct = Math.min(100, Math.round((params.cartSubtotalCents / rule.thresholdCents) * 100));
return { isFree, thresholdCents: rule.thresholdCents, amountNeededCents, progressPct };
}// React component for the progress bar
function FreeShippingBar({ amountNeededCents, progressPct, isFree }: {
amountNeededCents: number; progressPct: number; isFree: boolean;
}) {
const formatted = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' })
.format(amountNeededCents / 100);
return (
<div className="free-shipping-bar">
{isFree ? (
<p>You've unlocked FREE shipping!</p>
) : (
<p>Add <strong>{formatted}</strong> more for FREE shipping</p>
)}
<div className="progress-track">
<div className="progress-fill" style={{ width: `${progressPct}%` }} />
</div>
</div>
);
}Step 4: Set the right threshold amount
The threshold should be above your average order value (AOV) but achievable:
- Rule of thumb: Set the free shipping threshold at 20–30% above your current AOV
- Test the economics: If your average shipping cost is $8 and your gross margin is 40%, you need the incremental revenue from the upsell to cover the $8 shipping cost
- A/B test: Tools like Google Optimize (now GA4 Experiments) or Shopify's built-in theme A/B testing let you test different threshold amounts
Best Practices
- Show the progress bar on both the cart page and the mini-cart — customers who see the progress bar in the mini-cart add items more frequently than those who only see it at full checkout
- Update in real time — the bar should update immediately when items are added; stale values erode trust
- Use free shipping as the default reward, not a coupon code — requiring a code adds friction; automatic thresholds convert better
- Don't apply free shipping to international orders by default — international shipping costs can exceed your entire margin; set geographic restrictions from day one
- Communicate the threshold in the header/sitewide banner — "Free shipping on orders over $75" in the top bar sets expectations before customers even start shopping
Common Pitfalls
| Problem | Solution |
|---|---|
| Progress bar shows "free shipping" but checkout still charges | Double-check that the free shipping rate is active in your platform's shipping settings AND that no other rule is overriding it |
| Free shipping fires when a coupon reduces the cart below threshold | In WooCommerce, set the free shipping method to require "minimum order amount" after discounts; in Shopify, ensure the shipping rate uses post-discount subtotal |
| International customers see the free shipping bar | Scope your shipping rate to domestic zones only; configure the app to only show the bar for domestic visitors |
| Progress bar shows 100% but order is below threshold | Ensure progress calculation uses the same subtotal as the shipping rate rule (post-discount, excluding non-qualifying items) |
Related Skills
- @shipping-rate-calculator
- @coupon-management
- @discount-engine
- @loyalty-points-system
- @checkout-flow-optimization
{
"context": "Tests whether the agent correctly implements the shipping-status API endpoint with proper unit conversion and progress clamping, the FreeShippingProgress React component with the correct conditional rendering states and CSS class names, currency formatting, and animated progress bar styling. This scenario covers the full UI/API contract for the cart shipping progress feature.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Endpoint path",
"max_score": 6,
"description": "A GET endpoint at /api/cart/shipping-status (or equivalent route) is defined"
},
{
"name": "Response has isFree",
"max_score": 6,
"description": "The endpoint response includes an isFree boolean field"
},
{
"name": "threshold in dollars",
"max_score": 10,
"description": "The threshold field in the API response is in dollars (divided by 100 from the cents stored in the rule), or null"
},
{
"name": "amountNeeded in dollars",
"max_score": 10,
"description": "The amountNeeded field in the API response is in dollars (divided by 100), not cents"
},
{
"name": "progressPct clamped",
"max_score": 8,
"description": "progressPct is capped at 100 (using Math.min(100, ...) or equivalent) and is rounded to an integer"
},
{
"name": "null threshold returns null",
"max_score": 8,
"description": "FreeShippingProgress (or equivalent component) returns null / renders nothing when threshold is null"
},
{
"name": "Unlocked state message",
"max_score": 8,
"description": "When isFree is true, the component displays 'You unlocked FREE shipping!' (or functionally equivalent text containing 'unlocked' and 'FREE shipping')"
},
{
"name": "Not-yet-free message",
"max_score": 8,
"description": "When isFree is false, the component displays a message of the form 'Add [amount] more for FREE shipping'"
},
{
"name": "Intl.NumberFormat currency",
"max_score": 10,
"description": "Currency amounts are formatted using Intl.NumberFormat with locale 'en-US' and style 'currency' / currency 'USD'"
},
{
"name": "Unlocked CSS class",
"max_score": 8,
"description": "The unlocked state adds the CSS class 'shipping-progress--unlocked' (BEM modifier) to the container"
},
{
"name": "Progress bar fill transition",
"max_score": 10,
"description": "The progress bar fill element has a CSS transition for 'width' with a duration of 0.4s and ease-in-out timing (i.e., 'transition: width 0.4s ease-in-out' or equivalent)"
},
{
"name": "Both surfaces included",
"max_score": 8,
"description": "The progress bar component is placed in (or documented as being required in) both the main cart page and a mini-cart/drawer, not just one location"
}
]
}
Cart Shipping Progress Feature
Problem Description
Velox Shop's data team has found that customers who can see how close they are to earning free shipping add significantly more items to their cart before checking out. The product team wants to add a real-time shipping progress indicator to the storefront — both on the main cart page and in the slide-out mini-cart drawer — so customers always know how much more they need to spend.
The feature must reflect the current cart state immediately whenever items are added or removed; stale progress information that lingers after a cart change has been identified as a conversion killer in prior A/B tests.
You have been asked to build two things:
1. A backend route that the frontend can call to get the current shipping status for the active cart session. 2. A frontend React component that consumes the response and renders the progress indicator in three distinct visual states: no free shipping available, partway to the threshold, and threshold reached.
The designer has provided the following UI copy requirements:
- When the threshold has been reached: communicate that free shipping has been unlocked.
- When still working toward the threshold: tell the customer how much more they need to add, with the currency amount prominently displayed.
- When free shipping is not offered at all for this customer/zone combination: show nothing.
The designer also wants the progress bar fill to animate smoothly as the percentage changes.
Output Specification
Produce the following files:
server/routes/cart.ts(or.js) — the backend route handler for the shipping status endpoint. Assume helper functionsgetCart(sessionId),getCustomerSegments(userId),inferZoneFromIP(ip), andresolveShippingRule(subtotal, zone, segments)already exist and can be imported; stub them if needed.components/FreeShippingProgress.tsx(or.jsx) — the React component that accepts a shipping status object and renders the progress bar.components/FreeShippingProgress.css— the stylesheet for the component.INTEGRATION.md— a short note (max 10 lines) describing where in the storefront this component should be rendered.
{
"context": "Tests whether the agent uses the correct ShippingRule data model with proper field types and monetary conventions, and implements the rule-resolution logic that handles zone/segment filtering, date-bounded rules, and priority-based rule selection. The scenario covers the core domain model and resolver that underpin all other features.",
"type": "weighted_checklist",
"checklist": [
{
"name": "freeShippingThreshold type",
"max_score": 8,
"description": "ShippingRule has freeShippingThreshold typed as number | null (not just number or string)"
},
{
"name": "Monetary values in cents",
"max_score": 8,
"description": "freeShippingThreshold values are stored as integers representing cents (e.g., 7500 for $75, not 75 or 75.00)"
},
{
"name": "null means never-free",
"max_score": 8,
"description": "A rule with freeShippingThreshold === null is treated as 'no free shipping' (returns isFree: false), not as 'always free'"
},
{
"name": "Filters inactive rules",
"max_score": 8,
"description": "resolveShippingRule (or equivalent) skips rules where isActive is false"
},
{
"name": "Filters by date window",
"max_score": 8,
"description": "resolveShippingRule skips rules whose startsAt is in the future or endsAt is in the past"
},
{
"name": "Empty zones = all zones",
"max_score": 8,
"description": "A rule with an empty applicableZones array matches any shipping zone (catch-all behavior)"
},
{
"name": "Empty segments = all segments",
"max_score": 8,
"description": "A rule with an empty customerSegments array matches any customer (not just customers with no segment)"
},
{
"name": "Priority-based selection",
"max_score": 8,
"description": "When multiple rules are applicable, the rule with the highest priority number is selected"
},
{
"name": "Return shape",
"max_score": 8,
"description": "The resolver returns an object with isFree (boolean), threshold (number|null), and amountNeeded (number)"
},
{
"name": "amountNeeded is 0 when free",
"max_score": 8,
"description": "When isFree is true, amountNeeded is 0 (not negative or null)"
},
{
"name": "progressPct server-side",
"max_score": 8,
"description": "progressPct is calculated on the server/in the resolver (Math.min(100, ...) clamping applied), not deferred to the client"
},
{
"name": "Server-side eligibility",
"max_score": 12,
"description": "Shipping eligibility is computed in the backend/API layer and not solely determined from client-provided state"
}
]
}
Shipping Rule Engine
Problem Description
Volta Commerce is a mid-size online retailer that currently hard-codes a single $75 free-shipping threshold for all customers. The engineering team has been asked to replace this with a flexible rule engine that supports different thresholds for different customer tiers and shipping destinations, and can accommodate temporary promotional thresholds during sales events — all without shipping a code change every time a rule changes.
The business requirements are:
- Gold and Platinum loyalty members shipping within the US qualify for free shipping at $49+.
- Standard US customers qualify for free shipping at $75+.
- International customers (any zone not matched by a more specific rule) never qualify for free shipping via the rule engine.
- Rules can be scheduled to activate and deactivate on specific dates (for holiday promotions, etc.).
- When multiple rules match a customer's cart, the rule with the highest priority takes effect.
You have been asked to build a TypeScript module that models these rules and provides a function to determine, given a cart subtotal, a shipping zone, and a customer's segment memberships, whether the cart qualifies for free shipping and — if not — how much more the customer needs to spend.
Output Specification
Produce a single TypeScript file shipping-rules.ts that contains:
1. The ShippingRule type/interface definition. 2. A hardcoded array of at least the three rules described above (SHIPPING_RULES or similar). 3. A function that accepts a cart subtotal, a shipping zone string, and an array of customer segment strings, and returns an object indicating whether shipping is free, what the applicable threshold is, how much more the customer needs to spend to qualify, and the cart's progress toward the threshold as a percentage (0–100).
Also produce a short shipping-rules.test.ts (or equivalent test/demo script) that demonstrates the function returning correct results for at least these three cases:
- A Gold member in the US with a $40 cart.
- A standard US customer with a $60 cart.
- An international customer with a $200 cart.
You may use Node.js built-ins and TypeScript; no additional packages should be required to run the demo.
{
"context": "Tests whether the agent implements the upsell product-suggestion logic with the correct price range, cart exclusion, stock filter, result count, and ordering, and also correctly models a time-limited promotional shipping rule with higher priority than the existing base rule — without modifying the base rule. This scenario covers upsell gating, query parameters, and priority-based promotional rules.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Upsell threshold gate",
"max_score": 12,
"description": "Upsell suggestions are suppressed (returns empty / shows nothing) when amountNeeded is 0 or below, OR when amountNeeded exceeds 3000 cents ($30)"
},
{
"name": "Upsell price lower bound",
"max_score": 10,
"description": "Upsell product query filters for price >= amountNeeded (products must cost at least as much as the gap)"
},
{
"name": "Upsell price upper bound",
"max_score": 10,
"description": "Upsell product query filters for price <= amountNeeded + 1000 (up to $10 above the gap)"
},
{
"name": "Cart exclusion",
"max_score": 10,
"description": "Upsell product query excludes products already in the cart (filters out existing cartProductIds / cart item ids)"
},
{
"name": "In-stock filter",
"max_score": 8,
"description": "Upsell product query filters for inStock: true (out-of-stock products are excluded)"
},
{
"name": "Result limit of 4",
"max_score": 10,
"description": "Upsell query is limited to returning a maximum of 4 products"
},
{
"name": "Popularity ordering",
"max_score": 10,
"description": "Upsell results are ordered by popularity_score in descending order"
},
{
"name": "Promotional rule priority",
"max_score": 10,
"description": "The promotional shipping rule has a higher priority number than the standard/base rule it is meant to override"
},
{
"name": "Promotional date window",
"max_score": 10,
"description": "The promotional rule uses startsAt and endsAt (or equivalent) to bound its active period (not just isActive flag alone)"
},
{
"name": "Base rule unchanged",
"max_score": 10,
"description": "The original/base shipping rule is NOT modified; the promotion is implemented as a separate, additional rule"
}
]
}
Holiday Promotion and Upsell Suggestions
Problem Description
Meridian Goods is preparing for its holiday sale and wants to do two things at once: temporarily lower the free-shipping threshold for a limited window to drive higher order volumes, and show targeted product suggestions to customers who are just a few dollars short of qualifying.
The merchandising team has specifically flagged that irrelevant suggestions (shown when a customer is far from the threshold, or shown for out-of-stock items already in the cart) have hurt trust in previous campaigns. They want suggestions to appear only when they are actionable — i.e., when the customer is genuinely close to the threshold and one product addition could push them over.
The current codebase has a SHIPPING_RULES array with a standard rule that provides free shipping at $75 for US customers. The team does not want this rule changed; instead, the holiday promotion should be layered on top.
You have been asked to:
1. Add a holiday promotion rule to the existing rules array that lowers the free-shipping threshold to $50 for US and Canadian customers from December 1 through December 31, 2026. The promotion should automatically take precedence over the standard rule during that window. 2. Build a function getFreeShippingUpsells that, given the current cart subtotal (in cents), the gap to the threshold (in cents), and the list of product IDs already in the cart, returns a list of product suggestions from the database.
Output Specification
Produce the following files:
shipping-rules-holiday.ts— contains the updatedSHIPPING_RULESarray (or an exported holiday rule constant that can be spread into the array) and thegetFreeShippingUpsellsfunction. Assume adb.products.findAll(...)ORM method is available; stub or type it as needed.upsell-demo.ts— a short script that demonstrates thegetFreeShippingUpsellsfunction being called with at least two scenarios: one where the gap is small enough that suggestions should appear, and one where the gap is too large. Log the query parameters used in each case.
The existing standard rule (rule_us_standard, free shipping at $75 for US, priority 5) must remain present and unchanged in the output.
Input Files
The following files are provided as inputs. Extract them before beginning.
=============== FILE: existing-rules.ts =============== import { ShippingRule } from './types';
export const SHIPPING_RULES: ShippingRule[] = [ { id: 'rule_us_standard', name: 'Standard US — free shipping $75+', freeShippingThreshold: 7500, applicableZones: ['US'], customerSegments: [], priority: 5, isActive: true, startsAt: null, endsAt: null, }, { id: 'rule_international', name: 'International — no free shipping', freeShippingThreshold: null, applicableZones: [], customerSegments: [], priority: 1, isActive: true, startsAt: null, endsAt: null, }, ];
{
"name": "finsi/free-shipping-thresholds",
"version": "0.1.0",
"summary": "Dynamic free shipping rules with progress indicators and upsell nudges",
"skills": {
"free-shipping-thresholds": {
"path": "SKILL.md"
}
}
}