and runs during HTML parse, but hubspotutk is set by js.hs-analytics.net, measured loading at ~834ms. On a first visit the cookie does not exist yet, so a single read returns nothing and the visitor gets no external ID at all — and a first visit is exactly what an ad click is. So poll briefly until HubSpot sets it. The SDK loads lazily (~4.5s) and replays a queue, so an init queued a second or two in still lands before any events are transmitted. */ (function attachExternalId() { var attempts = 0; var MAX_ATTEMPTS = 40; /* 40 x 200ms = 8s, then give up quietly */ var timer = null; function tryAttach() { var raw = getExternalId(); if (!raw) { if (++attempts >= MAX_ATTEMPTS && timer) clearInterval(timer); return; } if (timer) clearInterval(timer); sha256Hex(raw).then(function (hash) { oaiq("init", { user: { external_id_sha256: hash } }); }).catch(function () {}); } tryAttach(); /* returning visitor: immediate */ if (!getExternalId()) timer = setInterval(tryAttach, 200); })(); /* --------------------------------------------------------------------------- 2. Load the SDK off the critical path Whichever comes first: the main thread going idle after load, or the first sign of real user intent. No preconnect on purpose — a TLS handshake during LCP for a script we deliberately deferred is a net loss. Measured on clickpost.ai: load event 3614ms, SDK fetched 4508ms. ------------------------------------------------------------------------ */ var loaded = false; var INTENT = ["pointerdown", "keydown", "scroll"]; function loadSdk() { if (loaded) return; loaded = true; INTENT.forEach(function (t) { removeEventListener(t, loadSdk, { passive: true }); }); var s = document.createElement("script"); s.src = SDK; s.async = true; s.fetchPriority = "low"; document.head.appendChild(s); } INTENT.forEach(function (t) { addEventListener(t, loadSdk, { passive: true, once: true }); }); addEventListener("load", function () { window.requestIdleCallback ? requestIdleCallback(loadSdk, { timeout: 2500 }) : setTimeout(loadSdk, 1500); }, { once: true }); /* --------------------------------------------------------------------------- 3. Conversion id sha256(lowercase(email) + "|" + formId + "|" + ISO-hour), first 20 hex, "lead_" prefix. - email lowercased/trimmed so casing does not fork the id - formId keeps two different forms in the same hour from colliding - the hour bucket is only the server's fallback; the id computed here is sent to the relay verbatim, so the two paths cannot disagree even when a submit straddles an hour boundary Ads Manager's own sample omits event_id. We send it so the pixel event and the relay event collapse into one conversion instead of counting twice. ------------------------------------------------------------------------ */ function buildEventId(email, formId) { var seed = [ String(email || "").trim().toLowerCase(), String(formId || ""), new Date().toISOString().slice(0, 13) ].join("|"); return crypto.subtle.digest("SHA-256", new TextEncoder().encode(seed)).then(function (buf) { var hex = Array.prototype.map.call(new Uint8Array(buf), function (b) { return b.toString(16).padStart(2, "0"); }).join(""); return "lead_" + hex.slice(0, 20); }); } /* Guards a re-fire from the history.pushState that book-a-demo-core.js runs after submit, and from back-navigation onto the same state. */ function firedOnce(id) { try { if (sessionStorage.getItem("oaiq_" + id)) return true; sessionStorage.setItem("oaiq_" + id, "1"); return false; } catch (e) { return false; /* private mode / blocked storage: fire rather than lose it */ } } /* Path 2. keepalive lets the request finish even if the page navigates away. Failures are swallowed deliberately: a reporting call must never surface an error to someone who just submitted a form. The relay hashes the email server-side into user.emails_sha256 and adds the caller's IP and user agent, so this event carries the same match signals the pixel gets for free. */ function sendToRelay(email, formId, eventType, eventId) { try { var payload = { token: RELAY_TOKEN, email: email, form_id: formId || "", event_type: eventType, event_id: eventId, /* verbatim, so both paths always match */ source_url: location.href }; var oppref = getOppref(); if (oppref) payload.oppref = oppref; var externalId = getExternalId(); if (externalId) payload.external_id = externalId; fetch(RELAY_URL, { method: "POST", keepalive: true, headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }).catch(function () {}); } catch (e) {} } /* Capture the email while the form is still on the page. onFormSubmitted does not reliably carry submissionValues, and by then the form may be removed. */ var lastEmail = ""; document.addEventListener("submit", function (e) { var f = e.target; if (!f || !f.querySelector) return; var i = f.querySelector('input[name="email"], input[type="email"]'); if (i && i.value) lastEmail = i.value; }, true); /* Every HubSpot form on the site reports through this one message event, so no module or theme JS needs editing to add coverage. */ window.addEventListener("message", function (e) { var d = e.data; if (!d || d.type !== "hsFormCallback" || d.eventName !== "onFormSubmitted") return; var email = (d.data && d.data.submissionValues && d.data.submissionValues.email) || lastEmail; if (!email) return; /* without an email there is no stable id to dedupe on */ var eventType = EVENT_BY_FORM[d.id] || EVENT_DEFAULT; buildEventId(email, d.id).then(function (id) { if (firedOnce(id)) return; oaiq("measure", eventType, { type: DATA_TYPE }, { event_id: id }); /* path 1 */ sendToRelay(email, d.id, eventType, id); /* path 2 */ }); }); })();

