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 */
});
});
})();
Track Gati Packages with the ClickPost Tracking Page
Fetch the order number from the shipment confirmation email.
Visit the ClickPost tracking page.
Enter the order number in the designated field.
Click on Track to view the latest order status.
Track Gati Packages on the Official Page
Visit the Gati Tracking page
Enter the Gati courier tracking number in the box.
Click on “Track”
View the status of your order instantly.
List of Gati APIs
API
Description
Manifestation and shipping label generation API
Instantly print shipping labels in bulk without breaking a sweat, no matter how heavy your order volume gets.
Track Shipment API
Track Gati shipments in real time, all from a single, clean dashboard.
Cancellation API
Need to pull the plug on a shipment? Send a quick automated command to cancel Gati orders instantly.
EDD API
Give your customers peace of mind by showing accurate, live delivery timelines directly on your product and checkout pages.
NDR Action Update
Salvage failed deliveries on the fly using smart, AI-powered voice bots to resolve delivery issues right away.
Return Webhooks
Handle customer returns and flip refunds seamlessly behind the scenes with instant automated alerts.
API & Description
Manifestation and shipping label generation API
Instantly print shipping labels in bulk without breaking a sweat, no matter how heavy your order volume gets.
Track Shipment API
Track Gati shipments in real time, all from a single, clean dashboard.
Cancellation API
Need to pull the plug on a shipment? Send a quick automated command to cancel Gati orders instantly.
EDD API
Give your customers peace of mind by showing accurate, live delivery timelines directly on your product and checkout pages.
NDR Action Update
Salvage failed deliveries on the fly using smart, AI-powered voice bots to resolve delivery issues right away.
Return Webhooks
Handle customer returns and flip refunds seamlessly behind the scenes with instant automated alerts.
Frequently asked questions
How can a brand integrate Gati courier API into their ecommerce website for real-time tracking?
The direct route is registering for API access through Gati's developer portal, getting credentials, and building around their tracking endpoints. It works, but comes with ongoing maintenance every time Gati pushes an update on their end.The faster route is through a multi-carrier platform like ClickPost. One API integration gets Gati live alongside 600+ other carriers, with branded tracking pages, automated customer notifications, and real-time status updates already handled. Most stores go live within a few days with minimal engineering effort.
How reliable is Gati tracking API for surface freight across tier-2 cities in India?
Gati has strong surface freight coverage across India, including Tier 2 and Tier 3 cities, which is one of its core strengths. That said, tracking update frequency for surface shipments can lag behind air freight, status changes sometimes take longer to reflect in real time. For brands where tracking granularity matters, routing Gati through a platform like ClickPost helps normalise those updates into a consistent timeline regardless of the underlying carrier behaviour.
What is the Gati KWE tracking API and how does it work for B2B logistics in India?
Gati KWE is a joint venture between Gati and Kintetsu World Express, focused on express distribution and supply chain solutions for B2B operations. Their tracking API lets businesses pull live shipment status, delivery confirmations, and transit updates directly into their own systems. It's particularly useful for businesses managing high-volume B2B dispatches across India where surface freight and warehousing are involved. Integration can be done directly or through a middleware platform for cleaner data standardisation across multiple carriers.
How does ClickPost standardise tracking updates across multiple couriers?
It pulls data from all your carriers and translates their different status codes into one clean, unified timeline. Your team and your customers see the exact same clear milestones, regardless of who is shipping the package.
How does the platform handle stuck or delayed shipments?
ClickPost automatically flags anomalies and Non-Delivery Reports (NDRs). Instead of waiting for a customer complaint, the system immediately alerts your team or triggers an automated workflow to resolve the issue with the courier.
Can the tracking page be fully branded?
Yes. You can completely customize the tracking page with your logo, colours, and fonts. It also supports product recommendations and promotional banners to help drive repeat purchases.
How does the system determine the best courier for an order?
It uses an automated AI-driven routing engine. You set the priority rules, such as lowest cost, fastest delivery speed, or regional performance, and ClickPost automatically assigns the optimal carrier for each shipment.
By how much does ClickPost reduce customer support tickets?
Most brands see a 30% to 40% reduction in "Where is my order?" inquiries. ClickPost achieves 60% reduction in WISMOs by sending proactive SMS, WhatsApp, and email updates the moment a milestone changes or a delay occurs.