Realization of PV-UV-IP and buried point technology

preface

Buried in the application of point technique in many larger flow is often used to hot technology, operated by the user or the request, record these operations, and then to record the number of operations, operating frequency to design the product, improve the user experience, and buried point technology in the realization of the front-end is also more than the back-end see more, This is because the user’s actions do not necessarily result in HTTP requests, and because it is difficult for the back end to monitor the user’s browsing of the page after the front-end SPA is prevalent, the burden of course falls on the front end.

Small episode: In fact, in most functional applications, through the buried point monitoring of each functional module, the user visit rate of the Banner rotation chart is very low, that is, the existence of the Banner is only a beautiful decoration in most cases, which also triggered a lot of debate among product managers.

PV, UV, AND IP Metric are the three most common metrics for website operation and management. They are also the three metrics that product managers want to use every day. For application developers, they will inevitably receive related development requirements, so WE will talk about these three metrics later.


What are PV, UV and IP

PV (Page View) refers to the number of Page views or clicks, which measures the number of pages visited by website users. Within a certain statistical period, the user will open or refresh a page for 1 time, and open or refresh the same page for many times will accumulate the page views. To put it more simply, count how many times a page is visited over a period of time, such as a day, even if it is visited multiple times by the same user, who may be particularly fond of the page? So repeated access is calculated to be valid.

UV (Unique Visitor)

The number of independent Internet Protocol (IP) IP addresses refers to the number of independent IP addresses that browse a page in a day. No matter how many pages are accessed by the same IP address, the number of independent IP addresses is 1. The count is increased by 1 for different IP addresses. IP distinguishes visitors based on the user’s WAN IP address, so multiple users (multiple LAN IP) accessing the Internet from the same router (the same WAN IP) may be recorded as a single IP visitor. If a user changes IP addresses repeatedly, the system may collect statistics for multiple times. In plain English, a user is identified by its IP address to count how many users access the application.


Where does the error come from

However, PV, UV and IP statistics are subject to error.

For example, during PV statistics, unknown sources of water soldiers may use scripts to repeatedly visit a web page, resulting in an abnormal surge in PV numbers. In this case, PV > real data.

UV statistics, if a user constantly clear cookies or change a lot of devices to access the words, then the user will be counted multiple times, then UV > real data. If multiple users share the same account and device, then UV < real data.

In IP statistics, if the user switches the network mode of the mobile phone (4G -> wifi), then IP > real data; if multiple users share the same device, then IP < real data. ** that is, errors always exist, in the case of a large amount of data, a long statistical period and obvious existence of some rules, in fact, these errors can be ignored.


The technical implementation

trigger

In fact, whether it is PV and UV statistics (IP statistics can be completed independently, without the front end’s participation), or buried point technology, to put it simply, is to send a suitable request to the back end at the right time.

When is the right time? This is also case-by-case. For example, PV count is usually performed in a route jump listener, but we can implement it in a global route hook. The statistics of UV rely on the back end more, the front end only needs to carry the kind of good cookie information to any request in the request body, the back end to filter and filter.

Buried technology scenarios are more complex, such as in certain button clicks, scrollbar listening event handlers, and so on.

How to send a request

The timing of the request varies from PV, UV, and buried point, and there is room for choice in the way the request is sent.

Common request methods such as ajax or FETCH to send GET/POST requests can certainly solve the need, but such methods tend to consume a lot and have a relatively slow speed. The advantage is that the data transmitted to the back end can carry a little more, and the data returned by request is generally in JSON format. It’s also easy to handle.

Using Ajax or FETCH, however, can cause cross-domain problems because sometimes the server that records buried data and PV and UV data is separate from the application server.

In many cases, the front end does not pass a lot of information when sending such requests, often just a few simple Query Params fields, and does not expect the server to return information to use.

So the real scenario-heavy implementation is done in the form of img requests.

Image Beacon technology

I received above that using img requests is the most feasible way in most cases, so why? How do you do that?

First of all, there is no cross-domain problem with Image Beacon, and browser security level restrictions do not apply to this.

Moreover, the request volume is smaller, the request speed is faster, and the network resource consumption is less.

In this case, why not choose other types of file requests such as JS files, CSS files, or TTF font class files?

Because JS and other types of files must be inserted into the document in the tree browser sends a request, is likely to bring the cost of rendering and is likely to block the render of the document tree, but not so good photo request, dot structure images not only not inserted into the DOM, as long as the new out of the Image object in JS can initiate the request, but also no congestion, In a browser environment without JS, the img tag can be used normally, which is not possible with other types of resource requests.

Speaking of which, there is one final choice to make: what format should I use for Img?

First, 1×1 pixel is the smallest legal image. And, because it is through the picture dot, so the picture is best transparent, transparent picture as long as the use of a binary mark picture is transparent color, do not store color space data, can save volume.

