Coder Social home page Coder Social logo

zadigetvoltaire / nuxt-gtm Goto Github PK

View Code? Open in Web Editor NEW
61.0 3.0 4.0 868 KB

Nuxt 3 module for Google Tag Manager

Home Page: https://www.npmjs.com/package/@zadigetvoltaire/nuxt-gtm

License: MIT License

JavaScript 6.15% Makefile 0.73% Vue 45.33% TypeScript 47.79%
nuxt google-tag-manager googletagmanager gtm module nuxt-module nuxt3 open-source

nuxt-gtm's Introduction

Nuxt GTM

npm version npm downloads License Nuxt

Nuxt Google Tag Manager module integrated with the Nuxt Devtools for Nuxt 3.

This library is an Nuxt 3 module wrapper of the @gtm-support/vue-gtm plugin

Quick Setup

  1. Add @zadigetvoltaire/nuxt-gtm dependency to your project
# Using pnpm
pnpm add -D @zadigetvoltaire/nuxt-gtm

# Using yarn
yarn add --dev @zadigetvoltaire/nuxt-gtm

# Using npm
npm install --save-dev @zadigetvoltaire/nuxt-gtm
  1. Add @zadigetvoltaire/nuxt-gtm to the modules section of nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@zadigetvoltaire/nuxt-gtm'
  ],
})
  1. Add configuration in nuxtConfig.gtm or in nuxtConfig.runtimeConfig.public.gtm

This module supports 2 ways of configuration:

  • Directly in key gtm of the Nuxt config
  • In public runtimeConfig: useful to override the config with environment variables and handle multiple environments
export default defineNuxtConfig({
  ...
  gtm: {
    id: 'GTM-xxxxxx', // Your GTM single container ID, array of container ids ['GTM-xxxxxx', 'GTM-yyyyyy'] or array of objects [{id: 'GTM-xxxxxx', queryParams: { gtm_auth: 'abc123', gtm_preview: 'env-4', gtm_cookies_win: 'x'}}, {id: 'GTM-yyyyyy', queryParams: {gtm_auth: 'abc234', gtm_preview: 'env-5', gtm_cookies_win: 'x'}}], // Your GTM single container ID or array of container ids ['GTM-xxxxxx', 'GTM-yyyyyy']
    queryParams: {
      // Add URL query string when loading gtm.js with GTM ID (required when using custom environments)
      gtm_auth: 'AB7cDEf3GHIjkl-MnOP8qr',
      gtm_preview: 'env-4',
      gtm_cookies_win: 'x',
    },
    defer: false, // Script can be set to `defer` to speed up page load at the cost of less accurate results (in case visitor leaves before script is loaded, which is unlikely but possible). Defaults to false, so the script is loaded `async` by default
    compatibility: false, // Will add `async` and `defer` to the script tag to not block requests for old browsers that do not support `async`
    nonce: '2726c7f26c', // Will add `nonce` to the script tag
    enabled: true, // defaults to true. Plugin can be disabled by setting this to false for Ex: enabled: !!GDPR_Cookie (optional)
    debug: true, // Whether or not display console logs debugs (optional)
    loadScript: true, // Whether or not to load the GTM Script (Helpful if you are including GTM manually, but need the dataLayer functionality in your components) (optional)
    enableRouterSync: true, // Pass the router instance of your app to automatically sync with router (optional)
    ignoredViews: ['homepage'], // Don't trigger events for specified router names (optional)
    trackOnNextTick: false, // Whether or not call trackView in Vue.nextTick
    devtools: true, // (optional)
  }
  ...
  runtimeConfig: {
    public: {
      gtm: {
        id: 'GTM-xxxxxx',
        queryParams: {
          gtm_auth: 'AB7cDEf3GHIjkl-MnOP8qr',
          gtm_preview: 'env-4',
          gtm_cookies_win: 'x',
        },
        defer: false,
        compatibility: false,
        nonce: '2726c7f26c',
        enabled: true,
        debug: true,
        loadScript: true,
        enableRouterSync: true,
        ignoredViews: ['homepage'],
        trackOnNextTick: false,
        devtools: true,
      }
    }
  }
})

