diff --git a/docs/02-app/01-building-your-application/06-optimizing/12-third-party-libraries.mdx b/docs/02-app/01-building-your-application/06-optimizing/12-third-party-libraries.mdx
index afc3badd11fc9..aba24ac1db60c 100644
--- a/docs/02-app/01-building-your-application/06-optimizing/12-third-party-libraries.mdx
+++ b/docs/02-app/01-building-your-application/06-optimizing/12-third-party-libraries.mdx
@@ -294,7 +294,11 @@ export function EventButton() {
return (
@@ -314,7 +318,11 @@ export function EventButton() {
return (
diff --git a/packages/third-parties/README.md b/packages/third-parties/README.md
index f325e42a4e341..21819008adb4a 100644
--- a/packages/third-parties/README.md
+++ b/packages/third-parties/README.md
@@ -40,4 +40,27 @@ export default function Page() {
}
```
+### Google Analytics Event
+
+The `sendGAEvent` function can be used to send an event to Google Analytics. This function uses the [gtag.js](https://developers.google.com/analytics/devguides/collection/ga4/events) library under the hood.
+
+```js
+import { sendGAEvent } from '@next/third-parties/google'
+
+export default function Page() {
+ return (
+
+ )
+}
+```
+
To get a better idea of how these components work, take a look at this [demo](https://test-next-script-housseindjirdeh.vercel.app/).
diff --git a/packages/third-parties/src/google/ga.tsx b/packages/third-parties/src/google/ga.tsx
index 40b00a685f3a0..010876dede6f4 100644
--- a/packages/third-parties/src/google/ga.tsx
+++ b/packages/third-parties/src/google/ga.tsx
@@ -3,7 +3,11 @@
import React, { useEffect } from 'react'
import Script from 'next/script'
-import type { GAParams } from '../types/google'
+import type {
+ GAParams,
+ GARecommendedEventName,
+ GARecommendedEventParams,
+} from '../types/google'
declare global {
interface Window {
@@ -56,14 +60,23 @@ export function GoogleAnalytics(props: GAParams) {
)
}
-export function sendGAEvent(..._args: Object[]) {
+export function sendGAEvent(
+ eventName: T,
+ eventParameters: T extends GARecommendedEventName
+ ? GARecommendedEventParams[T]
+ : { [key: string]: string | number }
+) {
if (currDataLayerName === undefined) {
console.warn(`@next/third-parties: GA has not been initialized`)
return
}
if (window[currDataLayerName]) {
- window[currDataLayerName].push(arguments)
+ window[currDataLayerName].push({
+ 0: 'event',
+ 1: eventName,
+ 2: eventParameters,
+ })
} else {
console.warn(
`@next/third-parties: GA dataLayer ${currDataLayerName} does not exist`
diff --git a/packages/third-parties/src/types/google.ts b/packages/third-parties/src/types/google.ts
index 808d60cc6387c..de9111b22bbb4 100644
--- a/packages/third-parties/src/types/google.ts
+++ b/packages/third-parties/src/types/google.ts
@@ -54,3 +54,191 @@ export type YouTubeEmbed = {
params?: string
style?: string
}
+
+// https://developers.google.com/tag-platform/gtagjs/reference/events
+type GAEventItemParam = {
+ item_id: string
+ item_name: string
+ affiliation?: string
+ coupon?: string
+ discount?: number
+ index?: number
+ item_brand?: string
+ item_category?: string
+ item_category2?: string
+ item_category3?: string
+ item_category4?: string
+ item_category5?: string
+ item_list_id?: string
+ item_list_name?: string
+ item_variant?: string
+ location_id?: string
+ price?: number
+ quantity?: number
+ [x: string]: any // can add item-scoped custom parameters
+}
+
+export type GARecommendedEventParams = {
+ add_payment_info: {
+ currency: string
+ value: number
+ coupon?: string
+ payment_type?: string
+ items: GAEventItemParam[]
+ }
+ add_shipping_info: {
+ currency: string
+ value: number
+ coupon?: string
+ shipping_tier?: string
+ items: GAEventItemParam[]
+ }
+ add_to_cart: {
+ currency: string
+ value: number
+ items: GAEventItemParam[]
+ }
+ add_to_wishlist: {
+ currency: string
+ value: number
+ items: GAEventItemParam[]
+ }
+ begin_checkout: {
+ currency: string
+ value: number
+ coupon?: string
+ items: GAEventItemParam[]
+ }
+ earn_virtual_currency: {
+ virtual_currency_name?: string
+ value?: number
+ }
+ exception: {
+ description?: string
+ fatal?: boolean
+ }
+ generate_lead: {
+ currency: string
+ value: number
+ }
+ join_group: {
+ group_id?: string
+ }
+ level_end: {
+ level_name?: string
+ success?: boolean
+ }
+ level_start: {
+ level_name?: string
+ }
+ level_up: {
+ level?: number
+ character?: string
+ }
+ login: {
+ method?: string
+ }
+ page_view: {
+ page_location?: string
+ client_id?: string
+ language?: string
+ page_encoding?: string
+ page_title?: string
+ user_agent?: string
+ }
+ post_score: {
+ score: number
+ level?: number
+ character?: string
+ }
+ purchase: {
+ currency: string
+ value: number
+ transaction_id: string
+ coupon?: string
+ shipping?: number
+ tax?: number
+ items: GAEventItemParam[]
+ }
+ refund: {
+ currency: string
+ transaction_id: string
+ value: number
+ coupon?: string
+ shipping?: number
+ tax?: number
+ items?: GAEventItemParam[]
+ }
+ remove_from_cart: {
+ currency: string
+ value: number
+ items: GAEventItemParam[]
+ }
+ search: {
+ search_term: string
+ }
+ select_content: {
+ content_type?: string
+ content_id?: string
+ }
+ select_item: {
+ item_list_id?: string
+ item_list_name?: string
+ // * The items array is expected to have a single element, representing the selected item. If multiple elements are provided, only the first element in items will be used. https://developers.google.com/tag-platform/gtagjs/reference/events#select_item
+ items: [GAEventItemParam]
+ }
+ select_promotion: {
+ creative_name?: string
+ creative_slot?: string
+ promotion_id?: string
+ promotion_name?: string
+ items?: GAEventItemParam[]
+ }
+ share: {
+ method?: string
+ content_type?: string
+ item_id?: string
+ }
+ sign_up: {
+ method?: string
+ }
+ spend_virtual_currency: {
+ value: number
+ virtual_currency_name: string
+ item_name?: string
+ }
+ // tutorial begin has no parameters
+ tutorial_begin: {}
+ tutorial_complete: {}
+ unlock_achievement: {
+ achievement_id: string
+ }
+ view_cart: {
+ currency: string
+ value: number
+ items: GAEventItemParam[]
+ }
+ view_item: {
+ currency: string
+ value: number
+ items: GAEventItemParam[]
+ }
+ view_item_list: {
+ item_list_id?: string
+ item_list_name?: string
+ items: GAEventItemParam[]
+ }
+ view_promotion: {
+ creative_name?: string
+ creative_slot?: string
+ promotion_id?: string
+ promotion_name?: string
+ // * The items array is expected to have a single element, representing the item associated with the promotion. If multiple elements are provided, only the first element in items will be used. https://developers.google.com/tag-platform/gtagjs/reference/events#view_promotion
+ items: [GAEventItemParam]
+ }
+ view_search_results: {
+ search_term?: string
+ }
+}
+
+export type GARecommendedEventName = keyof GARecommendedEventParams