BMP, PNG and GIF all support transparent formats. Which one should we choose? The answer is the GIF format. According to statistics, the smallest BMP file needs 74 bytes, PNG needs 67 bytes, and the legal GIF only needs 43 bytes, so the small size of the request cost is currently lower.

Why is the best solution for this type of request to use transparent images in GIF format?

  1. Ability to complete the entire HTTP request + response (although no response content is required)
  2. After a GET request is triggered, there is no need to fetch and process the data, nor does the server need to send the data
  3. Cross-domain friendly
  4. There is no blocking during execution
  5. Better performance than sending GET requests with XMLHttpRequest objects
  6. GIF has the smallest legal size (74 bytes for the smallest BMP file, 67 bytes for PNG, and 43 bytes for a legal GIF)

The amazing thing is that the back end doesn’t even need to return the 1 * 1 image, because the front end doesn’t need to render it into the body, so it doesn’t matter if the back end returns 204 — Not Content, because the goal is to send the request, and once the request is sent, the rest is forgotten.


Specific application in the project

Next, let’s look at how to achieve PV and UV statistics and buried points in the project. Here I take Vue project as an example.

Encapsulate the Beacon action method

/** * @module beacon implementation module */
import Qs from 'querystring'

/** * @function beacon action * @param {String} apiUrl sent interface request * @param {Object} params sent data * @example beaconAction('/api/recored', { url: '... ' }).then((res) => {}).catch((error) => {}) */
export const beaconAction = (apiUrl, params) = > {
  /** If the argument is not a string, it is converted to query-string */
  let _params = typeof params === 'string' ? params : Qs.stringify(params)
  /** Create an Image object to send the request */
  let img = new Image(1.1)
  let src = `${apiUrl}?${_params}`
  img.src = src
  /** There is no need to append the image to the body, the request has already been sent, and the purpose has already been accomplished
  /** Use load and error events to listen for completion of the action and return Promise for ease of operation */
  return new Promise((resolve, reject) = > {
    img.onload = function () {
      resolve({ code: 200.data: 'success! ' })
    }
    img.onerror = function (e) {
      reject(new Error(e.error))
    }
  })
}
Copy the code

Record PV and UV in the route listener

/** ** PV/UV record */
router.afterEach((to, from) = > {
  const path = to.path
  /** If login permission authentication is enabled */
  if (process.env.AUTH_ENABLED) {
    /** All other routing interfaces request records */
    if(to.path ! = ='/login') {
      pathBeaconAction(path)
    }
  }
})
Copy the code

Buried points are implemented in Vue

In VUE, it is recommended that you use custom instructions to realize burying operations. After encapsulating appropriate custom instructions, you can easily set instructions to achieve burying effects on DOM or components that need burying.

Here we recommend you to use a third party instruction ** V-track ** to complete the requirements, you can go to the official website to see the detailed instructions.

Usage:

<! -- Track-view (v-track global registered component) -->
<track-view v-track:18015></track-view>
<track-view v-track:18015.watch="{ rest }"></track-view>
<track-view v-track:18015.watch.delay="{ rest }"></track-view>
<track-view v-if="rest" v-track:18015></track-view>
 
<! -- Event Behavior Buried Point (DOM) -->
<div v-track:18015.click="handleClick"></div>
<div v-track:18015.click="{ handleClick, item, index }"></div>
<div v-track:18015.click.async="{ handleSearch, rest }"></div>
<div v-track:18015.click.delay="handleClick"></div>
 
<! -- Event behavior burying point (component) -->
<cmp v-track:18015.click="handleClick"></cmp>
<cmp v-track:18015.[Custom event name]="handleSearch"></cmp>
<cmp v-track:18015.[Custom event name].delay="handleSearch"></cmp>
<cmp v-track:18015.[Custom event name].async="{ handleSearch, rest }"></cmp>
 
<! -- Region display buried point (block can be DOM or component)
<block v-track:18015.show></block>
<block v-track:18015.show.once></block>
<block v-track:18015.show.custom="{ ref: 'scroll' }"></block>
<block v-track:18015.show.custom.once="{ ref: 'scroll' }"></block>
Copy the code

Modifiers:

  • .clickRepresents the burying point of the event behavior
  • .[custom-event]Represents a burial point for custom event behavior
  • .nativeRepresents a buried point to listen for the component’s native Click event behavior
  • .watchRepresents a buried point for asynchronous page behavior
  • .asyncCooperate with.clickInstruction that represents a burying point for asynchronous event behavior
  • .delayIndicates whether the burying point is delayed. By default, the burying point is executed before the callback
  • .showRepresents the buried point of regional exposure
  • .onceCooperate with.showInstruction, only one burial point is executed
  • .customCooperate with.showCommand to use the custom scroll event

After the language

Buried point and PVUV implementation scheme is too many, and each scheme will cause a lot of people to discuss, in this hope that you can also have their own ideas, welcome to discuss.