We’re upgrading our email infrastructure — for immediate response, email andrewjgaber@gmail.com meanwhile.
Skip to main content
Part of Digital Empire
Product analytics / CDP

HubSpot Tracking Code (_hsq.push identify + trackEvent) at Shopify checkout

HubSpot · Web Pixels API replacement · confidence: medium

Dies 2026-08-26

Paste-ready snippet
// Wave4-Hotel7 (2026-08-20): HubSpot post-checkout identify + purchase-event
// replacement. The legacy HubSpot Tracking Code (`_hsq.push(['identify', {...}])`
// followed by `_hsq.push(['trackEvent', {id: 'purchase', ...}])`) was pasted
// into Shopify Additional Scripts / checkout.liquid by hundreds of B2B-adjacent
// DTC stores using HubSpot Marketing Hub for lifecycle email + nurture flows.
// Additional Scripts stops executing after checkout on 2026-08-26 -- from that
// date, HubSpot never sees the buyer's email/order and cannot fire the
// post-purchase workflow that upsells / requests a review / segments the
// contact as a customer instead of a lead.
//
// Two variants: pick ONE.
//
// ============================================================
// VARIANT A -- BROWSER-SIDE (Shopify Web Pixels sandbox).
// Uses the HubSpot Tracking Code that Shopify already loads if you've added
// hs-scripts.com/{hubId}.js to your theme.liquid <head> (which continues to
// work -- theme.liquid execution is NOT deprecated). Web Pixels sandbox
// exposes the shared `_hsq` global through window when the tracker is loaded
// in theme scope; we push identify + custom purchase event from inside
// analytics.subscribe('checkout_completed').
// ============================================================
analytics.subscribe('checkout_completed', (event) => {
  const { checkout } = event.data;
  if (!checkout || !checkout.email) return;

  // If HubSpot's tracker hasn't loaded yet (adblock / slow network),
  // fall back to Variant B server-side path instead of silently no-op.
  const hsq = (window && window._hsq) ? window._hsq : null;
  if (!hsq) return;

  hsq.push(['identify', {
    email: checkout.email,
    firstname: checkout.shippingAddress ? checkout.shippingAddress.firstName : undefined,
    lastname: checkout.shippingAddress ? checkout.shippingAddress.lastName : undefined,
  }]);

  hsq.push(['trackCustomBehavioralEvent', {
    name: 'pe_purchase',
    properties: {
      order_id: checkout.order ? String(checkout.order.id) : checkout.token,
      value: Number(checkout.totalPrice.amount),
      currency: checkout.totalPrice.currencyCode,
      item_count: (checkout.lineItems || []).length,
    },
  }]);

  hsq.push(['trackPageView']);
});

// ============================================================
// VARIANT B -- SERVER-SIDE (HubSpot Custom Behavioral Events API).
// Use if: (a) you have any backend that receives Shopify's orders/paid
// webhook, or (b) you want ad-blocker-proof, single-source-of-truth
// attribution. HUBSPOT_PRIVATE_APP_TOKEN is a HubSpot Private App token
// scoped to `behavioral_events.event_definitions.read_write` + `crm.objects.contacts.write`.
// Docs: https://developers.hubspot.com/docs/api/analytics/custom-events
// ============================================================
//
// // Shopify webhook: orders/paid
// export async function handleShopifyOrderPaidForHubspot(order) {
//   await fetch('https://api.hubapi.com/events/v3/send', {
//     method: 'POST',
//     headers: {
//       'Authorization': `Bearer ${process.env.HUBSPOT_PRIVATE_APP_TOKEN}`,
//       'Content-Type': 'application/json',
//     },
//     body: JSON.stringify({
//       eventName: 'pe' + process.env.HUBSPOT_ACCOUNT_ID + '_purchase',
//       email: order.email,
//       occurredAt: order.created_at,
//       properties: {
//         order_id: String(order.id),
//         value: Number(order.total_price),
//         currency: order.currency,
//         item_count: order.line_items.length,
//       },
//     }),
//   });
// }

Legacy pattern detected via: _hsq\.push\(\s*\[\s*['"]identify['"]|_hsq\.push\(\s*\[\s*['"]trackEvent['"]

What this does NOT cover

What this does NOT cover: HubSpot's pre-checkout page-view tracking (that still works via theme.liquid's tracker), form submissions, chat conversations, or the HubSpot Ads Pixel (which is a separate script, ads.hubspot.com/analytics.js, and has its own Additional Scripts breakage surface -- track separately). Also does not migrate abandoned-cart nurture workflows if those were triggered by _hsq events set from checkout stages before checkout_completed -- those need Web Pixels analytics.subscribe('checkout_started') hooks.

Test-event verification checklist

  • The custom event name in HubSpot must be prefixed with `pe{portalId}_` when calling the server-side Events API (`pe12345678_purchase`), but only with `pe_purchase` when using the browser-side _hsq queue -- HubSpot rewrites the browser-side name internally, and doing both yields a mismatched event that fires but never lands in the timeline. If you rename the event in HubSpot's UI, update both call sites in lockstep.
  • Verify a live purchase in Contacts > (contact) > Timeline within 5 minutes -- the pe_purchase event should appear beneath the identify call with the correct order_id and value. If identify fires but the purchase event does not, the hs-scripts.com/{hubId}.js tracker in theme.liquid is missing or blocked; add Variant B as a backstop.
  • Duplicate-check: if you have the HubSpot for Shopify app (formerly `hubspot-shopify`) installed, it already syncs orders and creates lifecycle events server-side. Adding Variant B on top will double-count the purchase. Choose ONE path. If the HubSpot Shopify app is installed, skip Variant B and only ship Variant A for the browser-side behavioral signal HubSpot's app does not capture.
  • Verify live against the platform's own test-event tool: https://developers.hubspot.com/docs/api/analytics/custom-events

Related paste-ready snippets

Product-analytics + CDP + CRM · HubSpot, Segment, Amplitude, Mixpanel, PostHog — every DTC brand ships at least one of these and all break the same way Aug 26.