Server-side GTM
The sGTM plugin sends Funnel events directly to a server-side Google Tag Manager container
using the GA4 Measurement Protocol v2 JSON endpoint. Unlike the gtm plugin (which pushes
to window.dataLayer and relies on a browser snippet), this plugin bypasses the browser
container entirely and POSTs each event to a URL you control.
What it tracks
Section titled “What it tracks”Every Funnel event is sent as a single Measurement Protocol event with the same name and
parameters, plus event_id (for deduplication against browser events), a derived session_id,
and engagement_time_msec. User identity from setUser is attached as user_id /
user_properties. There is no event-name mapping. Names pass through unchanged.
Before you start
Section titled “Before you start”This is a server-relay plugin: there is no browser pixel global like gtag or fbq.
Instead it needs:
- The endpoint URL of your sGTM container (e.g.
https://sgtm.example.com). - A GA4 Measurement ID (
G-XXXXXXXXXX). - A
client_id, generated and persisted inlocalStorage(_funnel_sgtm_cid) automatically, or supplied viaclientId.
The GA4 Measurement Protocol API secret should not be placed in browser code: it would
leak in DevTools, proxy logs, and CDN access logs. The recommended setup is to leave apiSecret
unset and have your sGTM container skip api_secret validation for browser traffic. If you must
send it, you have to also set allowApiSecretInBrowser: true to acknowledge the risk; otherwise
the plugin strips it and logs an error.
Install & initialize
Section titled “Install & initialize”import { Funnel } from "@sunwjy/funnel-client";import { createSGTMPlugin } from "@sunwjy/funnel-client/sgtm";
export const funnel = new Funnel({ plugins: [createSGTMPlugin()], debug: true,});
funnel.initialize({ sgtm: { endpoint: "https://sgtm.example.com", measurementId: "G-XXXXXXXXXX", // path defaults to "/mp/collect" // engagementTimeMsec defaults to 1 },});Track an event
Section titled “Track an event”funnel.track("purchase", { currency: "KRW", value: 29000, transaction_id: "T-1",});Verify
Section titled “Verify”- Enable
debug: trueon theFunnelto log each dispatch. - Watch the Network tab for
POSTrequests to yourendpoint+ path (default/mp/collect). - Open GA4 DebugView (or your sGTM container’s preview) to confirm events arrive.
- SSR-safe:
trackis a no-op whenwindowis absent, or whenendpoint/measurementIdare missing. - A
client_idis persisted inlocalStorageand asession_idinsessionStoragewith a 30-minute idle timeout (GA4’s default). - Set
consentRequired: trueto drop events untilanalytics_storageis granted viasetConsent. The default is no gating (platform delegation). nonPersonalizedAdsand a customengagementTimeMseccan be set in config; the defaultengagementTimeMsecis1to avoid polluting GA4 engagement metrics.