Documentation

Please refer to the @gtm-support/vue-gtm documentation

Composition API - useGtm composable

Example:

<template>
  <button @click="triggerEvent">
    Trigger event!
  </button>
  <button @click="triggerView">
    Trigger event!
  </button>
</template>

<script lang="ts" setup>
  const gtm = useGtm() // auto-imported by the module

  function triggerEvent() {
    gtm.trackEvent({
      event: 'event name',
      category: 'category',
      action: 'click',
      label: 'My custom component trigger',
      value: 5000,
      noninteraction: false,
    })
  }

  function triggerView() {
    gtm.trackView('Home', '/')
  }
</script>

Options API

export default {
  methods: {
    triggerEvent() {
      this.$gtm.trackEvent({
        event: 'event name',
        category: 'category',
        action: 'click',
        label: 'My custom component trigger',
        value: 5000,
        noninteraction: false,
      })
    }
  }
}

Modules options

The modules inherit the options of the plugin @gtm-support/vue-gtm, except vueRouter entry replaced by enableRouterSync.

type ModuleOptions = {
  // SPECIFIC MODULES OPTIONS
  /**
   * Enable Nuxt Devtools integration
   *
   * @default true
   */
  devtools?: boolean
  /**
   * Synchronise GTM with NuxtRouter
   */
  enableRouterSync?: boolean

  // PLUGIN AND MODULE OPTIONS

  /**
   * Derive additional event data after navigation.
   */
  vueRouterAdditionalEventData?: (to: RouteLocationNormalized, from: RouteLocationNormalized) => Record<string, any> | Promise<Record<string, any>>;
  /**
   * Don't trigger events for specified router names.
   */
  ignoredViews?: string[] | ((to: RouteLocationNormalized, from: RouteLocationNormalized) => boolean);
  /**
   * Whether or not call `trackView` in `Vue.nextTick`.
   */
  trackOnNextTick?: boolean;
  /**
   * Your GTM single container ID, array of container ids or array of objects.
   *
   * @example
   *     'GTM-xxxxxx'
   *     // or
   *     ['GTM-xxxxxx', 'GTM-yyyyyy']
   *     // or
   *     [{
   *       id: 'GTM-xxxxxx',
   *       queryParams: {
   *         gtm_auth: 'abc123',
   *         gtm_preview: 'env-4',
   *         gtm_cookies_win: 'x'
   *       }
   *     }, {
   *       id: 'GTM-yyyyyy',
   *       queryParams: {
   *         gtm_auth: 'abc234',
   *         gtm_preview: 'env-5',
   *         gtm_cookies_win: 'x'
   *       }
   *     }]
   */
  id: string | string[] | GtmIdContainer[];
  /**
   * Add url query string when load gtm.js with GTM ID.
   */
  queryParams?: GtmQueryParams;
  /**
   * Script can be set to `defer` to speed up page load at the cost of less accurate results (in case visitor leaves before script is loaded, which is unlikely but possible).
   *
   * Defaults to false, so the script is loaded `async` by default.
   *
   * @default false
   */
  defer?: boolean;
  /**
   * Will add `async` and `defer` to the script tag to not block requests for old browsers that do not support `async`.
   *
   * @default false
   */
  compatibility?: boolean;
  /**
   * Will add `nonce` to the script tag.
   *
   * @see [Using Google Tag Manager with a Content Security Policy](https://developers.google.com/tag-manager/web/csp)
   */
  nonce?: string;
  /**
   * The URL of the script; useful for server-side GTM.
   *
   * @default https://www.googletagmanager.com/gtm.js
   */
  source?: string;
  /**
   * Plugin can be disabled by setting this to `false`.
   *
   * @example enabled: !!GDPR_Cookie
   * @default true
   */
  enabled?: boolean;
  /**
   * Whether or not to display console logs debugs.
   */
  debug?: boolean;
  /**
   * Whether or not to load the GTM Script.
   *
   * Helpful if you are including GTM manually, but need the dataLayer functionality in your components.
   */
  loadScript?: boolean;
  /**
   * The property of Track view event.
   *
   * @example trackViewEventProperty: 'track-view-event-demo'
   * @default content-view
   */
  trackViewEventProperty?: string;
}

