useGtm
Pushes ecommerce events (view, impressions, click, add to cart, checkout, purchase) to Google Tag Manager's dataLayer when the store has GTM.
import { useGtm, UseGtmResult } from '@salla.sa/twilight-theme-engine/hooks/useGtm';In plain words
If the merchant connected Google Tag Manager, you can report what shoppers do: detail(product) when they view a product, add(product) when they add it to the cart, and so on. The hook builds the event objects in the shape GTM ecommerce tags expect.
If the store has no GTM container, enabled is false and every call quietly does nothing.
Signature
function useGtm(): UseGtmResult
interface UseGtmResult {
enabled: boolean;
push: (data: Record<string, unknown>) => void;
viewPage: (pageType: string) => void;
detail: (product: Product) => void;
impressions: (products: Product[], list?: string) => void;
click: (product: Product, list?: string, position?: number) => void;
add: (product: Product, quantity?: number) => void; // quantity 1
remove: (item: CartItem) => void;
checkout: (cart: Cart, step?: number) => void; // step 1
purchase: (orderId: string | number, cart: Cart) => void;
}Try it live
enabled: true · store.settings.keys.gtm: ["GTM-TGFC6FV"]
import { useEffect } from 'react';
import { useGtm } from '@salla.sa/twilight-theme-engine/hooks/useGtm';
export function TrackPageView() {
const { viewPage } = useGtm();
useEffect(() => {
viewPage('playground'); // does nothing when the store has no GTM container
}, [viewPage]);
return null;
}
Example
import { useEffect } from 'react';
import { useGtm } from '@salla.sa/twilight-theme-engine/hooks/useGtm';
import type { Product } from '@salla.sa/twilight-theme-engine/types';
export function TrackProductView({ product }: { product: Product }) {
const { detail } = useGtm();
useEffect(() => {
detail(product); // an effect: it writes to window.dataLayer
}, [detail, product]);
return null;
}
How it behaves
enabledisstore.settings.keys.gtmhaving at least one id.pushreturns early when it isfalse; otherwisewindow.dataLayer = window.dataLayer || []andwindow.dataLayer.push(data).Events are
{ event, ecommerce: { currencyCode, event_id, <detail | impressions | click | add | remove | checkout | purchase>: … } }, withevent_idlikedetail_<timestamp>_<random>.viewPagepushes{ event: 'viewPage', pageType }.Products become
{ id, name, price: sale_price, brand: brand?.name, category: category?.name, quantity: 1 }, pluspositionandlistfor impressions and clicks.currencyCodeis the product'scurrencyfor product events; otherwise the logged-in customer'spreferences.currency_code, elseSAR.remove,checkoutandpurchasealways use that fallback.The functions are memoised on
enabledand the currency, so they are safe as effect dependencies.It calls
useUser()for the currency. The GTM container itself is loaded by the defaultbody:starthandler; this hook only pushes events.
Gotchas
Product events send
price: product.sale_price, and the Store API answerssale_price: nullfor some products that are not on sale (checked on the demo store). Push your own event withpush()if your tags need a price every time.Call the functions from effects or event handlers, never while rendering: they write to
window, which the server does not have, and a render can run more than once.packages/theme-engine/docs/useLocation.md passes
location.pathnametoviewPage, whose parameter is a page type, not a path.
Related
The logged-in customer as a TanStack Query result, plus an isLoggedIn flag; it never requests anything for guests.
registerDefaultHooksRegisters the engine's built-in slot handlers (GTM, bundles, store closed, fast checkout, price quote, pre-order); importing the hooks module already runs it.
useProductKeeps a live copy of a product that follows price and stock changes from Salla option pickers, and can reload its details.