Closed jssouders closed 4 years ago
I know they have a nuxt plugin for gtag, but it's not a wrapper of vue-gtag, it's a standalone package called @nuxtjs/google-gtag
I'm not sure if I'm going to make a nuxt package wrapper of vue-gtag I'll let u know
thanks for the feedback
I have a simple solution for this. I load the script through a plugin with the following code
In plugins/vue-gtag.client.js
import Vue from 'vue'
import VueGtag from 'vue-gtag'
/**
* @type {import('@nuxt/types').Plugin}
*/
const vueGtag = ({ app, env }) => {
Vue.use(
VueGtag,
{
config: { id: env.gaId },
disabled: true, // Here you could ignore user privacy and set to true
},
app.router
)
}
export default vueGtag
And in plugins/vue-gtag.server.js
/**
* @type {import('@nuxt/types').Plugin}
*/
const vueGtag = ({ app, env }) => {
const preloadLinks = [
{
rel: 'preload',
as: 'script',
href: `https://www.googletagmanager.com/gtag/js?id=${env.gaId}`,
},
{
rel: 'preconnect',
href: 'https://www.google-analytics.com/',
},
]
if (process.env.NODE_ENV === 'production') {
if (typeof app.head === 'function') {
console.error("We can't add the preload links if head is a function")
} else if (app.head) {
app.head.link = [...(app.head.link || []), ...preloadLinks]
} else {
app.head = {
link: preloadLinks,
}
}
}
}
export default vueGtag
On nuxt.config.js
export default {
env: {
/** Configuración de google-analytics */
gaId: 'UA-XXXXX-X',
},
plugins: [
// ... other plugins
'~/plugins/vue-gtag.client.js',
'~/plugins/vue-gtag.server.js',
]
}
And here is a component for controlling the activation of said plugin. This part is optional and depends on your moral and legal concerns.
<template>
<transition name="fade">
<article
v-if="showComponent"
class="alert-cookie bg-gray-800 shadow max-w-xs text-white p-3 rounded"
role="alert"
>
<h1 class="h6">
Uso de cookies
</h1>
<p class="mb-2 text-small leading-point">
Este sitio web utiliza cookies para que tengas la mejor experiencia de
usuario. Si continúas navegando nos das tu consentimiento y aceptas
nuestra
<n-link class="underline text-blue-200" no-prefetch to="/cookies">
Política de cookies
</n-link>
</p>
<p>
<button class="btn" @click="setCookie(true)">
Ok gracias
</button>
</p>
</article>
</transition>
</template>
<script>
export const cookieName = 'DinamoGalleta'
export const cookieMaxAge = 60 * 60 * 24 * 365
export const hasCookie = (name = '') => {
const cookies = document.cookie.split(';')
const [dinamoCookie = ''] = cookies.filter(item => item.includes(`${name}=`))
return {
cookie: dinamoCookie,
isEnabled: dinamoCookie.indexOf('active') !== -1,
isDisabled: dinamoCookie.indexOf('nope') !== -1,
}
}
export const setCookie = (active = false) => {
const cookieValue = active ? 'active' : 'nope'
document.cookie = `${cookieName}=${cookieValue};path=/;max-age=${cookieMaxAge};SameSite=Strict`
return cookieValue
}
export default {
// TODO: En vue3 vamos a reemplazar esto por composition API
data() {
return {
showComponent: false,
cookie: {
cookie: '',
isEnabled: false,
isDisabled: false,
},
}
},
mounted() {
this.getCookieFromCtx()
if (!this.cookie.cookie) {
this.$root.$once('routeChanged', () => this.setCookie(true))
this.enableTracking()
} else if (this.cookie.isEnabled) {
this.enableTracking()
}
},
methods: {
getCookieFromCtx() {
this.cookie = hasCookie(cookieName)
},
setCookie(active = false) {
const cookieValue = setCookie(active)
this.getCookieFromCtx()
this.showComponent = false
if (this.cookie.isEnabled) {
this.enableTracking()
} else {
this.disableTracking()
}
this.$emit('cookieSet', cookieValue)
},
enableTracking() {
try {
// NOTE: Si quieres más trackers, aquí van.
this.$gtag.optIn()
this.$fbpixel.enable()
// eslint-disable-next-line no-empty
} catch (e) {}
},
disableTracking() {
try {
// NOTE: Si quieres más trackers, aquí van.
this.$gtag.optOut()
this.$fbpixel.disable()
// eslint-disable-next-line no-empty
} catch (e) {}
},
},
}
</script>
And a page for disabling cookies.vue
<template>
<main class="page--cookies section">
<div class="container cookies">
<h1 class="h1">Política de cookies</h1>
<p>
Las cookies de este sitio web se utilizan para ofrecer contenido y
anuncios personalizados, además de brindar funciones de redes sociales y
analizar el tráfico. Es importante que sepas que compartimos información
sobre el uso que hagas del sitio web con nuestros partners de redes
sociales, publicidad y análisis web, quienes pueden combinar esta
información con otra que les hayas proporcionado o que hayan recopilado
a partir del uso que haya hecho de sus servicios. Aceptas nuestras
cookies si continúas navegando nuestro sitio web.
</p>
<ul class="flex flex-col lg:flex-row justify-between mt-8 mb-6">
<li
v-for="(definition, i) in cookieDefinition"
:key="i"
class="cookies__list-col"
>
<h2 class="h3 title">{{ definition.label }}</h2>
<div class="content">
<p v-for="(d, o) in definition.desc" :key="o" v-text="d"></p>
</div>
</li>
</ul>
<div class="flex flex-col justify-center items-center">
<p>¿Aceptas las cookies de terceros?</p>
<input
id="accept-cookie"
v-model="cookie.isEnabled"
:value="true"
type="radio"
name="accept-cookie"
class="hidden"
/>
<input
id="deny-cookie"
v-model="cookie.isDisabled"
:value="true"
type="radio"
name="accept-cookie"
class="hidden"
/>
<div
class="switch"
:class="{
'switch--yes': cookie.isEnabled,
'switch--no': cookie.isDisabled,
}"
>
<label class="switch__label switch__label--yes" for="accept-cookie"
>Si</label
>
<span class="switch__icon"></span>
<label class="switch__label switch__label--no" for="deny-cookie"
>No</label
>
</div>
</div>
</div>
</main>
</template>
<script>
import { data as cookieDefinition } from '~/assets/data/cookie-definitions.json'
import { hasCookie, cookieName, setCookie } from '~/components/AlertCookie.vue'
export default {
// TODO: En vue3 vamos a reemplazar esto por composition API
name: 'PageCookies',
data() {
return {
cookieDefinition,
cookie: {
cookie: '',
isEnabled: false,
isDisabled: false,
},
}
},
watch: {
'cookie.isDisabled': function cookieIsDisabled(newValue) {
this.cookie.isEnabled = !newValue
if (newValue) {
this.denyCookie()
}
},
'cookie.isEnabled': function cookieIsEnabled(newValue) {
this.cookie.isDisabled = !newValue
if (newValue) {
this.acceptCookie()
}
},
},
mounted() {
this.getCookieFromCtx()
},
methods: {
getCookieFromCtx() {
this.cookie = hasCookie(cookieName)
},
acceptCookie() {
this.setCookie(true)
},
denyCookie() {
this.setCookie(false)
},
setCookie(active = false) {
const cookieValue = setCookie(active)
this.getCookieFromCtx()
if (this.cookie.isEnabled) {
this.enableTracking()
} else {
this.disableTracking()
}
this.$emit('cookieSet', cookieValue)
},
enableTracking() {
try {
// NOTE: Si quieres más trackers, aquí van.
this.$gtag.optIn()
this.$fbpixel.enable()
// eslint-disable-next-line no-empty
} catch (e) {}
},
disableTracking() {
try {
// NOTE: Si quieres más trackers, aquí van.
this.$gtag.optOut()
this.$fbpixel.disable()
// eslint-disable-next-line no-empty
} catch (e) {}
},
},
}
</script>
<style lang="scss" scoped>
$radious: 25px;
.switch {
position: relative;
display: grid;
max-width: theme('maxWidth.sm');
line-height: theme('lineHeight.small');
text-align: center;
border-radius: $radious;
transition: 0.3s ease;
transition-property: color, background-color;
align-items: stretch;
grid-template-columns: 1fr 40px 1fr;
&__icon {
display: block;
width: 20px;
height: 4px;
margin: 4px 4px 4px 12px;
background: #fff;
border-radius: 2px;
transition: 0.2s ease;
transform: rotate(-45deg);
align-self: center;
&::after {
position: absolute;
display: block;
width: 4px;
height: 12px;
margin-top: -8px;
content: '';
background: #fff;
border-radius: 2px;
transition: 0.2s ease;
transition-property: margin, height, width, background-color;
}
}
&__label {
display: flex;
padding: theme('spacings.1');
align-items: center;
font-weight: normal;
color: rgba(0, 0, 0, 0.2);
cursor: pointer;
background-color: transparent;
transition: color 0.2s ease, background-color 0.6s ease-out;
&:hover,
&:focus {
background-color: rgba($black, $alpha: 0.1);
}
}
&__label--yes {
padding-left: theme('spacings.2');
text-align: left;
border-top-left-radius: $radious;
border-bottom-left-radius: $radious;
}
&__label--no {
padding-right: theme('spacings.2');
text-align: right;
border-top-right-radius: $radious;
border-bottom-right-radius: $radious;
}
&--no {
background-color: #ff3b30;
}
&--no & {
&__label--no {
font-weight: bold;
}
&__icon {
background-color: #fff;
&::after {
height: 20px;
margin-top: -8px;
margin-left: 8px;
background-color: #fff;
}
}
&__label--yes,
&__label--no {
color: #fff;
}
}
&--yes {
font-weight: bold;
background: $green-500;
}
&--yes & {
&__label--yes {
font-weight: bold;
}
&__label--yes,
&__label--no {
color: #fff;
}
}
}
</style>
@cesasol on vue-gtag.server.js you might want to push those objects into the app.head.link array. Otherwise you will overwrite all other head settings.
@AlejandroMut Thank you so much for stating this. I had this problem and i had to replace the heads again from each page dynamically to solve it. Now i know why the heads were missing in production in the first place.
I tried the code from @cesasol and it works (after a small change to push data to the app.head instead of overwriting it all) however i have one issue i couldn't figure out.
Everything seems to work fine however query parameters in the URL aren't displayed in Analytics, so i see this one appearing in "live metrics" https://domain.xx/gaming-entertainment
but i don't see https://domain.xx/gaming-entertainment?page=2
.
So it looks like the vue-gtag.client.js
isn't working like it should, any suggestions on how to fix that @cesasol because i think vue-gtag is a wiser thing to use then the current community analytics module for nuxtjs that is based on the older vue-analytics code.
@Vout Sorry for the late response. But your issue comes from the fact that vue-gtag uses vue-router to detect route changes but if you change the query string without using vue-router (like assigning a location) then vue-gtag has no way of detecting the route change
Using @cesasol solution, it starts tracking even though I don't run opt in (sets the ga-cookies right away) on the first load before opt out has explicitly been set.. Any ideas? I thought using enabled: false would prevent that? Perhaps because it's loading the SSR plugin?
I am starting a new NUXT application and have a requirement to add google analytics. There is currently an analytics-module package in the nuxt-community that utilizes your vue-analytics package, but I have not been able to find one for your new vue-tag package. Do you know if one exists?