pimlie / nuxt-matomo

Matomo analytics for Nuxt.js
Other
88 stars 15 forks source link

How to enable the media tracking #20

Open michael-hillmann opened 3 years ago

michael-hillmann commented 3 years ago

Hi, I'm building a video component in NUXT, which runs fine so far. When I want to enable tracking for the video media usage of the media extension of Matomo (I use the cloud installation), we need to call the function "MediaAnalytics::scanForMedia" as described in the Matomo SDK

Here is my component:

<template>
  <div v-if="video.title">
    <video
      id="player"
      :title="video.title"
      :data-matomo-title="video.title"
      class="cld-video-player cld-video-player-skin-dark"
    >
    </video>
  </div>
</template>

<script>
export default {
  probs: {
    video: {
      type: Object,
      required: true
    }
  },
  mounted() {
    if (this.video.title) {
      const cld = cloudinary.Cloudinary.new({
        cloud_name: '<my-cloudinary-space>',
        secure: true
      })
      const player = cld.videoPlayer('player', {
          "fluid": true,
          "controls": true,
          "hideContextMenu": true,
          "posterOptions": {
              "transformation": {
                  "startOffset": this.video.poster_seconds
              }
          }
      })
      const public_id = this.video.video_id.filename
      const start = public_id.indexOf('/videos/') + 1
      const end = public_id.indexOf('.mp4')
      player.source(public_id.substring(start, end), {
          "info": {
              "title": this.video.title,
              "subtitle": this.video.subtitle
          }
      })
      if (this.$matomo) {
        this.$matomo['MediaAnalytics::scanForMedia']()
      }
    }
  }
}
</script>

When enable debug information for [nuxt-matomo], I got the information:

[nuxt-matomo] Delaying call to tracker: MediaAnalytics::scanForMedia

But never the delayed calling as I would expect:

[nuxt-matomo] Calling tracker MediaAnalytics::scanForMedia with args []

Any ideas, what I'm doing wrong?

pimlie commented 3 years ago

@michael-hillmann window.$matomo is a ref to the matomo tracker object (not window._paq), afaik there doesnt exist a MediaAnalytics::scanForMedia method so when matomo is loaded it wont execute that fn because it doesnt exists.

Looking at the Matomo docs Im not entirely sure which method on the tracker you should use though cause I cant find any docs for the media plugin.

michael-hillmann commented 3 years ago

According to this documentation, I got it managed to result in a working application. Unfortunately, I need to remove the Javascript Proxy from the plugin and put the plugin.js directly in my project. So: far from optimal, but working for now. ;-)

matomo.zip

To get this working, I add the official javascript snippet from matomo.com into my nuxt.config.js like:

import config from './app.config.js'

export default {
  target: 'static',
  head: {
    __dangerouslyDisableSanitizers: ['script'],
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' }
    ],
    script: [
      // asynchronous tracking
      config.MATOMO_SITE_ID ? {
        innerHTML:
          `var _paq = window._paq = window._paq || []; `+
          `_paq.push(["trackPageView"]); ` +
          `_paq.push(["enableLinkTracking"]); ` +
          `(function() { var u="${config.MATOMO_URL}"; ` +
          `_paq.push(["setTrackerUrl", u+"matomo.php"]); ` +
          `_paq.push(["setSiteId", "${config.MATOMO_SITE_ID}"]); ` +
          `var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; ` +
          `g.type="text/javascript"; g.async=true; g.src="${config.MATOMO_SRC}"; ` +
          `s.parentNode.insertBefore(g,s); })();`,
        type: 'text/javascript',
        charset: 'utf-8'} : {}
      ]
  },
  // ... snipping irrelevant stuff ...
  plugins: [
    { src: '~plugins/matomo.js', mode: 'client' }
  ],
  // ... snipping irrelevant stuff ...
}

and a configuration file app.config.js:

// development settings
const development = {
  MATOMO_SITE_ID: [your matomo site-id for testing]
}

// production settings
const production = {
  MATOMO_SITE_ID: [your matomo site-id for production]
}

const config = process.env.NODE_ENV=='development' ? development : production

// common settings
export default {
  // analytics url
  MATOMO_SRC: '//cdn.matomo.cloud/[matomo-account].matomo.cloud/matomo.js',
  MATOMO_URL: 'https://[matomo-account].matomo.cloud/',

  // add stage specific settings
  ...config
}
michael-hillmann commented 3 years ago

In case someone is interested: my video component is now working fine. I'm using Cloudinary for video hosting and video.js as a video player because this player is supported by Matomo out of the box.

Comments for improvements are welcome!

<template>
  <v-container>
    <v-card>
      <v-card-text class="pa-1">
        <video
          ref="videoPlayer"
          preload="none"
          :title="paragraph.video_title"
          :data-matomo-title="paragraph.video_title"
          aspect-ratio="1"
          class="video-js vjs-fill player-dimensions"
        >
        </video>
      </v-card-text>
    </v-card>
    <div v-if="paragraph.caption != ''">
      <div class="caption font-italic text-center">
        {{ paragraph.caption }}
      </div>
    </div>    
  </v-container>
</template>

<script>
import videojs from 'video.js'

export default {
  name: 'Video',
  props: {
    paragraph: {
      type: Object,
      required: true
    }
  },
  data() {
    return {
      player: null
    }
  },
  methods: {
    getVideo(type) {
      const url = this.paragraph.video_id.filename.replace('.mp4', '.' + type)
      const video = {
        src: url,
        type: "video/" + type
      }
      return video
    },
    getPoster(type) {
      const url = this.paragraph.video_id.filename
        .replace('/upload/','/upload/so_0,h_300,w_500,f_auto,c_limit/')
        .replace('.mp4', '.' + type)
      return url
    }
  },
  mounted() {
    const context = this
    this.player = videojs(this.$refs.videoPlayer, {
      aspectRatio: '9:16',
      responsive: true,
      autoplay: false,
      controls: true,
      sources: [
        this.getVideo('mp4'),
        this.getVideo('webm'),
        this.getVideo('ogg')
      ],
      poster: this.getPoster('jpg') 
    },
    function onPlayerReady() {
      if (window && window._paq) {
      }
    })
  },
  beforeDestroy() {
    if (this.player) {
      this.player.dispose()
    }
  }
}
</script>

<style>
.vjs-poster {
  background-size: cover;
  background-color: #fff;
}
.player-dimensions {
  width: 1920px;
  height: 1080px;
}
.player-dimensions.vjs-fluid {
  padding-top: 56.25%;
}
</style>