That's it! You can now use Nuxt GTM in your Nuxt app ✨

Contributing

# Install dependencies, prepare apps & run dev server
make start

# Run dev server
pnpm dev

# Develop with playground, with bundled client ui
pnpm play:prod

# Run ESLint
pnpm lint

# Run Vitest
pnpm test
pnpm test:watch

Release new version

  1. Execute release command

⚠ This command should be executed only on the main branch

This command will:

  • Generate the CHANGELOG.md and push it with a release commit
  • Bump the package version
  • Create and push the new tag
  • Create a github release to trigger the library publish pipeline
pnpm release

© Zadig&Voltaire is a registered trademark of ZV FRANCE

nuxt-gtm's People

Contributors

louismazel avatar michael-bouvy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

nuxt-gtm's Issues

This plugin doesn't work for AW-* tags

It creates an error [nuxt] error caught during app initialization Error: 'AW-*' is not a valid GTM-ID (/^GTM-[0-9A-Z]+$/). Did you mean 'GTM-*'?, which is issue one.

However, it also creates very unintuitive error when using Vuetify for a project, namely nuxt.js?v=49ff4004:96 [nuxt] error caught during app initialization Error: [Vuetify] Could not find defaults instance. Lots of functionalities don't work with that setup.

Repo to reproduce: https://github.com/Doyban/Doyban-Website/tree/cab0e05bd28d2e11241b88a72087c001dc2ba188

I tried Node 16/18/20, Vuetify with/out SSR, and the same issue.

Any idea on how to create consent for cookies?

I'm wondering about a scenario where anonymous users can have GTM enabled by default. When a user logs in, if they've opted out of cookies (from a BE endpoint), the plugin is disabled and the cookies are removed.

By manually updating GTM to not be enabled, the debugger successfully does not send data. However, there's still cookies being saved to the user's browser regardless of whether it's enabled. Even manually deleting the cookies continues to create them.

Is there a better solution for this issue? Is it purely from setting up a policy on Google's end? Is there a way to essentially remove the script from the application?

How to configure the module using enviroment variables

Hey there!

Thank you for your work on this module! 👏

I have been trying to configure the module with environment variables by setting the id using NUXT_PUBLIC_GTM_ID, but it does not work - do you have an example of how to configure the module through environment variables?

If it is not possible to do at this moment, would it be something you are interested in supporting in a future release?

Compatibility with Nuxt 4

Hi nuxt-gtm team,

Recently Nuxt has started the upgrade towards v4. It is possible to opt-in to this version early using the nightly build ("nuxt": "npm:nuxt-nightly@latest") and adding future: { compatibilityVersion: 4 } to the Nuxt config.

With this version installed, I get an error when installing nuxt-gtm using npm i -D @zadigetvoltaire/nuxt-gtm, see below. If I read it correctly, let me know if I don't, the @zadigetvoltaire/nuxt-gtm module seems incompatible with [email protected].

npm error code ERESOLVE
npm error ERESOLVE could not resolve
npm error
npm error While resolving: <redacted>@undefined
npm error Found: [email protected]
npm error node_modules/nuxt
npm error   nuxt@"npm:nuxt-nightly@latest" from the root project
npm error
npm error Could not resolve dependency:
npm error dev @zadigetvoltaire/nuxt-gtm@"*" from the root project
npm error
npm error Conflicting peer dependency: [email protected]
npm error node_modules/nuxt
npm error   peer nuxt@"^3.0.0" from @zadigetvoltaire/[email protected]
npm error   node_modules/@zadigetvoltaire/nuxt-gtm
npm error     dev @zadigetvoltaire/nuxt-gtm@"*" from the root project
npm error
npm error Fix the upstream dependency conflict, or retry
npm error this command with --force or --legacy-peer-deps
npm error to accept an incorrect (and potentially broken) dependency resolution.
npm error
npm error
npm error For a full report see:
npm error /Users/<redacted>/.npm/_logs/2024-07-22T09_58_16_098Z-eresolve-report.txt

