0

I've tried to add an event on an 'Add to cart' button, but it is not triggering and I don't know hot to do it.

ReactGA4.gtag("event", "add_to_cart", {
      currency: "RON",
      value: price,
      items: [
        {
          item_id: id,
          item_name: title,
          item_category: 'book',
          price,
          quantity: 1,
        },
      ],
    });

The initialisation is correct, other events such as pageviews work.

I expect to send that event whenever I click that button.

1 Answers1

0

To solve the problem, I created my own implementation of Google Tag Manager with manual calls to Google Analytics.

I use React (18.0.9) with TypeScipt

type WindowWithDataLayer = Window & {
  dataLayer: Record<string, any>[]
}

declare const window: WindowWithDataLayer

/**
 * Provider for Google analytics with Google Tag Manager
 */
export default class GoogleTagManagerProvider implements IAnalyticsProvider {
  /**
   * The global unique id of provider
   */
  GUID = 'GoogleTagManager'

  private _id: string

  /**
   * Create a new instance of GoogleTagManagerProvider
   * @param id The measurement ID
   */
  constructor(id: string) {
    this._id = id
    window.dataLayer = window.dataLayer || []
  }

  /**
   * Initialize the analytics provider
   */
  initialize(): void {
    // Default consent mode is "denied" for both ads and analytics as well as the optional types, but delay for 2 seconds until the Cookie Solution is loaded
    this.gtag({
      consent: 'default',
      ad_storage: 'denied',
      analytics_storage: 'denied',
      functionality_storage: 'denied', // optional
      personalization_storage: 'denied', // optional
      security_storage: 'denied', // optional
      wait_for_update: 2000 // milliseconds
    })

    // Improve ad click measurement quality (optional)
    this.gtag({
      set: {
        url_passthrough: true
      }
    })

    // Further redact your ads data (optional)
    this.gtag({
      set: {
        ads_data_redaction: true
      }
    })

    this.gtag({
      js: new Date()
    })

    this.gtag({
      config: this._id,
      debug_mode: IsDevelopment
    })

    window.dataLayer.push({
      'gtm.start': new Date().getTime(),
      event: 'gtm.js'
    })
    var f = document.getElementsByTagName('script')[0]
    var j = document.createElement('script')
    j.async = true
    j.src = `https://www.googletagmanager.com/gtm.js?id=${this._id}`
    if (f.parentNode) {
      f.parentNode.insertBefore(j, f)
    }
  }

  /**
   * Informs the provider that the consent for the user's data has changed
   * @param consent The user consent
   */
  onConsentChanged(consent: IConsent) {
    // Alredy handled by iubenda
  }

  /**
   * Fire the page view event
   */
  pageView(): void {
    this.gtag({
      event: 'page_view',
      page_title: document.title,
      page_location: window.location.href
    })
  }

  /**
   * Fire login event
   * @param method The login event such as Email, Google or Facebook
   */
  login(method: string) {
    this.gtag({
      event: 'login',
      method: method
    })
  }

  /**
   * Fire sign up event
   * @param method The login event such as Email, Google or Facebook
   */
  signUp(method: string) {
    this.gtag({
      event: 'sign_up',
      method: method
    })
  }

  /**
   * Fire the add to cart event
   * @param product The product added to cart
   */
  addToCart(product: IProduct): void {
    const totalAmount = PriceUtility.calculateTotalAmount(product.price)
    this.gtag({
      event: 'add_to_cart',
      ecommerce: {
        currency: 'EUR',
        value: totalAmount,
        items: [
          {
            item_id: product.id,
            item_name: product.name,
            discount: product.price.amount - totalAmount,
            price: product.price.amount,
            quantity: 1
          }
        ]
      }
    })
  }

  /**
   * Fire the remove from cart event
   * @param product The product removed to cart
   */
  removeFromCart(product: IProduct) {
    const totalAmount = PriceUtility.calculateTotalAmount(product.price)
    this.gtag({
      event: 'remove_from_cart',
      ecommerce: {
        currency: 'EUR',
        value: totalAmount,
        items: [
          {
            item_id: product.id,
            item_name: product.name,
            discount: product.price.amount - totalAmount,
            price: product.price.amount,
            quantity: 1
          }
        ]
      }
    })
  }

  /**
   * Fire the begin checkout event
   * @param cart The cart
   */
  beginCheckout(cart: ICart) {
    const items: any[] = []

    cart.details.forEach((value, index) => {
      const totalAmount =
        PriceUtility.calculateTotalAmount(value.product.price) * value.quantity

      const baseAmount = value.product.price.amount * value.quantity

      const totalDiscount = baseAmount - totalAmount

      items.push({
        item_id: value.product.id,
        item_name: value.product.name,
        discount: totalDiscount,
        price: baseAmount,
        quantity: value.quantity
      })
    })

    this.gtag({
      event: 'begin_checkout',
      value: items.reduce(
        (previousValue, currentValue) =>
          previousValue + (currentValue.price - currentValue.discount),
        0
      ),
      currency: 'EUR',
      items: items
    })
  }

  /**
   * Fire the purchase event
   * @param transactionId The payment transaction Id
   * @param cart The cart
   */
  purchase(transactionId: string, cart: ICart) {
    const items: any[] = []

    cart.details.forEach((value, index) => {
      const totalAmount =
        PriceUtility.calculateTotalAmount(value.product.price) * value.quantity

      const baseAmount = value.product.price.amount * value.quantity

      const totalDiscount = baseAmount - totalAmount

      items.push({
        item_id: value.product.id,
        item_name: value.product.name,
        discount: totalDiscount,
        price: baseAmount,
        quantity: value.quantity
      })
    })

    this.gtag({
      event: 'purchase',
      transaction_id: transactionId,
      value: items.reduce(
        (previousValue, currentValue) =>
          previousValue + (currentValue.price - currentValue.discount),
        0
      ),
      currency: 'EUR',
      items: items
    })
  }

  /**
   * Fire the join group event
   * @param groupId
   */
  joinGroup(groupId: string) {
    this.gtag({
      event: 'join_group',
      group_id: groupId
    })
  }

  gtag(args: any) {
    window.dataLayer.push(args)
  }
}