Google Analytics 4 (GA4)
Description
Section titled “Description”Google Analytics 4 is used for web analytics and conversion tracking across web applications.
App Coverage
Section titled “App Coverage”| App | Integrated |
|---|---|
| UK | ✅ |
| DE | ✅ |
Integration
Section titled “Integration”GA4 can be integrated via Google tag (gtag.js) API. An overview of the integration methods can be found via the links below:
Debug Tools
Section titled “Debug Tools”An overview of the debugging tools can be found via the links below:
- GA4 DebugView
- Chrome DevTools Network tab (
collect,g/collect) - Google Tag Assistant
- Consent Debug
Before integrating GA4, note the following:
- Default consent should be configured before GA4 loads.
- Event names and parameters should follow a consistent schema of the recommended events.
Plugin Usage Guide
Section titled “Plugin Usage Guide”The @releafuk/analytics package provides a custom GA4 plugin through the ga4Provider() factory function. GA4 is integrated directly through gtag.js, without requiring GTM.
Configuration
Section titled “Configuration”The ga4Provider() factory accepts the config parameter that should satisfy the Ga4Config type:
type GtagConfig = { debug_mode?: boolean; send_page_view?: boolean;};
type Ga4Config = { measurementId: string; enabled?: boolean; nonce?: string; gtagName?: string; dataLayerName?: string; gtagConfig?: GtagConfig;};| Option | Required | Default | Description |
|---|---|---|---|
measurementId | Yes | - | GA4 measurement ID |
enabled | No | true | Controls whether the provider loads and initializes GA4. Use false to keep the provider registered but disabled for an environment. |
nonce | No | - | CSP nonce added to the dynamically loaded Google tag script |
gtagName | No | gtag | Global Google tag function name |
dataLayerName | No | dataLayer | Global data layer name. |
gtagConfig | No | See below | Google tag configuration |
gtagConfig
Section titled “gtagConfig”The gtagConfig object is passed to the GA4 gtag("config", measurementId, gtagConfig) command during provider initialization. See the Google documentation for the GA4 configuration fields and page-view measurement.
| Option | Default | Description |
|---|---|---|
debug_mode | false | Marks events for GA4 DebugView. The provider also enables this automatically when analytics service debug mode is enabled. |
send_page_view | true | Controls whether GA4 sends a page_view event automatically when the provider runs the config command. |
The send_page_view option determines how page views are handled:
send_page_view: trueuses GA4 automatic page-view tracking. The custom GA4page()implementation does not send another event whenanalytics.page()is called.send_page_view: falsedisables the automatic page view sent by the GA4configcommand. The custom GA4page()implementation runs whenanalytics.page()is called and sends apage_viewevent withpage_title,page_location,page_path,page_hash,page_search, andpage_referrer.
Use send_page_view: false when the application controls navigation or needs to send page views manually, for example in a single-page application. Disabling the automatic page view avoids duplicate page_view events.
ga4Provider({ measurementId: import.meta.env.PUBLIC_GA4_MEASUREMENT_ID, gtagConfig: { debug_mode: import.meta.env.ENVIRONMENT === "development", send_page_view: false, },});Define GA4 event parameters under the ga4 provider key, then register ga4Provider() when creating the analytics service:
import { createAnalyticsService, createEvent, createEventDefinition, createEventRegistry, ga4Provider,} from "@releafuk/analytics";
const purchase = createEvent< { orderId: string; total: number; currency: string; items: Array<{ productId: string; name: string; }>; }, "purchase">({ name: "purchase",});
const events = createEventRegistry().register( createEventDefinition(purchase, { providers: { ga4: (data) => ({ name: "purchase", items: data.items.map((item) => ({ item_id: item.productId, item_name: item.name, })), currency: data.currency, value: data.total, transaction_id: data.orderId, }), }, }),);
export const analytics = createAnalyticsService({ app: "releaf", events, providers: [ ga4Provider({ measurementId: import.meta.env.PUBLIC_GA4_MEASUREMENT_ID, }), ], consent: { default: { analytics: "denied", advertising: "denied", functionality: "denied", adUserData: "denied", adPersonalization: "denied", }, },});
await analytics.init();Render the provider markup in the document head so the default consent command runs before GA4 is initialized. For example, in an Astro layout:
---import { analytics } from "@/libs/analytics";---
<head> { analytics.markup?.().map((contribution) => { if (contribution.kind === "inline-script") { return ( <script is:inline id={contribution.id} set:html={contribution.content} transition:persist /> ); } }) }</head>