npm error A complete log of this run can be found in: /Users/<redacted>/.npm/_logs/2024-07-22T09_58_16_098Z-debug-0.log

Support for Google Analytics 4 ID in format G-ID

I would like to integrate my app with Google Analytics 4 which now uses a new ID format starting with G-

Unfortunately, when attempting to integrate it, my app encounters a 500 error with the message: G-X is not a valid GTM-ID (/^GTM-[0-9A-Z]+$/).

After investigating, I discovered that the issue lies with the @gtm-support/vue-gtm library, which is responsible among other things for ID validation.

But the author of this library is not willing to adjust a small regexp. Will you be able to fork this repository and base nuxt-gtm on it?

Here are the issues with wontfix labels 🙃
gtm-support/vue-gtm#286
gtm-support/vue-gtm#338
gtm-support/vue-gtm#356

enabled option does not work

The "enabled" option seems not to work.

nuxt.config.ts

  modules: [
   "@zadigetvoltaire/nuxt-gtm"
  ],
  gtm: {
    id: my-id,
    enabled: false
  },

Even with the above settings, tags are still being delivered from Google Tag Manager.
Something wrong?

@zadigetvoltaire/nuxt-gtm0.0.13
node 18.18.2
npm 9.8.1
vue 3.3.8
nuxt 3.8.2

500 error - is not a valid GTM-ID

Only a specially-named environment variable can override a runtime config property. That is, an uppercase environment variable starting with NUXT_ which uses _ to separate keys and case changes.

First, you have to add a check to make sure that the secondary value exists at all.

const moduleOptions: ModuleOptions = defu(nuxt.options.runtimeConfig.public.gtm, options)

If you make a mistake in naming the ENV variable due to carelessness, the entire application will crash in production, but will work in any version locally.

This happens because there is a .env file locally. In production, .env is not recommended and you need to use environment variables.

Since your primary source of the value is the runtime config variables, the module settings are erased with an empty value from the runtime config. This is an error, since the environment variable should in principle be optional, and if it is present, the value of the module settings is replaced. And if there is no environment variable, the setting from the module configuration should be taken.


