One, foreword

Data burying point is TO monitor user behavior in the application, which is becoming more and more important for product iteration of TO C.

The data burying point is the source of product requirement analysis to verify whether the function meets expectations. The front end is closer to the user, I say data buried in the system development scheme.

2. Data burying point scheme analysis

Different products pay attention to data from different perspectives, and collect and design different schemes according to requirements. For example, tiktok, a product of information flow, has a higher stay time of following users. For example, the commodity category pays attention to the “re-purchase rate”, statistics of new and old users.

Buried data statistics are usually divided into:

(1) Page view statistics

(2) Statistics of function clicks

We are only going to talk about page view statistics today. You can define your own page view statistics in your development system.

Usually we access third-party services, such as Baidu Statistics, there are related page visit statistics, as well as user portraits and so on. But as a developer, if in their own system, according to their own needs customized data buried point is not very cool.

1. Page view statistics

Page views are usually divided into: PV and UV.

(1) PV: page access times.

(2) UV: number of page visitors.

Page views are not determined by content appeal alone, but by entry, location, depth to the home page, and so on. The entrance is mainly designed by the UI visual staff. The location of the entrance can be adjusted after data analysis, and the depth of the home page can be adjusted based on the user’s access path.

The collection page is loaded from and to to obtain the user access path:

Analytics can know the general depth of user visits, and the attrition rate of each layer and each page can be seen intuitively, thus adjusting the source and depth of the core page entry.

There are also some special cases: for example, PV stable page views suddenly plunge, may be a load failure or error.

3. Actual operation of data burying point scheme

Next, I accessed the data burial point through my own system: chat.chengxinsong-cn

Technical architecture: Vue +vuex+ KOA2 +mysql+websocketIO+ Redis, etc.

1. Scheme 1: define Router globally. BeforeEach method

Globally defined in main.js

/* Global PV statistics */ router. BeforeEach ((to, from, next) => {let flag = localStorage.getItem("HappyChatUserInfo") !== null ? true: false;
  let data = {
    type: 'visit',
    user_id: flag ? JSON.parse(localStorage.getItem("HappyChatUserInfo")).user_id: 'Cannot get userId',
    time: (new Date()).getTime(),
    params: {
      from: {
        name: from.name || ' ',
        path: from.path || ' ',
        query: from.query || ' '
      },
      to: {
        name: to.name || ' ',
        path: to.path || ' ',
        query: to.query || ' '
      }
    }
  }
  App.methods.logEvent(data);
  next()
})
Copy the code

The stay time can be determined by from and to page time (jump page time – current page time). How to count when closing an application? Consider the window.onunload method

window.onunload = function unloadPage() {
  let data = {
    type: 'close',
    user_id: localStorage.getItem("HappyChatUserInfo") !== null ? JSON.parse(localStorage.getItem("HappyChatUserInfo")).user_id: 'Cannot get userId',
    time: (new Date()).getTime(),
    params: {
      from: {
        name: 'Before closing',
        path: router.currentRoute.path || ' ',
        query: router.currentRoute.params || ' '
      },
      to: {
        name: 'off',
        path: ' ',
        query: ' '
      }
    }
  }
  App.methods.logEvent(data);
}
Copy the code

In this case, we need to define the interface parameter, and the interface method is logEvent.

We customize the Method of Vue plug-in App to send buried data to the server.

We defined it in app.vue

The specific methods

/* Data buried point */logEvent(opts) {
        let data = {
          type: opts.type,
          user_id: opts.user_id,
          time: opts.time,
          params: opts.params || {}
        }
        return Api.pvLog(data).then(res => {
          console.log(res)
        }).catch(function (error) {
          console.log(error);
        });
      }
Copy the code

Where Api is axiOS interface unified encapsulation method.

How to save data in the back end and what parameters to save are defined according to requirements, such as common client IP, data type type, user ID, access time, page name in from, path path, tea tree query and so on.

The control layer of the back-end interface. (Whether the interface needs to be authenticated or not is designed according to the requirements.)

let pvLog = async (ctx, next) => {
    const data = ctx.request.body;
    let req = ctx.req;
    let clientIP = req.headers['x-forwarded-for'] ||
        req.connection.remoteAddress ||
        req.socket.remoteAddress ||
        req.connection.socket.remoteAddress;
    userModel.logPV([clientIP, data.type, data.user_id, data.time,
        data.params.from.name || ' ', data.params.from.path || ' ', JSON.stringify(data.params.from.query) || ' ',
        data.params.to.name || ' ', data.params.to.path || ' ', JSON.stringify(data.params.to.query) || ' ']);
    ctx.body = {
        success: true}};Copy the code

Next is the data into the library operation, the code will not put, source address:

1. Back-end code: github.com/saucxs/happ…

2. Front-end code: github.com/saucxs/happ…

Welcome fork and start.

2. Scheme 2: Global registration mixed with beforeRouteEnter and beforeRouteLeave

Although officials say to be careful with global blending objects.

Take a look at the sample code

import Vue from 'vue'

Vue.mixin({
    beforeRouteEnter (to, from, next) {
        next(vm => {
            vm.$app.logEvent({
                type: 'visit',
                name: to.name,
                time: new Date().valueOf(),
                params: {
                    from: {
                        name: from.name,
                        path: from.path,
                        query: from.query
                    },
                    to: {
                        name: to.name,
                        path: to.path,
                        query: to.query
                    }
                }
            })
        })
    },
    beforeRouteLeave (to, from, next) {
        this.$app.logEvent({
            type: 'visit',
            name: to.name,
            time: new Date().valueOf(),
            params: {
                from: {
                    name: from.name,
                    path: from.path,
                    query: from.query
                },
                to: {
                    name: to.name,
                    path: to.path,
                    query: to.query
                }
            }
        })
        next()
    }
})
Copy the code

We need to consider whether the beforeRouteLeave method should be triggered when the application is closed.

Two more questions:

(1) Each page has hook function beforeRouteEnter, beforeRouteLeave method, how to merge.

(2) Sometimes when the child routing problem is involved, the child routing page will call beforeRouteEnter and beforeRouteLeave methods twice, and PV will double.

Therefore, plan 2 is only for reference and should be used with caution.

Among them, this.App.logEvent) is equivalent to app.logEvent of scheme 1.

Iv. Summary of global PV statistical scheme

Use different solutions based on actual needs and assessments:

(1) SPA application, single entry, global definition of Router in entry file. BeforeEach can be, is scheme 1.

(2) MPA application, multi-entry, can encapsulate common logic, avoid the cost of repeated construction entry.

(3) SPA+MPA mixed application: MPA scheme is ok.

(4) SSR application: The pursuit of SEO adopts server-side rendering (SSR). Different templates are used to render pages. PV related data can be known by directly counting the number of calls to templates.

As for UV, PV data collection userId can be repeated. If no user management system is applied, COLLECTING IP and deviceId can also roughly know UV (inaccurate).

Author’s brief introduction

Nickname: saucxs | songEagle | treasure to write code

Making:github.com/saucxs

First, technical products

  • 1. Sau Exchange Learning Community (www.mwcxs.top/);
  • 2. Personal website of Cheng Xinsong (www.chengxinsong.cn);
  • 3. HappyChat (chat. Chengxinsong.cn);
  • 4. Weekly weekly newspaper system (weekly.mwCXS. top);
  • And so on.

Ii. Open Source Works:

  • Watermarking plugin (github.com/saucxs/wate…
  • 2. Captcha – Mini plug-in (github.com/saucxs/capt…
  • 3, Watermark-image (github.com/saucxs/wate…
  • And so on.