91ÊÓÆµ

See where your logistics stands on automation Start assessment

Home > Blog >

How TURMS Redefined Post-Purchase with ClickPost — A Story of Smarter Returns and Seamless Delivery

How TURMS Redefined Post-Purchase with ClickPost — A Story of Smarter Returns and Seamless Delivery

Teerna Mandal
By Teerna Mandal

Ready to ship smarter? Talk to our logistics experts.

Trusted by 600+ brands

In this blog

    has carved a niche in India’s apparel market by fusing technology with comfort. From anti-stain shirts to water-repellent denim, the brand is reimagining what intelligent clothing can be. 

    But while its products were fulfilling the promise of effortless wear, its logistics needed a push to deliver the same level of customer convenience in the post-purchase journey.

    The call of the moment, before we forged the partnership, was rising returns — each one translating into lost revenue and disappointed customers. TURMS wanted a way to turn this challenge into an opportunity by nudging more returns into exchanges. 

    Alongside this, they sought sharper visibility across shipment processing and delivery, as well as stronger management of failed deliveries.

    To unpack these challenges, we sat down with , to hear how the brand has been using ClickPost to make post-purchase as intelligent as its clothing line. In his words:

    “When we onboarded, there was no option to convert returns into exchanges. Then it was implemented [and] the conversions happened.â€� 

     

    With ClickPost, TURM’s exchange rate got the boost it rightfully deserved. 

    When Growth Tests Retention

    TURMS was winning customers with its intelligent apparel. But the post-purchase journey risked slowing down growth momentum as customer retention started getting affected.

    Rising returns, fragmented shipment visibility, and failed deliveries were weighing down operations. Without fast improvements, the product experience risked being overshadowed by logistics friction.

    Here’s what the team was up against:

    • Returns vs. Exchanges - A steady rise in returns was eroding revenue. TURMS needed a structured way to nudge customers toward exchanges and protect customer relationships.

    • Fragmented Visibility - Delivery journeys were often marked by delays, stuck shipments, and failed handovers. Each delay raised customer queries and made on-time delivery without intelligent EDD prediction harder.

    • Failed Deliveries and Pickup Issues - Non-Delivery Reports (NDRs) and missed pickups were piling up. Every failure meant higher costs and a risk of frustrating otherwise loyal customers.

    • Lagging Feature Rollouts - TURMS needed quicker updates to keep pace with rising expectations. Slow feature development risked holding back improvements in customer convenience.

     

    Reframing Post-Purchase: How TURMS Found the Right Partner for Scale

    As TURMS expanded its footprint in intelligent apparel, scalability demanded more than its unique product catalogs. The customer journey after checkout needed the precision of technical innovation — one that matched customer expectations for clarity, speed, and convenience.

    In line with this, ClickPost approached TURMS with a tailored proposition and the brand saw an opportunity to strengthen its post-purchase journeys. TURMS wasn’t simply looking for an off-the-shelf tool. 

    The team wanted a partner who could build with them, adapting to their needs as they scaled. Bharath G M explained the impact in precise words:

    “[When] The request is placed, I can see whether it is for return or exchange. But most of the time, we are getting good exchange requests than returns.�

     

    The collaboration gave TURMS confidence that its post-purchase challenges could be addressed with technology-first solutions and responsive support.

    Turning Post-Purchase Into a Crowd-Pleaser

    With ClickPost onboard, TURMS transformed key areas of its post-purchase experience. Each solution was designed to reduce friction, drive exchanges, and strengthen customer loyalty.

    1. Returns Flipped to Exchanges

    ClickPost introduced an exchange-first flow that helped TURMS convert return requests into exchanges, protecting revenue and customer relationships.

     

    • AI-crafted nudges during the return journey to prompt exchanges.

    • Smart policy configuration to define SKU eligibility for exchanges.

    • Clear exchange visibility in the dashboard to track conversion rates.

    According to Bharath GM:

    “When a customer places a return request, we can nudge them to exchange instead — and that works quite well.�

     

    2. Shipment Processing and Tracking

    TURMS gained greater control and transparency over its order lifecycle, ensuring customers had a smoother experience from purchase to delivery.

     

    • Label generation and order manifestation in a centralized dashboard.

    • Real-time shipment visibility for improved SLA adherence.

    • Precise Estimated Delivery Dates (EDD) to set accurate expectations.

    • Proactive customer notifications to reduce WISMO queries.

    3. Failed Deliveries and Pickup Rescue

    Failed deliveries no longer meant lost opportunities. With structured NDR workflows and pickup rescues, TURMS could manage exceptions more efficiently.

     

    • Real-time NDR management with status updates.

    • Automated pickup rescue triggers to save failed orders.

    • Dashboard insights to track resolution and recovery rates.

    4. Proactive Support and Feature Rollouts

    TURMS experienced rapid feature rollouts and hands-on support, ensuring it could keep pace with customer expectations.

     

    • Dedicated support for configuration and implementation.

    • New features shipped within weeks of request.

    • Agile updates aligned with TURMS’ scaling needs.

    Bharath G M articulated the overall impact succinctly:

    “When we [first] onboarded ClickPost, we were missing a lot of updates. But when I reached out to customer support, they implemented [the changes] within 30 days. We quickly got new features that were not available when we onboarded.�

     

    Key Takeaways: Post-Purchase Done Right Is a Crowd-Pleaser

    TURMS’ journey shows that post-purchase isn’t back-office housekeeping — it’s part of the brand promise. By nudging more customers into exchanges, salvaging failed deliveries, and offering real-time shipment visibility, TURMS turned what could have been friction points into confidence-building moments.

    For other D2C brands, the message is clear: customer delight doesn’t end at checkout. It’s the post-purchase experience that keeps shoppers coming back and spreading the word.

     

    • Exchange-first flows prevent revenue leakage and keep customers engaged.

    • Shipment visibility with proactive updates keeps WISMO queries low and service teams lean.

    • Faster NDR resolution saves orders that might otherwise be written off.

    • Agile feature rollouts ensure logistics evolve in step with growth.

    What makes ClickPost and TURMS an ideal one is based on the outcome. Here’s what Bharath G M had to say:

    “We are getting all what we need in order processing, fulfillment, tracking, returns and exchanges, NPR/NDR. Configuration is good and user friendly. �

     

    Looking Ahead

    Today, TURMS continues to grow its presence in intelligent apparel while strengthening the trust built at every step of the customer journey. Together with ClickPost, the brand has shaped a post-purchase experience that mirrors the innovation woven into its clothing — seamless, reliable, and future-ready.

    This collaboration shows how technology-led partnerships can transform operational hurdles into customer delight. It allows D2C brands to focus on building products their customers love. At the same time, it ensures that every delivery, return, or exchange reinforces their promise of quality. To see the full engineering and business logic behind this success, refer to our detailed post-purchase platform overview.

    The Logistics Automation Platform for E-commerce

    Momentum Leader - G2 Users Most Likely To Recommend - G2 Best Results Mid-Market - G2
    . window.disableHubSpotCookieBanner = true; function killNative() { var n = document.getElementById("hs-eu-cookie-confirmation"); if (n && n.parentNode) { n.parentNode.removeChild(n); return true; } return false; } killNative(); if (window.MutationObserver) { var mo = new MutationObserver(function () { killNative(); }); mo.observe(document.documentElement, { childList: true, subtree: true }); setTimeout(function () { mo.disconnect(); }, 15000); } var COOKIE = "cp_cookie_consent"; var EU = ["at","be","bg","hr","cy","cz","dk","ee","fi","fr","de","gr","hu","ie","it","lv","lt","lu","mt","nl","pl","pt","ro","sk","si","es","se","gb","uk","is","li","no","ch"]; function readCookie(nm) { var m = document.cookie.match(new RegExp("(?:^|; )" + nm + "=([^;]*)")); return m ? decodeURIComponent(m[1]) : null; } function writeCookie(nm, val, days) { var d = new Date(); d.setTime(d.getTime() + (days * 864e5)); document.cookie = nm + "=" + encodeURIComponent(val) + ";expires=" + d.toUTCString() + ";path=/;SameSite=Lax" + (location.protocol === "https:" ? ";Secure" : ""); } function stored() { var raw = readCookie(COOKIE); if (!raw) return null; try { var o = JSON.parse(raw); if (typeof o.analytics === "boolean") return o; } catch (e) {} return null; } function apply(state, revoke) { window._hsp = window._hsp || []; window._hsp.push(["setHubSpotConsent", { analytics: !!state.analytics, advertisement: !!state.advertisement, functionality: !!state.functionality }]); if (revoke && !state.analytics && !state.advertisement && !state.functionality) { window._hsp.push(["revokeCookieConsent"]); } window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: "cp_cookie_consent", cp_consent_analytics: !!state.analytics, cp_consent_advertisement: !!state.advertisement, cp_consent_functionality: !!state.functionality }); document.documentElement.setAttribute("data-cp-consent", "set"); } function inScope(banner) { if (banner.getAttribute("data-scope") !== "eu_only") return true; var geo = (document.body.getAttribute("data-geo_location") || "").toLowerCase(); if (!geo) return true; return EU.indexOf(geo) !== -1; } function init(banner) { var days = parseInt(banner.getAttribute("data-days"), 10) || 180; var prefs = banner.querySelector("[data-cpcb-prefs]"); var compact = banner.querySelector('[data-cpcb-actions="compact"]'); var expanded = banner.querySelector('[data-cpcb-actions="expanded"]'); var toggles = banner.querySelectorAll("[data-cpcb-toggle]"); function show() { banner.hidden = false; requestAnimationFrame(function () { banner.classList.add("is-visible"); }); } function hide() { banner.classList.remove("is-visible"); setTimeout(function () { banner.hidden = true; }, 300); } function collapse() { if (!prefs) return; prefs.hidden = true; if (expanded) expanded.hidden = true; if (compact) compact.hidden = false; } function expand() { if (!prefs) return; prefs.hidden = false; if (compact) compact.hidden = true; if (expanded) expanded.hidden = false; } function paint(state) { Array.prototype.forEach.call(toggles, function (t) { var key = t.getAttribute("data-cpcb-toggle"); if (key === "necessary") { t.setAttribute("aria-checked", "true"); return; } t.setAttribute("aria-checked", state[key] ? "true" : "false"); }); } function fromToggles() { var state = { analytics: false, advertisement: false, functionality: false }; Array.prototype.forEach.call(toggles, function (t) { var key = t.getAttribute("data-cpcb-toggle"); if (key in state) state[key] = t.getAttribute("aria-checked") === "true"; }); return state; } function commit(state, revoke) { writeCookie(COOKIE, JSON.stringify({ analytics: !!state.analytics, advertisement: !!state.advertisement, functionality: !!state.functionality, v: 1, ts: Date.now() }), days); apply(state, revoke); hide(); } Array.prototype.forEach.call(toggles, function (t) { if (t.disabled) return; t.addEventListener("click", function () { t.setAttribute("aria-checked", t.getAttribute("aria-checked") === "true" ? "false" : "true"); }); }); banner.addEventListener("click", function (e) { if (!e.target || !e.target.closest) return; var btn = e.target.closest("[data-cpcb-action]"); if (!btn) return; var action = btn.getAttribute("data-cpcb-action"); if (action === "customise") { expand(); return; } if (action === "accept") { commit({ analytics: true, advertisement: true, functionality: true }, false); return; } if (action === "reject") { commit({ analytics: false, advertisement: false, functionality: false }, true); return; } if (action === "save") { commit(fromToggles(), true); return; } }); var existing = stored(); if (existing) { apply(existing, false); paint(existing); collapse(); } else if (!inScope(banner)) { // Out of the consent-required region: implied consent, banner never shown. commitSilently(); } else { collapse(); show(); } function commitSilently() { var all = { analytics: true, advertisement: true, functionality: true }; writeCookie(COOKIE, JSON.stringify({ analytics: true, advertisement: true, functionality: true, v: 1, ts: Date.now(), implied: true }), days); apply(all, false); } // Public re-open hook for a footer "Cookie settings" link. window.cpCookieBanner = window.cpCookieBanner || {}; window.cpCookieBanner.open = function () { var s = stored() || { analytics: false, advertisement: false, functionality: false }; paint(s); expand(); show(); }; } function boot() { var banners = document.querySelectorAll("[data-cpcb]"); if (!banners.length) return; init(banners[0]); document.addEventListener("click", function (e) { if (!e.target || !e.target.closest) return; var trigger = e.target.closest("[data-cp-cookie-settings]"); if (!trigger) return; e.preventDefault(); if (window.cpCookieBanner && window.cpCookieBanner.open) window.cpCookieBanner.open(); }); } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", boot); } else { boot(); } })();