nuxt-matomo icon indicating copy to clipboard operation
nuxt-matomo copied to clipboard

How to enable the media tracking

Open michael-hillmann opened this issue 4 years ago • 3 comments

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?

michael-hillmann avatar Jan 25 '21 14:01 michael-hillmann

@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.

pimlie avatar Jan 31 '21 12:01 pimlie

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 avatar Feb 04 '21 16:02 michael-hillmann

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>

michael-hillmann avatar Feb 04 '21 16:02 michael-hillmann