A couple of years ago, I was helping a friend migrate their side hustle to Shopify. The storefront looked great, the checkout was smooth, and the product pages were converting. But a few weeks after launch, my friend was drowning in support emails.
They were all variations of the same question: "Where is my order?"
At first, I thought it was just a shipping delay issue. But looking closer, the packages were moving fine. The problem was the post-purchase experience. Once the customer clicked "pay," they were met with total silence until the package arrived. The default Shopify order status page just threw a plain text tracking link at them, sending them away to a carrier's clunky website.
The support burden was eating into their margins, and the anxiety was palpable. So I decided to build something.
The Hidden Cost of WISMO
In e-commerce, WISMO (Where Is My Order) tickets are often treated as an unavoidable side effect of doing business. But they are actually a massive hidden cost.
Think about the lifecycle of a WISMO ticket. A customer emails. A support agent has to log in, find the order, check the carrier's site, formulate a polite reply, and send it. For a small team, this context switching is brutal. For example, if a store receives 30 WISMO emails a day, that's easily a few hours of lost productivity daily.
Beyond the operational cost, there is a brand cost. The post-purchase phase is when buyer's remorse is highest. If you break the brand experience by sending them to a third-party courier site, you lose the trust you just built. Customers expect a seamless, branded experience from the moment they add an item to their cart until the day they unbox it.
Engineering the Solution
To fix this, we needed a way to keep the customer on the store's domain, showing real-time tracking status in a way that matched the store's design.
The main architectural decision was how to inject this into existing Shopify themes without breaking them. In the past, developers would have to manually edit theme liquid files. Today, Shopify's App Embed blocks allow us to inject UI elements safely and non-destructively.
Here is a simplified look at the App Embed block we use to render the tracking widget on the order status page:
{% comment %}
Renders shipment tracking widget on order status pages
{% endcomment %}
<div id="parcelglance-widget"
data-order-id="{{ order.id }}"
data-order-number="{{ order.name }}"
data-store-name="{{ shop.name }}"
style="min-height: 200px;">
</div>
<script>
(function() {
const script = document.createElement('script');
script.src = 'https://cdn.parcelglance.com/widget.js';
script.async = true;
script.onload = function() {
Parcelglance.init({
orderId: document.getElementById('parcelglance-widget').dataset.orderId,
orderNumber: document.getElementById('parcelglance-widget').dataset.orderNumber,
storeName: document.getElementById('parcelglance-widget').dataset.storeName,
container: 'parcelglance-widget',
});
};
document.head.appendChild(script);
})();
</script>
Let's break down the technical decisions here.
First, we use Liquid variables ({{ order.id }}, etc.) to pass the context securely to the frontend. We don't want to expose sensitive customer data, just the identifiers needed to fetch the tracking status.
Second, notice the min-height: 200px on the container div. When you load external scripts asynchronously, you risk Cumulative Layout Shift (CLS). By reserving the space upfront, the page doesn't jump around when the widget finally renders.
Third, we load the widget script asynchronously. This ensures that if our CDN is slow or the script fails to load, it doesn't block the main thread or delay the rendering of the rest of the order status page.
On the backend, the architecture had to evolve as well. Initially, I had the frontend widget poll carrier APIs directly. This was a mistake. Carrier APIs have strict rate limits, and hitting them on every page load is a quick way to get IP banned.
Instead, I shifted to a webhook-driven architecture. We listen to Shopify's orders/fulfilled webhooks. When an order is marked as shipped, our backend captures the tracking number and carrier. When building the webhook handler, verifying the HMAC signature is non-negotiable. You never want to trust incoming webhook data blindly. We use Node's crypto module to hash the raw body with the webhook secret and compare it to the x-shopify-hmac-sha256 header. Once verified, we sync with the carrier's API to get the initial status. Subsequent tracking updates are fetched via scheduled background jobs, not frontend requests. This keeps the frontend lightning fast and keeps us well within carrier API limits.
Practical Results and Lessons Learned
Building this taught me a lot about the intersection of developer experience and merchant experience.
What worked really well was the App Embed approach. Merchants were thrilled that they didn't have to touch a single line of theme code to get a branded tracking page. They just installed the app, toggled the embed block on, and it worked.
What surprised me was the emphasis on visual customization. I initially thought merchants just wanted the tracking data. It turned out they cared deeply about the widget matching their store's typography, colors, and button styles. A tracking page that looks like it belongs to a different brand defeats the purpose of keeping them on your site. I ended up spending a lot more time building a robust CSS variable system for the widget than I originally planned.
If I were to start over, I would implement the webhook architecture from day one. The transition from frontend polling to backend webhooks caused some temporary headaches with data consistency, but it was absolutely the right call for long-term stability.
Wrapping Up
The post-purchase experience shouldn't be an afterthought. By keeping customers informed with a branded, real-time tracking experience, you not only reduce support overhead but also turn a stressful waiting period into a positive brand touchpoint.
If you're dealing with WISMO tickets and want to give your customers a better post-purchase experience, I built a free tool to help with exactly this. You can check out the Shipment Tracking Widget at parcelglance.com to see how it works and add it to your store.
Full disclosure: I'm the developer of Parcelglance. I built this because I needed it myself.
Top comments (0)