Nuxt has a very confusing system of ENV variables. When a variable is defined in the runtime config like this

  runtimeConfig: {
    public: {
      gtm: {
        id: process.env.GOOGLE_TAG_MANAGER_ID

Then the environment variable should be

NUXT_PUBLIC_GTM_ID=GTM-QWERTY0

A typo in the naming of an environment variable should not crash the production. Your module in its current form is dangerous :)

Enabling the plugin while application is working has no effect

Hello!

I implemented your plugin and I start the application with the plugin turned off by default. User needs to consent to cookies to enable the plugin. When I set the:
config.public.gtm.enabled = true;
nothing happens. The setup works if that value is true from the beginning. Any suggestion about what am I doing wrong?

My runtimeConfig:

runtimeConfig: {
    public: {
      ga_cookie: process.env.GA_COOKIE_NAME,
      gtm: {
        id: process.env.GTM_TAG,
        defer: false,
        compatibility: false,
        nonce: '2726c7f26c',
        enabled: false,
        debug: true,
        loadScript: true,
        enableRouterSync: true,
        trackOnNextTick: false,
        devtools: true,
      }
    }
  }, 

Feature request: Configurable property name for `dataLayer`

I'd like to be able to substitute the key dataLayer in the configuration to another label, for example dataLayer1.

The use case is managing multiple gtm instances on a site.

This property name "dataLayer" is currently not configurable.

How to change GTM ID dynamically?

I need to use different GTM IDs acording to my routes.
Is the only possible configuration via defineNuxtConfig or could i configure it using a composable, for example?

Page View only sent on initial load / full refresh

Hi, I have an interesting situation here.

I have configured this module with

{
gtm: {
    id: 'my-id',
    defer: false,
    compatibility: false,
    loadScript: true,
    debug: true,
    enabled: true,
    enableRouterSync: true, // I want it to sync
    trackOnNextTick: true,
  },
}

Now, whenever I hit a hard refresh, I can see in the console that the page view was tracked:

Snímka obrazovky 2024-01-12 o 12 01 41

...and in Network, I can also see the follow-up "beacon" POST request:

epik

Problem

When I start navigating on the client-side (clicking a <NuxtLink>), I can see the console outputting the track views:

Snímka obrazovky 2024-01-12 o 12 04 39

However, there is no follow-up beacon and the data never arrives to Google.

Has anyone experienced this / can anyone confirm?

Is there a workaround?

Thank you.

useGtm() is randomly undefined

The GTM snippet is always loaded and the TrackView Event via router sync is always fired.

But I have the problem, that useGtm() inside vue components is randomly undefined.

If I stop and start the development server (npm run dev) several times or clear the cache (npx nuxi cleanup), it eventually works again.
When I then restart the development server again later, it doesn't work again.

What could be the problem.

The `useGtm` composable returns `undefined` on server

The original useGtm directive is returning essentially an instance of GtmSupport, which is built to handle server-side calls.

However, it will only return an object if it's been instantiated, and that only happens in the install method.

Because for your nuxt approach, you chose to only install the plugin on the client, this is breaking the server-side use of useGtm.

While i know that there is no actual utility of useGtm on the server-side, it would still be great if we didn't have to ensure all calls of gtm.* are done on the client side.

Can I manually init GTM?

Can I manually init GTM? For example, init GTM if the user has allowed this in the cookie settings

Feature request/question: `trackEvent` predefined properties

@LouisMazel @michael-bouvy
Currently when I try to use gtm.trackEvent it has some prefined props (event, value etc) already set.

Is there a way to omit all the predefined props and just use the custom ones? (I want to have object that ends up in the datalayer completely purified from those predefined values)

If no, is there a possibility to add this as a feature?

Enabling plugin breaks nuxt (componentName property of undefined)

When I enable the plugin in the nuxt.config.ts modules I get the following error message:

500
Cannot read properties of undefined (reading 'componentName')

at defineNuxtLink (./node_modules/nuxt/dist/app/components/nuxt-link.js:23:33)
at ./node_modules/nuxt/dist/app/components/nuxt-link.js:264:64
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async ViteNodeRunner.directRequest (/home/laz/node_modules/vite-node/dist/client.mjs:341:5)
at async ViteNodeRunner.cachedRequest (/home/laz/node_modules/vite-node/dist/client.mjs:197:14)
at async ViteNodeRunner.dependencyRequest (/home/laz/node_modules/vite-node/dist/client.mjs:231:12)
at async ./node_modules/nuxt/dist/app/components/index.js:1:31
at async ViteNodeRunner.directRequest (/home/laz/node_modules/vite-node/dist/client.mjs:341:5)
at async ViteNodeRunner.cachedRequest (/home/laz/node_modules/vite-node/dist/client.mjs:197:14)
at async ViteNodeRunner.dependencyRequest (/home/laz/node_modules/vite-node/dist/client.mjs:231:12)

My relevant package.json lines:

    "@zadigetvoltaire/nuxt-gtm": "^0.0.13",
    "nuxt": "^3.8.0",

Nuxt config:

 modules: [
    "@zadigetvoltaire/nuxt-gtm",
    .....
],
.... ,
runtimeConfig: {
   public : {
      gtm: {
        id: process.env.GTM_ID || "",
        enabled: process.env.GTM_ENABLED === "true" || false,
        devtools: process.env.NODE_ENV === "development",
        enableRouterSync: true,
        defer: true,
        compatibility: true,
        source:
          process.env.GTM_SOURCE || "https://www.googletagmanager.com/gtm.js"
      }
  }
}

Load script tag within <head> tag

Is there an ability to load the script tag:

<script async="" src="https://www.googletagmanager.com/gtag/js?id=GTM-XXXXXX&amp;l=dataLayer"></script>

within the head tag instead of within the body tag?

Feat: SSR support

Currently when using the useGtm, it's only supported and initialized on the client side.
It would be nice to find a way on handling the events that are triggered on the SSR.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.