├── .babelrc
├── .github
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
└── stale.yml
├── .gitignore
├── .travis.yml
├── LICENCE
├── README.md
├── SUMMARY.md
├── __mocks__
├── config.js
└── load-script.js
├── __tests__
├── create-trackers.spec.js
├── helpers.spec.js
├── lib
│ ├── event.spec.js
│ ├── exception.spec.js
│ ├── page.spec.js
│ ├── require.spec.js
│ ├── set.spec.js
│ ├── social.spec.js
│ └── time.spec.js
└── vuex-middleware.spec.js
├── docs
├── batch.md
├── console-logs.md
├── cross-domain-tracking.md
├── custom-analytics.md
├── custom-methods.md
├── debug.md
├── ecommerce.md
├── event-tracking.md
├── exception-tracking.md
├── fields.md
├── installation.md
├── opt-out.md
├── page-tracking.md
├── require.md
├── screen-tracking.md
├── script-loader.md
├── set.md
├── social-interactions.md
├── turn-off-development.md
├── untracked-hits.md
├── user-timings.md
├── v-ga.md
├── vuex.md
└── when-google-analytics-is-loaded.md
├── jest.config.js
├── package.json
├── src
├── bootstrap.js
├── collectors.js
├── config.js
├── create-trackers.js
├── directives
│ └── ga.js
├── helpers.js
├── index.js
├── lib
│ ├── ecommerce.js
│ ├── event.js
│ ├── exception.js
│ ├── index.js
│ ├── page.js
│ ├── query.js
│ ├── require.js
│ ├── screenview.js
│ ├── set.js
│ ├── social.js
│ └── time.js
├── no-ga.js
├── untracked.js
└── vuex-middleware.js
├── vue-analytics.d.ts
├── webpack.config.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "targets": "last 3 versions, ie >= 9"
7 | }
8 | ]
9 | ]
10 | }
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | If you are reporting a bug, please fill in below. Otherwise feel free to remove this template entirely.
2 |
3 | ### Description
4 |
5 | What are you reporting?
6 |
7 | ### Expected behavior
8 |
9 | Tell us what you think should happen.
10 |
11 | ### Actual behavior
12 |
13 | Tell us what actually happens.
14 |
15 | ### Environment
16 |
17 | Run this command in the project folder and fill in their results:
18 |
19 | `npm ls vue-analytics`:
20 |
21 | Then, specify:
22 |
23 | 1. Operating system:
24 | 2. Browser and version:
25 |
26 | ### Reproducible Demo
27 |
28 | Please take the time to create a new app that reproduces the issue or at least some code example
29 |
30 | Demonstrable issues gets fixed faster.
31 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)**
2 |
3 |
4 | **What is the current behavior? (You can also link to an open issue here)**
5 |
6 |
7 | **What is the new behavior (if this is a feature change)?**
8 |
9 |
10 | **Does this PR introduce a breaking change?**
11 |
12 |
13 | **Please check if the PR fulfills these requirements**
14 | - [ ] The commit message follows semantic-release [guidelines](https://github.com/semantic-release/semantic-release#commit-message-format)
15 | - [ ] Fix/Feature: Docs have been added/updated
16 | - [ ] Fix/Feature: Tests have been added; existing tests pass
17 |
18 | **Other information**:
19 |
20 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Number of days of inactivity before an issue becomes stale
2 | daysUntilStale: 14
3 | # Number of days of inactivity before a stale issue is closed
4 | daysUntilClose: 7
5 | # Issues with these labels will never be considered stale
6 | exemptLabels:
7 | - "P0: Critical"
8 | - "technical debt"
9 | - "feature"
10 | - "bug"
11 | - "pending"
12 | # Label to use when marking an issue as stale
13 | staleLabel: stale
14 | # Comment to post when marking an issue as stale. Set to `false` to disable
15 | markComment: >
16 | This issue has been automatically marked as stale because it has not had
17 | recent activity. It will be closed if no further activity occurs.
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | node_modules/
3 | .DS_Store
4 | npm-debug.log
5 | yarn-error.log
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | cache:
3 | directories:
4 | - node_modules
5 | notifications:
6 | email: false
7 | node_js:
8 | - '10'
9 | before_script:
10 | - npm prune
11 | script:
12 | - npm run test
13 | after_success:
14 | - npm run semantic-release
15 | branches:
16 | only:
17 | - master
18 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016-2017 Matteo Gabriele
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > :warning: Sorry but vue-analytics is not longer maintained. I would suggest you to switch to [vue-gtag](https://github.com/MatteoGabriele/vue-gtag). With love, the guy who made the package.
2 |
3 |
20 |
21 | # vue-analytics
22 |
23 | Vue plugin for Google Analytics
24 |
25 | ## Why should I use it?
26 |
27 | The plugin isn't just a wrapper of the Google Analytics API, but provides a solution to issues that most of the time you don't want to deal with or you not even know you have to deal with.
28 |
29 | For example:
30 |
31 | * Automatic Google Analytics script loading
32 | * Automatic page tracking
33 | * Event batching
34 | * Opt-out from Google Analytics with promise support
35 | * Multiple domain ID tracking system
36 | * Vuex support
37 | * E-commerce API
38 | * Vue error exception tracking system
39 | * Debugging API
40 |
41 | ## Does this library support GA4?
42 | Nope! GA4 is only supported by the new gtag.js library which you can find in the `vue-gtag` package.
43 | This package only uses analytics.js which doesn't provide that feature.
44 |
45 | ## Requirements
46 |
47 | Vue ^2.0.0
48 |
49 | ## Articles
50 |
51 | [Google Analytics, GDPR and Vuejs](https://medium.com/@matteo_gabriele/google-analytics-gdpr-and-vuejs-e1bd6affd2b4)
52 |
53 | [Vuejs and Google Analytics](https://medium.com/@matteo_gabriele/vuejs-and-google-analytics-689a07e00116)
54 |
55 | [Tips & tricks for vue-analytics](https://medium.com/@matteo_gabriele/tips-tricks-for-vue-analytics-87a9d2838915)
56 |
57 | ## Install
58 |
59 | ```bash
60 | npm install vue-analytics
61 | ```
62 |
63 | ## User guide
64 |
65 | * [Get started](/docs/installation.md)
66 | * [How to load Google Analytics](/docs/script-loader.md)
67 | * [Page tracking](/docs/page-tracking.md)
68 | * [Event tracking](/docs/event-tracking.md)
69 | * [Screen tracking](/docs/screen-tracking.md)
70 | * [Event batches](/docs/batch.md)
71 | * [v-ga](/docs/v-ga.md)
72 | * [Cross-domain tracking](/docs/cross-domain-tracking.md)
73 | * [User timings](/docs/user-timings.md#user-timings)
74 | * [Exception tracking](/docs/exception-tracking.md)
75 | * [Require](/docs/require.md)
76 | * [Set](/docs/set.md)
77 | * [Social interactions](/docs/social-interactions.md)
78 | * [Fields](/docs/fields.md)
79 | * [On Analytics script ready](/docs/when-google-analytics-is-loaded.md)
80 | * [Custom methods](/docs/custom-methods.md)
81 | * [E-commerce](/docs/ecommerce.md)
82 | * [Untracked hits](/docs/untracked-hits.md)
83 | * [Vuex](/docs/vuex.md)
84 | * [Turn off during development](/docs/turn-off-development.md)
85 | * [Console logs](/docs/console-logs.md)
86 | * [Opt-out from Google Analytics](/docs/opt-out.md)
87 | * [Custom analytics.js URL](/docs/custom-analytics.md)
88 | * [Debug](/docs/debug.md)
89 |
90 | Follow me on twitter [@matteo\_gabriele](https://twitter.com/matteo_gabriele)
91 |
--------------------------------------------------------------------------------
/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # Summary
2 |
3 | * [Get started](/docs/installation.md)
4 | * [How to load Google Analytics](/docs/script-loader.md)
5 | * [Page tracking](/docs/page-tracking.md)
6 | * [Event tracking](/docs/event-tracking.md)
7 | * [Screen tracking](/docs/screen-tracking.md)
8 | * [Event batches](/docs/batch.md)
9 | * [v-ga](/docs/v-ga.md)
10 | * [Cross-domain tracking](/docs/cross-domain-tracking.md)
11 | * [User timings](/docs/user-timings.md#user-timings)
12 | * [Exception tracking](/docs/exception-tracking.md)
13 | * [Require](/docs/require.md)
14 | * [Set](/docs/set.md)
15 | * [Social interactions](/docs/social-interactions.md)
16 | * [Fields](/docs/fields.md)
17 | * [On Analytics script ready](/docs/when-google-analytics-is-loaded.md)
18 | * [Custom methods](/docs/custom-methods.md)
19 | * [E-commerce](/docs/ecommerce.md)
20 | * [Untracked hits](/docs/untracked-hits.md)
21 | * [Vuex](/docs/vuex.md)
22 | * [Turn off during development](/docs/turn-off-development.md)
23 | * [Console logs](/docs/console-logs.md)
24 | * [Opt-out from Google Analytics](/docs/opt-out.md)
25 | * [Custom analytics.js URL](/docs/custom-analytics.md)
26 | * [Debug](/docs/debug.md)
27 |
--------------------------------------------------------------------------------
/__mocks__/config.js:
--------------------------------------------------------------------------------
1 | import config, { update, getId, reset } from '../src/config'
2 |
3 | export const mockUpdate = update
4 | export const mockGetId = getId
5 | export const mockReset = reset
6 |
7 | export default config
8 |
--------------------------------------------------------------------------------
/__mocks__/load-script.js:
--------------------------------------------------------------------------------
1 | export default function () {
2 | return new Promise((resolve, reject) => {
3 | process.nextTick(() => {
4 | window.ga = jest.fn()
5 | return resolve()
6 | })
7 | })
8 | }
9 |
--------------------------------------------------------------------------------
/__tests__/create-trackers.spec.js:
--------------------------------------------------------------------------------
1 | jest.mock('config')
2 |
3 | import config, { mockUpdate, mockGetId, mockReset } from 'config'
4 | import createTrackers from '../src/create-trackers'
5 | import { getTracker } from '../src/helpers'
6 |
7 | window.ga = jest.fn()
8 |
9 | afterEach(() => {
10 | mockReset()
11 | })
12 |
13 | it ('should initialize single tracker', () => {
14 | mockUpdate({ id: 'UA-1234-1' })
15 |
16 | createTrackers()
17 | expect(window.ga).toBeCalledWith('create', config.id, 'auto', {})
18 | expect(window.ga).not.toBeCalledWith('set', 'sendHitTask', null)
19 | })
20 |
21 | it ('should initialize multiple trackers', () => {
22 | mockUpdate({ id: [ 'UA-1234-1', 'UA-1234-2' ] })
23 |
24 | createTrackers()
25 |
26 | mockGetId().forEach((id) => {
27 | expect(window.ga).toBeCalledWith('create', id, 'auto', { 'name': getTracker(id) })
28 | })
29 | })
30 |
31 | it('should intialize each id with its own configuration', () => {
32 | const customIdFields = {
33 | 'UA-12345-1': {
34 | clientId: '1'
35 | },
36 | 'UA-54321-1': {
37 | clientId: '2'
38 | },
39 | }
40 |
41 | mockUpdate({
42 | id: ['UA-12345-1', 'UA-54321-1'],
43 | fields: {
44 | 'global': true
45 | },
46 | customIdFields,
47 | })
48 |
49 | createTrackers()
50 |
51 | mockGetId().forEach(id => {
52 | expect(window.ga).toBeCalledWith('create', id, 'auto', {
53 | global: true,
54 | ...customIdFields[id],
55 | name: getTracker(id),
56 | })
57 | })
58 | })
59 |
60 | it ('should add linkers if list is not empty', function () {
61 | mockUpdate({
62 | id: 'UA-1234-1',
63 | linkers: ['www.google.com', 'www.bing.com']
64 | })
65 |
66 | createTrackers()
67 |
68 | expect(config.linkers).toHaveLength(2)
69 | expect(window.ga).toBeCalledWith('require', 'linker')
70 | expect(window.ga).toBeCalledWith('linker:autoLink', config.linkers)
71 | })
72 |
73 | it ('should stop sending hit if sendHitTask is set to false', () => {
74 | mockUpdate({
75 | id: 'UA-1234-1',
76 | debug: {
77 | sendHitTask: false
78 | }
79 | })
80 |
81 | createTrackers()
82 |
83 | expect(config.debug.sendHitTask).toBe(false)
84 | expect(window.ga).toBeCalledWith('set', 'sendHitTask', null)
85 | })
86 |
87 | it ('should set the trace property if debug is enabled', () => {
88 | mockUpdate({
89 | id: 'UA-1234-1',
90 | debug: {
91 | enabled: true,
92 | trace: true
93 | }
94 | })
95 |
96 | createTrackers()
97 |
98 | expect(config.debug.enabled).toBe(true)
99 | expect(window.ga_debug.trace).toBe(true)
100 | })
101 |
--------------------------------------------------------------------------------
/__tests__/helpers.spec.js:
--------------------------------------------------------------------------------
1 | jest.mock('config')
2 |
3 | import * as helpers from '../src/helpers'
4 | import config, { mockGetId, mockUpdate } from 'config'
5 |
6 | describe('noop', () => {
7 | it ('should be a function', () => {
8 | expect(typeof helpers.noop).toEqual('function')
9 | })
10 | })
11 |
12 | describe('merge', () => {
13 | it ('should merge two objects', () => {
14 | const a = { a: 1, c: { a: 1 } }
15 | const b = { b: 1, c: { b: 1 } }
16 | const c = helpers.merge(a, b)
17 |
18 | expect(c).toMatchObject({
19 | a: 1,
20 | b: 1,
21 | c: {
22 | b: 1,
23 | a: 1
24 | }
25 | })
26 | })
27 |
28 | it ('should merge objects containing non-objects', () => {
29 | const a = { c: [ 1, 2, 3 ], d: Promise.resolve({ a: 1 }) }
30 | const b = { c: [ 4, 5 ], d: { b: 1 } }
31 | const c = helpers.merge(a, b)
32 |
33 | expect(c).toEqual({
34 | c: [
35 | 4,
36 | 5,
37 | 3
38 | ],
39 | d: {
40 | b: 1
41 | }
42 | })
43 | })
44 | })
45 |
46 | describe('getMethod', () => {
47 | it ('should return the plain method name if single tracker', () => {
48 | mockUpdate({ id: 'UA-1234-5' })
49 |
50 | const method = helpers.getMethod('send', config.id)
51 | expect(method).toEqual('send')
52 | })
53 |
54 | it ('should return the method name prepended with tracker name if multiple trackers', () => {
55 | mockUpdate({ id: ['UA-1234-5', 'UA-1234-6'] })
56 |
57 | const method = helpers.getMethod('send', 'UA-1234-5')
58 | expect(method).toEqual('UA12345.send')
59 | })
60 | })
61 |
62 | describe('getTracker', () => {
63 | it ('should return the tracking id without dashes', () => {
64 | const tracker1 = helpers.getTracker('UA-1234-5')
65 | expect(tracker1).toEqual('UA12345')
66 | })
67 | })
68 |
69 | describe('getQueryString', () => {
70 | it ('should return a query string from an object literal', () => {
71 | const obj = { name: 'matteo', surname: 'gabriele' }
72 | const queryString = helpers.getQueryString(obj)
73 |
74 | expect(queryString).toEqual('?name=matteo&surname=gabriele')
75 | })
76 |
77 | it ('should return a empty string if object literal is empty', () => {
78 | const obj = {}
79 | const queryString = helpers.getQueryString(obj)
80 |
81 | expect(queryString).toEqual('')
82 | })
83 | })
84 |
85 | describe('isRouteIgnored', () => {
86 | it ('should be truthy if home route name is added to ignoreRoutes list', () => {
87 | mockUpdate({ id: 'UA-1234-5', ignoreRoutes: ['home'] })
88 | expect(helpers.isRouteIgnored({ name: 'home' })).toBeTruthy()
89 | })
90 |
91 | it ('should be truthy if home route path is added to ignoreRoutes list', () => {
92 | mockUpdate({ id: 'UA-1234-5', ignoreRoutes: ['/'] })
93 | expect(helpers.isRouteIgnored({ path: '/' })).toBeTruthy()
94 | })
95 |
96 | it ('should be falsy if a `null` value is added to ignoreRoutes list', () => {
97 | mockUpdate({ id: 'UA-1234-5', ignoreRoutes: [null] })
98 | expect(helpers.isRouteIgnored({ path: '/' })).toBeFalsy()
99 | })
100 | })
101 |
--------------------------------------------------------------------------------
/__tests__/lib/event.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueAnalytics from '../../src'
3 |
4 | window.ga = jest.fn()
5 |
6 | let $vm
7 |
8 | beforeEach(() => {
9 | window.ga.mockClear()
10 |
11 | Vue.use(VueAnalytics, {
12 | id: 'UA-1234-5'
13 | })
14 |
15 | $vm = new Vue({})
16 |
17 | $vm.$mount()
18 | })
19 |
20 | it ('should track an event', () => {
21 | $vm.$ga.event('foo', 'bar')
22 | expect(window.ga).toBeCalledWith('send', 'event', 'foo', 'bar')
23 | })
24 |
--------------------------------------------------------------------------------
/__tests__/lib/exception.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueAnalytics from '../../src'
3 |
4 | window.ga = jest.fn()
5 |
6 | let $vm
7 |
8 | beforeEach(() => {
9 | window.ga.mockClear()
10 |
11 | Vue.config.errorHandler = jest.fn()
12 |
13 | Vue.use(VueAnalytics, {
14 | id: 'UA-1234-5'
15 | })
16 |
17 | $vm = new Vue({})
18 |
19 | $vm.$mount()
20 | })
21 |
22 | it ('should track an error exception', () => {
23 | $vm.$ga.exception('bad stuff', true)
24 |
25 | expect(window.ga).toBeCalledWith('send', 'exception', {
26 | exDescription: 'bad stuff',
27 | exFatal: true
28 | })
29 | })
30 |
--------------------------------------------------------------------------------
/__tests__/lib/page.spec.js:
--------------------------------------------------------------------------------
1 | jest.mock('config')
2 | jest.mock('load-script')
3 |
4 | import Vue from 'vue'
5 | import VueAnalytics from '../../src/index'
6 | import VueRouter from 'vue-router'
7 | import config, { mockUpdate } from 'config'
8 |
9 | const routes = [
10 | {
11 | name: 'home',
12 | path: '/',
13 | component: {
14 | name: 'home',
15 | render: h => h('div')
16 | }
17 | },
18 | {
19 | name: 'about',
20 | path: '/about',
21 | component: {
22 | name: 'about',
23 | render: h => h('div')
24 | }
25 | }
26 | ]
27 |
28 | window.ga = jest.fn()
29 |
30 | let $vm
31 |
32 | beforeEach(done => {
33 | window.ga.mockClear()
34 |
35 | Vue.use(VueRouter)
36 |
37 | const router = new VueRouter({
38 | mode: 'hash',
39 | routes
40 | })
41 |
42 | Vue.use(VueAnalytics, {
43 | id: 'UA-1234-5',
44 | router
45 | })
46 |
47 | $vm = new Vue({
48 | router,
49 | render: (h) => h('router-view')
50 | })
51 |
52 | $vm.$mount()
53 |
54 | Vue.nextTick(done)
55 | })
56 |
57 | it ('should track a page', () => {
58 | $vm.$ga.page('/')
59 |
60 | expect(window.ga).toBeCalledWith('set', 'page', '/')
61 | expect(window.ga).toBeCalledWith('send', 'pageview', '/')
62 | })
63 |
64 | it ('should set and track page with a VueRouter instance', () => {
65 | $vm.$ga.page($vm.$router)
66 |
67 | expect(window.ga).toBeCalledWith('set', 'page', '/')
68 | expect(window.ga).toBeCalledWith('send', 'pageview', '/')
69 | })
70 |
71 | it ('should skip tracking when page first argument is a falsy value', () => {
72 | $vm.$ga.page(null)
73 | $vm.$ga.page(false)
74 | $vm.$ga.page(undefined)
75 | // Google officially states that page path must begin with '/'
76 | // https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#page
77 | $vm.$ga.page('')
78 |
79 | expect(window.ga).not.toHaveBeenCalled()
80 | expect(window.ga).not.toHaveBeenCalled()
81 |
82 | // Skip behavior must be explicit
83 | $vm.$ga.page()
84 |
85 | expect(window.ga).toHaveBeenCalled()
86 | expect(window.ga).toHaveBeenCalled()
87 | })
88 |
--------------------------------------------------------------------------------
/__tests__/lib/require.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueAnalytics from '../../src'
3 |
4 | window.ga = jest.fn()
5 |
6 | let $vm
7 |
8 | beforeEach(() => {
9 | window.ga.mockClear()
10 |
11 | Vue.use(VueAnalytics, {
12 | id: 'UA-1234-5'
13 | })
14 |
15 | $vm = new Vue({})
16 |
17 | $vm.$mount()
18 | })
19 |
20 | it ('should require a plugin', () => {
21 | $vm.$ga.require('myplugin')
22 |
23 | expect(window.ga).toBeCalledWith('require', 'myplugin')
24 | })
25 |
26 | it ('should require a plugin with options', () => {
27 | $vm.$ga.require('myplugin', {
28 | foo: 'bar'
29 | })
30 |
31 | expect(window.ga).toBeCalledWith('require', 'myplugin', {
32 | foo: 'bar'
33 | })
34 | })
35 |
--------------------------------------------------------------------------------
/__tests__/lib/set.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueAnalytics from '../../src'
3 |
4 | window.ga = jest.fn()
5 |
6 | let $vm
7 |
8 | beforeEach(() => {
9 | window.ga.mockClear()
10 |
11 | Vue.use(VueAnalytics, {
12 | id: 'UA-1234-5'
13 | })
14 |
15 | $vm = new Vue({})
16 |
17 | $vm.$mount()
18 | })
19 |
20 | it ('should set a variable on Google Analytics', () => {
21 | $vm.$ga.set('foo', 'bar')
22 |
23 | expect(window.ga).toBeCalledWith('set', 'foo', 'bar')
24 | })
25 |
26 | it ('should set a variable on Google Analytics with an object literal', () => {
27 | $vm.$ga.set({
28 | fieldName: 'foo',
29 | fieldValue: 'bar'
30 | })
31 |
32 | expect(window.ga).toBeCalledWith('set', {
33 | fieldName: 'foo',
34 | fieldValue: 'bar'
35 | })
36 | })
37 |
--------------------------------------------------------------------------------
/__tests__/lib/social.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueAnalytics from '../../src'
3 |
4 | window.ga = jest.fn()
5 |
6 | let $vm
7 |
8 | beforeEach(() => {
9 | window.ga.mockClear()
10 |
11 | Vue.use(VueAnalytics, {
12 | id: 'UA-1234-5'
13 | })
14 |
15 | $vm = new Vue({})
16 |
17 | $vm.$mount()
18 | })
19 |
20 | it ('should track a social interaction', () => {
21 | $vm.$ga.social('Facebook', 'like', 'http://foo.com')
22 | expect(window.ga).toBeCalledWith('send', 'social', 'Facebook', 'like', 'http://foo.com')
23 | })
24 |
25 | it ('should track a social interaction with an object literal', () => {
26 | $vm.$ga.social({
27 | socialNetwork: 'Facebook',
28 | socialAction: 'like',
29 | socialTarget: 'http://foo.com'
30 | })
31 |
32 | expect(window.ga).toBeCalledWith('send', 'social', {
33 | socialNetwork: 'Facebook',
34 | socialAction: 'like',
35 | socialTarget: 'http://foo.com'
36 | })
37 | })
38 |
--------------------------------------------------------------------------------
/__tests__/lib/time.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueAnalytics from '../../src'
3 |
4 | window.ga = jest.fn()
5 |
6 | let $vm
7 |
8 | beforeEach(() => {
9 | window.ga.mockClear()
10 |
11 | Vue.use(VueAnalytics, {
12 | id: 'UA-1234-5'
13 | })
14 |
15 | $vm = new Vue({})
16 |
17 | $vm.$mount()
18 | })
19 |
20 | it ('should track timing', () => {
21 | $vm.$ga.time('category', 'variable', 123, 'label')
22 |
23 | expect(window.ga).toBeCalledWith('send', 'timing', 'category', 'variable', 123, 'label')
24 | })
25 |
26 | it ('should track timing with an object literal', () => {
27 | $vm.$ga.time({
28 | timingCategory: 'category',
29 | timingVar: 'variable',
30 | timingValue: 123,
31 | timingLabel: 'label'
32 | })
33 |
34 | expect(window.ga).toBeCalledWith('send', 'timing', {
35 | timingCategory: 'category',
36 | timingVar: 'variable',
37 | timingValue: 123,
38 | timingLabel: 'label'
39 | })
40 | })
41 |
--------------------------------------------------------------------------------
/__tests__/vuex-middleware.spec.js:
--------------------------------------------------------------------------------
1 | jest.mock('load-script')
2 |
3 | import Vue from 'vue'
4 | import VueAnalytics from '../src'
5 | import analyticsMiddleware from '../src/vuex-middleware'
6 | window.ga = jest.fn()
7 |
8 | let $vm
9 | let store
10 | beforeEach(() => {
11 | window.ga.mockClear()
12 | store = {
13 | subscribers: [],
14 | subscribe: function (fn) {
15 | this.subscribers.push(fn)
16 | },
17 | fire: function (mutation) {
18 | this.subscribers.forEach(x => { x(mutation) })
19 | }
20 | }
21 |
22 | analyticsMiddleware(store)
23 | Vue.use(VueAnalytics, {
24 | id: 'UA-1234-5'
25 | })
26 | $vm = new Vue({})
27 |
28 | $vm.$mount()
29 | })
30 |
31 | describe('input check', () => {
32 | it('should allow meta tags without analytics', () => {
33 | let mutation = {
34 | payload: {
35 | meta: {
36 |
37 | }
38 | }
39 | }
40 | expect(() => { store.fire(mutation) }).not.toThrowError()
41 | })
42 |
43 | it('should throw an error when analytics is not an array', () => {
44 | let mutation = {
45 | payload: {
46 | meta: {
47 | analytics: {}
48 | }
49 | }
50 | }
51 | expect(() => { store.fire(mutation) }).toThrowError()
52 | })
53 |
54 | it('should throw an unknown type error', () => {
55 | let mutation = {
56 | payload: {
57 | meta: {
58 | analytics: [['unknown']]
59 | }
60 | }
61 | }
62 | expect(() => { store.fire(mutation) }).toThrowError()
63 | })
64 |
65 | it('should throw an unknown method for type error', () => {
66 | let mutation = {
67 | payload: {
68 | meta: {
69 | analytics: [['event:unknown']]
70 | }
71 | }
72 | }
73 | expect(() => { store.fire(mutation) }).toThrowError()
74 | })
75 |
76 | it('should throw an error because ecommerce requires a method call', () => {
77 | let mutation = {
78 | payload: {
79 | meta: {
80 | analytics: [['ecommerce']]
81 | }
82 | }
83 | }
84 | expect(() => { store.fire(mutation) }).toThrowError()
85 | })
86 | })
87 |
88 | describe('fire event', () => {
89 | it('should fire a simple tracking event based on the meta payload', () => {
90 | let mutation = {
91 | payload: {
92 | meta: {
93 | analytics: [
94 | [
95 | 'event', 'CLICK', 'TEST', 'LABEL', 1
96 | ]
97 | ]
98 | }
99 | }
100 | }
101 | store.fire(mutation)
102 | expect(window.ga).toBeCalledWith('send', 'event', 'CLICK', 'TEST', 'LABEL', 1)
103 | })
104 |
105 |
106 | it('should fire a simple event based on the meta payload', () => {
107 | let mutation = {
108 | payload: {
109 | meta: {
110 | analytics: [
111 | [
112 | 'event', 'foo', 'bar'
113 | ]
114 | ]
115 | }
116 | }
117 | }
118 | store.fire(mutation)
119 | expect(window.ga).toBeCalledWith('send', 'event', 'foo', 'bar')
120 | })
121 |
122 | it('should fire a simple exception event based on the meta payload', () => {
123 | let mutation = {
124 | payload: {
125 | meta: {
126 | analytics: [
127 | [
128 | 'exception', 'CLICK', 'TEST'
129 | ]
130 | ]
131 | }
132 | }
133 | }
134 | store.fire(mutation)
135 | expect(window.ga).toBeCalledWith('send', 'exception', { exDescription: 'CLICK', exFatal: 'TEST' })
136 | })
137 |
138 | it('should fire a simple set event based on the meta payload', () => {
139 | let mutation = {
140 | payload: {
141 | meta: {
142 | analytics: [
143 | [
144 | 'set', 'foo', 'bar'
145 | ]
146 | ]
147 | }
148 | }
149 | }
150 | store.fire(mutation)
151 | expect(window.ga).toBeCalledWith('set', 'foo', 'bar')
152 | })
153 |
154 |
155 | it('should fire a simple social event based on the meta payload', () => {
156 | let mutation = {
157 | payload: {
158 | meta: {
159 | analytics: [
160 | [
161 | 'social', 'Facebook', 'like', 'http://foo.com'
162 | ]
163 | ]
164 | }
165 | }
166 | }
167 | store.fire(mutation)
168 | expect(window.ga).toBeCalledWith('send', 'social', 'Facebook', 'like', 'http://foo.com')
169 | })
170 |
171 | it('should fire a simple timing event based on the meta payload', () => {
172 | let mutation = {
173 | payload: {
174 | meta: {
175 | analytics: [
176 | [
177 | 'time', 'category', 'variable', 123, 'label'
178 | ]
179 | ]
180 | }
181 | }
182 | }
183 | store.fire(mutation)
184 | expect(window.ga).toBeCalledWith('send', 'timing', 'category', 'variable', 123, 'label')
185 | })
186 |
187 |
188 | it('should fire a simple timing event based on the meta payload', () => {
189 | let mutation = {
190 | payload: {
191 | meta: {
192 | analytics: [
193 | [
194 | 'time', 'category', 'variable', 123, 'label'
195 | ]
196 | ]
197 | }
198 | }
199 | }
200 | store.fire(mutation)
201 | expect(window.ga).toBeCalledWith('send', 'timing', 'category', 'variable', 123, 'label')
202 | })
203 |
204 | it('should fire a simple page event based on the meta payload', () => {
205 | let mutation = {
206 | payload: {
207 | meta: {
208 | analytics: [
209 | [
210 | 'page', '/'
211 | ]
212 | ]
213 | }
214 | }
215 | }
216 | store.fire(mutation)
217 | expect(window.ga).toBeCalledWith('set', 'page', '/')
218 | expect(window.ga).toBeCalledWith('send', 'pageview', '/')
219 | })
220 |
221 | it('should fire a simple require event based on the meta payload', () => {
222 | let mutation = {
223 | payload: {
224 | meta: {
225 | analytics: [
226 | [
227 | 'require', 'myplugin', { foo: 'bar' }
228 | ]
229 | ]
230 | }
231 | }
232 | }
233 | store.fire(mutation)
234 | expect(window.ga).toBeCalledWith('require', 'myplugin', {
235 | foo: 'bar'
236 | })
237 | })
238 |
239 | it('should fire a simple query event based on the meta payload', () => {
240 | let mutation = {
241 | payload: {
242 | meta: {
243 | analytics: [
244 | [
245 | 'query', 'test'
246 | ]
247 | ]
248 | }
249 | }
250 | }
251 | store.fire(mutation)
252 | expect(window.ga).toBeCalledWith('test')
253 | })
254 |
255 | it('should fire a ecommerce query event based on the meta payload', () => {
256 | let item = {
257 | id: '1234',
258 | name: 'Fluffy Pink Bunnies',
259 | sku: 'DD23444',
260 | category: 'Party Toys',
261 | price: '11.99',
262 | quantity: '1'
263 | }
264 | let mutation = {
265 | payload: {
266 | meta: {
267 | analytics: [
268 | ['ecommerce:addItem', item]
269 | ]
270 | }
271 | }
272 | }
273 | store.fire(mutation)
274 | expect(window.ga).toBeCalledWith('ecommerce:addItem', item)
275 | })
276 |
277 | it('should allow multiple events to fire', () => {
278 | let mutation = {
279 | payload: {
280 | meta: {
281 | analytics: [
282 | [
283 | 'event', 'foo', 'bar'
284 | ],
285 | [
286 | 'exception', 'CLICK', 'TEST', 'LABEL', 1
287 | ]
288 | ]
289 | }
290 | }
291 | }
292 | store.fire(mutation)
293 | expect(window.ga).toBeCalledWith('send', 'event', 'foo', 'bar')
294 | expect(window.ga).toBeCalledWith('send', 'exception', { exDescription: 'CLICK', exFatal: 'TEST' })
295 |
296 | })
297 | })
298 |
--------------------------------------------------------------------------------
/docs/batch.md:
--------------------------------------------------------------------------------
1 | ## Event batches
2 |
3 | It is possible to fire event using a queue that will be processed on a certain rate.
4 | The gap between each cycle and the amount of events fired on each cycle is totally customizable: default options are 2 events every 500ms.
5 |
6 | ```js
7 | import Vue from 'vue'
8 | import VueAnalytics from 'vue-analytics'
9 |
10 | Vue.use(VueAnalytics, {
11 | id: 'UA-XXX-X',
12 | batch: {
13 | enabled: true, // enable/disable
14 | amount: 2, // amount of events fired
15 | delay: 500 // delay in milliseconds
16 | }
17 | })
18 | ```
--------------------------------------------------------------------------------
/docs/console-logs.md:
--------------------------------------------------------------------------------
1 | ## Console logs
2 |
3 | Implements Google Analaytics debug logs in your console.
4 |
5 | **Please remember that it is for debug only. The file size of analytics\_debug.js is way larger than analytics.js**
6 |
7 | Example:
8 |
9 | ```js
10 | Vue.use(VueAnalytics, {
11 | id: 'UA-XXX-X',
12 | debug: {
13 | enabled: true
14 | }
15 | })
16 | ```
17 |
18 | Google Analytics docs: [debugging](https://developers.google.com/analytics/devguides/collection/analyticsjs/debugging)
19 |
--------------------------------------------------------------------------------
/docs/cross-domain-tracking.md:
--------------------------------------------------------------------------------
1 | ## Cross-domain tracking
2 |
3 | To enable cross-domain tracking you need to add your links in the `linkers` array in the configuration object
4 |
5 | ```js
6 | import Vue from 'vue'
7 | import VueAnalytics from 'vue-analytics'
8 |
9 | Vue.use(VueAnalytics, {
10 | id: 'UA-XXX-X',
11 | linkers: ['example1.com', 'example2.com']
12 | })
13 | ```
14 |
15 | More information about [cross-domain tracking](https://support.google.com/analytics/answer/1034342?hl=en)
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/custom-analytics.md:
--------------------------------------------------------------------------------
1 | ## Custom analytics.js URL
2 |
3 | Due to country restrictions, in specific cases is necessary to add a custom URL to load the analytics.js file.
4 |
5 | It is possible to use the `customResourceURL` prop in the plugin options
6 |
7 | ```js
8 | Vue.use(VueAnalytics, {
9 | id: 'UA-XXX-X',
10 | customResourceURL: 'http://your-custom-url/analytics.js'
11 | })
12 | ```
13 |
14 | By adding the `customResourceURL` you won't be able to switch between debug and production file, so you need to do it manually, depending on which file you want to use.
--------------------------------------------------------------------------------
/docs/custom-methods.md:
--------------------------------------------------------------------------------
1 | ## Custom methods
2 |
3 | Google Analytics has a very big api and sometimes the wrapper might limit you on what you need, so it's still possible to access the plain Analytics api
4 |
5 | ```js
6 | this.$ga.query(...)
7 | ```
8 |
9 | if you need more interaction or you want to add specific features, please add an issue on the repo or make a pull request
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/docs/debug.md:
--------------------------------------------------------------------------------
1 | ## Debug
2 |
3 | Implements Google Analaytics debug library.
4 |
5 | **Please remember that it is for debug only. The file size of analytics\_debug.js is way larger than analytics.js**
6 |
7 | Example:
8 |
9 | ```js
10 | Vue.use(VueAnalytics, {
11 | id: 'UA-XXX-X',
12 | debug: {
13 | enabled: false, // default value
14 | trace: false, // default value
15 | sendHitTask: true // default value
16 | }
17 | })
18 | ```
19 |
20 | Google Analytics docs: [debugging](https://developers.google.com/analytics/devguides/collection/analyticsjs/debugging)
21 |
--------------------------------------------------------------------------------
/docs/ecommerce.md:
--------------------------------------------------------------------------------
1 | ## E-commerce
2 |
3 | All e-commerce features are built-in in the plugin, so there's no need to require any e-commerce libraries: just enable the e-commerce features from the plugin configuration
4 |
5 | ```js
6 | import Vue from 'vue'
7 | import VueAnalytics from 'vue-analytics'
8 |
9 | Vue.use(VueAnalytics, {
10 | id: 'UA-XXX-X',
11 | ecommerce: {
12 | enabled: true
13 | }
14 | })
15 | ```
16 |
17 | It is also possible to use the Enhanced E-commerce library just by changing the configuration like so
18 |
19 | ```js
20 | Vue.use(VueAnalytics, {
21 | id: 'UA-XXX-X',
22 | ecommerce: {
23 | enabled: true,
24 | enhanced: true
25 | }
26 | })
27 | ```
28 |
29 | Finally it's possible to pass additional options during the installation of the library
30 |
31 | ```js
32 | Vue.use(VueAnalytics, {
33 | id: 'UA-XXX-X',
34 | ecommerce: {
35 | enabled: true,
36 | options: { ... }
37 | }
38 | })
39 | ```
40 |
41 | ### Usage
42 | All e-commerce features are accessable via the `ecommerce` object
43 |
44 | - addItem
45 | - addTransaction
46 | - addProduct
47 | - addImpression
48 | - setAction
49 | - addPromo
50 | - send
51 |
52 | Remember that not all methods are included in the E-commerce or the Enhanced E-commerce, so please check the relative documentation in the Google Analytics dev guide.
53 |
54 | - [E-commerce](https://developers.google.com/analytics/devguides/collection/analyticsjs/ecommerce)
55 | - [Enhanced E-commerce](https://developers.google.com/analytics/devguides/collection/analyticsjs/enhanced-ecommerce)
56 |
57 |
58 | ```html
59 |
60 |
61 |
62 |
63 |
64 |
65 |
83 | ```
84 |
--------------------------------------------------------------------------------
/docs/event-tracking.md:
--------------------------------------------------------------------------------
1 | ## Event tracking
2 |
3 | Event tracking can be achieved in different ways, following Google specifications
4 |
5 | passing parameters in this exact order
6 |
7 | ```js
8 | this.$ga.event('category', 'action', 'label', 123)
9 | ```
10 |
11 | an object literal is also possible
12 |
13 | ```js
14 | this.$ga.event({
15 | eventCategory: 'category',
16 | eventAction: 'action',
17 | eventLabel: 'label',
18 | eventValue: 123
19 | })
20 | ```
21 |
22 | Google Analytics docs: [event tracking](https://developers.google.com/analytics/devguides/collection/analyticsjs/events)
23 |
24 | ##
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/docs/exception-tracking.md:
--------------------------------------------------------------------------------
1 | ## Exception tracking
2 |
3 | Exception tracking allows you to measure the number and type of crashes or errors that occur in your application
4 |
5 | is possible to track single exceptions using a try catch
6 |
7 | ```js
8 | try {
9 | // some code that might crash
10 | } catch (error) {
11 | // handle your error here
12 |
13 | // track the error with analytics
14 | // depending on the error you might want to check
15 | // if a `message` property exists or not
16 | const exception = error.message || error
17 | this.$ga.exception(exception)
18 | }
19 | ```
20 |
21 | ### Enable exception auto tracking
22 |
23 | It is also possible to just enable the plugin exception auto tracking and the plugin will do everything for you
24 |
25 | ```js
26 | Vue.use(VueAnalytics, {
27 | id: 'UA-XXX-X',
28 | autoTracking: {
29 | exception: true
30 | }
31 | })
32 | ```
33 |
34 | **important: the auto tracking script uses Vue.config.errorHandler, if you need to add your handler, do it before installing the plugin or will be overwritten**
35 |
36 | ### Error logs
37 |
38 | When auto-tracking errors logs are automatically logged in the console, if you want to disable them, you can add this property to your configuration
39 |
40 | ```js
41 | Vue.use(VueAnalytics, {
42 | id: 'UA-XXX-X',
43 | autoTracking: {
44 | exception: true,
45 | exceptionLogs: false
46 | }
47 | })
48 | ```
49 |
50 |
51 | Google Analytics docs: [exceptions](https://developers.google.com/analytics/devguides/collection/analyticsjs/exceptions)
52 |
53 |
--------------------------------------------------------------------------------
/docs/fields.md:
--------------------------------------------------------------------------------
1 | ## Tracker fields
2 |
3 | It is possible to setup initial tracker fields using the `fields` prop
4 |
5 | ```js
6 | Vue.use(VueAnalytics, {
7 | id: 'UA-XXX-X',
8 | fields: {
9 | userId: 'xxx'
10 | }
11 | })
12 | ```
13 |
14 | It's also possible to add fields per id
15 |
16 | ```js
17 | Vue.use(VueAnalytics, {
18 | id: ['UA-12345-1', 'UA-54321-2'],
19 | //fields for both IDS
20 | fields: {
21 | userId: '1',
22 | },
23 | customIdFields: {
24 | 'UA-12345-1': {
25 | clientId: '2'
26 | },
27 | 'UA-54321-2': {
28 | clientId: '3'
29 | }
30 | }
31 | })
32 | ```
33 |
34 | **it is also possible to set fields in runtime using the **[**set**](/docs/set.md)** method**
35 |
--------------------------------------------------------------------------------
/docs/installation.md:
--------------------------------------------------------------------------------
1 | ## Get started
2 |
3 | ### Installation
4 | ```bash
5 | npm install vue-analytics
6 | ```
7 |
8 | Start using it your Vue application
9 | ```js
10 | import Vue from 'vue'
11 | import VueAnalytics from 'vue-analytics'
12 |
13 | Vue.use(VueAnalytics, {
14 | id: 'UA-XXX-X'
15 | })
16 | ```
17 |
18 | **Important**
19 |
20 | For all the ES5 users out there, this package uses a default export so if you want to use `require` instead of `import` you should import the plugin like this
21 |
22 | ```js
23 | const VueAnalytics = require('vue-analytics').default
24 |
25 | Vue.use(VueAnalytics, { ... })
26 | ```
27 |
28 | ### Usage
29 | it is possible to use the api in two different ways:
30 | - within the component scope
31 | - importing methods separately
32 |
33 | #### Component scope
34 |
35 | ```js
36 | export default {
37 | name: 'MyComponent',
38 |
39 | methods: {
40 | track () {
41 | this.$ga.page('/')
42 | }
43 | }
44 | }
45 | ```
46 |
47 | #### Import methods
48 |
49 | To be able to use methods import, make sure you install vue-analytics **before** you want to use them
50 |
51 | ```js
52 | import { page } from 'vue-analytics'
53 |
54 | export default {
55 | name: 'MyComponent',
56 |
57 | methods: {
58 | track () {
59 | page('/')
60 | }
61 | }
62 | }
63 | ```
64 |
65 | #### API
66 | - event
67 | - ecommerce
68 | - set
69 | - page
70 | - query
71 | - screenview
72 | - time
73 | - require
74 | - exception
75 | - social
76 |
77 | ## Track multiple accounts
78 |
79 | Pass an array of strings for a multiple tracking system. Every hit will be fired twice: each time with a different tracker name
80 |
81 | ```js
82 | import Vue from 'vue'
83 | import VueAnalytics from 'vue-analytics'
84 |
85 | Vue.use(VueAnalytics, {
86 | id: ['UA-XXX-A', 'UA-XXX-B']
87 | })
88 | ```
89 |
90 | ## Use functions or/and Promises
91 |
92 | It is also possible to pass a function, a Promise or a function that returns a Promise: as soon as it returns always a string or an array of strings
93 |
94 | ```js
95 | import Vue from 'vue'
96 | import VueAnalytics from 'vue-analytics'
97 | import axios from 'axios'
98 |
99 | // a function
100 | Vue.use(VueAnalytics, {
101 | id () {
102 | return 'UA-XXX-A'
103 | }
104 | })
105 |
106 | // a Promise
107 | Vue.use(VueAnalytics, {
108 | id: axios.get('/api/foo').then(response => {
109 | return response.data
110 | })
111 | })
112 |
113 | // a function that returns a Promise
114 | Vue.use(VueAnalytics, {
115 | id: () => axios.get('/api/foo').then(response => {
116 | return response.data
117 | })
118 | })
119 | ```
120 |
--------------------------------------------------------------------------------
/docs/opt-out.md:
--------------------------------------------------------------------------------
1 | ## Opt-out from Google Analytics
2 |
3 | It is possible to opt-out from Google Analytics by simply setting the `disabled` property to true.
4 | The `disabled` property accepts also a function, a promise or a function that returns a promise, but it needs to return a boolean.
5 |
6 | Take in mind that when using a promise, the plug-in won't start tracking until it's resolved, because the opt-out needs to happen before trackers or queues are initialized.
7 |
8 | If you are using more then one domain name, all of them will be disabled from tracking.
9 |
10 | **if you need to disable tracking just for development, is better to use the `sendHitTask` property in the `debug` object. Read more [here](/docs/turn-off-development.md)**
11 |
12 | ```js
13 | import Vue from 'vue'
14 | import VueAnalytics from 'vue-analytics'
15 |
16 | // boolean
17 | Vue.use(VueAnalytics, {
18 | id: 'UA-XXX-X',
19 | disabled: true
20 | })
21 |
22 | // function
23 | Vue.use(VueAnalytics, {
24 | id: 'UA-XXX-X',
25 | disabled: () => {
26 | return true
27 | }
28 | })
29 |
30 | // promise
31 | Vue.use(VueAnalytics, {
32 | id: 'UA-XXX-X',
33 | disabled: Promise.resolve(true)
34 | })
35 |
36 | // function that returns a promise
37 | Vue.use(VueAnalytics, {
38 | id: 'UA-XXX-X',
39 | disabled: () => {
40 | return Promise.resolve(true)
41 | }
42 | })
43 | ```
44 |
45 | It is also possible to disable tracking from everywhere at any time using the `disable` method.
46 |
47 | ```js
48 | export default {
49 | methods: {
50 | disableTracking () {
51 | this.$ga.disable()
52 | // from now on analytics is disabled
53 | },
54 | enableTracking () {
55 | this.$ga.enable()
56 | // from now on analytics is enabled
57 | }
58 | }
59 | }
60 | ```
61 | or
62 |
63 | ```js
64 | Vue.$ga.disable()
65 | Vue.$ga.enable()
66 | ```
67 |
--------------------------------------------------------------------------------
/docs/page-tracking.md:
--------------------------------------------------------------------------------
1 | ## Page tracking
2 |
3 | Page tracking is the most important feature of Google Analytics and you can achieve that in different ways
4 |
5 | ### Enable page auto tracking
6 |
7 | The most easy way to track your application, is to pass your VueRouter instance to the plugin and let it handle everything for you
8 |
9 | ```js
10 | import Vue from 'vue'
11 | import VueRouter from 'vue-router'
12 | import VueAnalytics from 'vue-analytics'
13 |
14 | const router = new VueRouter({
15 | router: // your routes
16 | })
17 |
18 | Vue.use(VueAnalytics, {
19 | id: 'UA-XXX-X',
20 | router
21 | })
22 | ```
23 |
24 | ### Manual page tracking
25 |
26 | The standard way is just passing the current page path
27 |
28 | ```js
29 | this.$ga.page('/')
30 | ```
31 |
32 | passing as an object literal
33 |
34 | ```js
35 | this.$ga.page({
36 | page: '/',
37 | title: 'Home page',
38 | location: window.location.href
39 | })
40 | ```
41 |
42 | or you can even pass the VueRouter instance scoped in your component and the plugin will automatically detect the current route name, path and location: just be sure to add the `name` property in your route object
43 |
44 | ```js
45 | this.$ga.page(this.$router)
46 | ```
47 |
48 | Google Analytics docs: [page tracking](https://developers.google.com/analytics/devguides/collection/analyticsjs/pages)
49 |
50 | ### Use screenview with autotracking
51 |
52 | It is also possible to use autotracking and screen tracking by passing true to the `screenview` property in the `autoTracking` object
53 |
54 | ```js
55 | import Vue from 'vue'
56 | import VueAnalytics from 'vue-analytics'
57 |
58 | Vue.use(VueAnalytics, {
59 | id: 'UA-XXX-X',
60 | autoTracking: {
61 | screenview: true
62 | }
63 | })
64 | ```
65 |
66 | ### Disable pageview hit on page load
67 |
68 | Page auto tracking sends a pageview event on page load, but it is possible to disable that
69 |
70 | ```js
71 | import Vue from 'vue'
72 | import VueRouter from 'vue-router'
73 | import VueAnalytics from 'vue-analytics'
74 |
75 | const router = new VueRouter({
76 | router: // your routes
77 | })
78 |
79 | Vue.use(VueAnalytics, {
80 | id: 'UA-XXX-X',
81 | router,
82 | autoTracking: {
83 | pageviewOnLoad: false
84 | }
85 | })
86 | ```
87 |
88 | ### Disable page auto tracking
89 |
90 | To disable auto tracking we can just remove the VueRouter instance, but if you need to track only in specific environment or situations, it is also possible to disable page auto tracking like so
91 |
92 | ```js
93 | Vue.use(VueAnalytics, {
94 | id: 'UA-XXX-X',
95 | router,
96 | autoTracking: {
97 | page: false
98 | }
99 | })
100 | ```
101 |
102 | ### Ignore routes on page auto tracking
103 |
104 | To disable auto tracking for specific routes, you need to pass an array of strings to the plugin options.
105 | The string needs to be the route `name` or the route `path`.
106 |
107 | ```js
108 | Vue.use(VueAnalytics, {
109 | router,
110 | ignoreRoutes: ['home', '/contacts']
111 | })
112 | ```
113 |
114 | ### Auto track with custom data
115 |
116 | When auto-tracking is possible to pass a function with a custom object shape to use as a tracker.
117 |
118 | The `pageViewTemplate` passes the current route as parameter
119 |
120 | ```js
121 | Vue.use(VueAnalytics, {
122 | id: 'UA-XXX-X',
123 | router,
124 | autoTracking: {
125 | pageviewTemplate (route) {
126 | return {
127 | page: route.path,
128 | title: document.title,
129 | location: window.location.href
130 | }
131 | }
132 | }
133 | })
134 | ```
135 |
136 | It is also possible to add custom data structure for each route, using the meta object
137 |
138 | ```js
139 | import Vue from 'vue'
140 | import VueAnalytics from 'vue-analytics'
141 | import VueRouter from 'vue-router'
142 |
143 | const router = new VueRouter({
144 | routes: [
145 | {
146 | name: 'home',
147 | path: '/',
148 | component: {...},
149 | meta: {
150 | analytics: {
151 | pageviewTemplate (route) {
152 | return {
153 | title: 'This is my custom title',
154 | page: route.path,
155 | location: 'www.mydomain.com'
156 | }
157 | }
158 | }
159 | }
160 | }
161 | ]
162 | })
163 |
164 | ```
165 | important: the route pageviewTemplate has always priority over the global one.
166 |
167 | `pageviewTemplate` can return a falsy value to skip tracking, which can be useful for specific needs:
168 |
169 | - `shouldRouterUpdate` documented below is more appropriate for tracking control based on routing, but is not enough when you need to disable initial tracking on some pages, since it only applies to navigation after initial page load.
170 | - `pageviewOnLoad: false` is global and can’t depend on current route.
171 |
172 | ## Avoid transforming route query object into querystring
173 | It is possible to avoid route query to be sent as querystring using the `transformQueryString` property
174 |
175 | ```js
176 | Vue.use(VueAnalytics, {
177 | id: 'UA-XXX-X',
178 | router,
179 | autoTracking: {
180 | transformQueryString: false
181 | }
182 | })
183 | ```
184 |
185 | ## Remove vue-router base option
186 | When a base path is added to the VueRouter instance, the path is merged to the actual router path during the automatic tracking: however it is still possible to remove this behaviour modifying the `prependBase` property in the configuration object
187 |
188 | ```js
189 | Vue.use(VueAnalytics, {
190 | id: 'UA-XXX-X',
191 | router,
192 | autoTracking: {
193 | prependBase: false
194 | }
195 | })
196 | ```
197 |
198 | ## Customize router updates
199 | On every route change, the plugin will track the new route: when we change hashes, query strings or other parameters.
200 |
201 | To avoid router to update and start tracking when a route has the same path of the previous one, it is possible to use the `skipSamePath` property in the `autoTracking` object
202 |
203 | ```js
204 | Vue.use(VueAnalytics, {
205 | id: 'UA-XXX-X',
206 | router,
207 | autoTracking: {
208 | skipSamePath: true
209 | }
210 | })
211 | ```
212 |
213 | For other use cases it is also possible to use the `shouldRouterUpdate`, accessible in the plugin configuration object, inside the `autoTracking` property.
214 | The methods has the previous and current route as parameters and it needs to return a truthy or falsy value.
215 |
216 | ```js
217 | Vue.use(VueAnalytics, {
218 | id: 'UA-XXX-X',
219 | router,
220 | autoTracking: {
221 | shouldRouterUpdate (to, from) {
222 | // Here I'm allowing tracking only when
223 | // next route path is not the same as the previous
224 | return to.path !== from.path
225 | }
226 | }
227 | })
228 | ```
229 |
--------------------------------------------------------------------------------
/docs/require.md:
--------------------------------------------------------------------------------
1 | ## Require
2 |
3 | It's possible to use this method to require an Analytics plugin or add your own plugin
4 |
5 | example adding [Google Optimize](https://optimize.google.com/optimize/home/#/accounts)
6 |
7 | ```js
8 | this.$ga.require('GMT-XXXXXXX')
9 | ```
10 |
11 | or adding a custom plugin
12 |
13 | ```js
14 | const options = {}
15 | this.$ga.require('pluginName', options)
16 | ```
17 |
18 | Google Analytics docs: [require](https://developers.google.com/analytics/devguides/collection/analyticsjs/command-queue-reference#require)
19 |
20 |
--------------------------------------------------------------------------------
/docs/screen-tracking.md:
--------------------------------------------------------------------------------
1 | ## Screen tracking
2 |
3 | Screen hits can be sent using the `screenview` method.
4 |
5 | By passing a string it will track the page by sending a screenview event with the string as screenName property.
6 |
7 | ```js
8 | export default {
9 | name: 'MyComponent',
10 |
11 | methods: {
12 | track () {
13 | this.$ga.screenview('home')
14 | }
15 | }
16 | }
17 | ```
18 |
19 | it is also possible to pass an object literal to fully customize the event
20 |
21 | ```js
22 | export default {
23 | name: 'MyComponent',
24 |
25 | methods: {
26 | track () {
27 | this.$ga.screenview({
28 | screenName: 'home',
29 | ... // other properties
30 | })
31 | }
32 | }
33 | }
34 | ```
35 |
36 | ## Screen autotracking
37 |
38 | It is also possible to use autotracking and screen tracking by passing true to the `screeview` property in the `autoTracking` object
39 |
40 | ```js
41 | import Vue from 'vue'
42 | import VueAnalytics from 'vue-analytics'
43 |
44 | Vue.use(VueAnalytics, {
45 | id: 'UA-XXX-X',
46 | autoTracking: {
47 | screenview: true
48 | }
49 | })
50 | ```
51 |
52 | **Route name property is mandatory**
--------------------------------------------------------------------------------
/docs/script-loader.md:
--------------------------------------------------------------------------------
1 | ## How to load Google Analytics script
2 |
3 | **By default nothing is needed: the plugin does everything for you!**
4 |
5 | However, in some cases, you might want to avoid auto-loading the analytics.js script because:
6 | - maybe the framework you're using already does it for you
7 | - you really can't remove it from your project
8 | - other issue that I can't come up with
9 |
10 | So for all those cases it is possible to let the plugin detect if an analytics script has been added already in your html
11 |
12 | ```js
13 | import Vue from 'vue'
14 | import VueAnalytics from 'vue-analytics'
15 |
16 | Vue.use(VueAnalytics, {
17 | id: 'UA-XXX-X',
18 | checkDuplicatedScript: true
19 | })
20 | ```
21 |
22 | or just disable the script loader
23 |
24 | ```js
25 | import Vue from 'vue'
26 | import VueAnalytics from 'vue-analytics'
27 |
28 | Vue.use(VueAnalytics, {
29 | id: 'UA-XXX-X',
30 | disableScriptLoader: true
31 | })
32 | ```
33 |
34 | ### Important
35 | It is not possible for the plugin to remove the initial trackers, because it needs them to create all methods for the multi-tracking feature.
36 | **If you can't remove initial trackers, don't use this plugin: the outcome could be unpredictable.**
37 |
--------------------------------------------------------------------------------
/docs/set.md:
--------------------------------------------------------------------------------
1 | ## Set
2 |
3 | Sets a single field and value pair or a group of field/value pairs on a tracker object.
4 |
5 | ```js
6 | this.$ga.set(fieldName, fieldValue)
7 | ```
8 |
9 | also possible to pass an object literal
10 |
11 | ```js
12 | this.$ga.set({ fieldName: fieldValue })
13 | ```
14 |
15 | ### Set multiple fields before first hit
16 | Adding the `set` property to the configuration object, we can set multiple fields automatically before the first hit
17 |
18 | ```js
19 | import Vue from 'vue'
20 | import VueAnalytics from 'vue-analytics'
21 |
22 | Vue.use(VueAnalytics, {
23 | id: 'UA-XXX-X',
24 | set: [
25 | { field: 'fieldname', value: 'fieldvalue' }
26 | ]
27 | })
28 | ```
29 |
--------------------------------------------------------------------------------
/docs/social-interactions.md:
--------------------------------------------------------------------------------
1 | ## Social interactions
2 |
3 | You can use social interaction analytics to measure the number of times users click on social buttons embedded in webpages. For example, you might measure a Facebook "Like" or a Twitter "Tweet".
4 |
5 | is possible to impletement this feature passing parameters in this exact order
6 |
7 | ```js
8 | this.$ga.social('Facebook', 'like', 'http://myownpersonaldomain.com')
9 | ```
10 |
11 | also possible to pass an object literal
12 |
13 | ```js
14 | this.$ga.social({
15 | socialNetwork: 'Facebook',
16 | socialAction: 'like',
17 | socialTarget: 'http://myownpersonaldomain.com'
18 | })
19 | ```
20 |
21 | Google Analytics docs: [social interactions](https://developers.google.com/analytics/devguides/collection/analyticsjs/social-interactions)
22 |
23 |
--------------------------------------------------------------------------------
/docs/turn-off-development.md:
--------------------------------------------------------------------------------
1 | ## Turn off during development
2 |
3 | Stop sending hit to your domain during development
4 |
5 | Example:
6 |
7 | ```js
8 | Vue.use(VueAnalytics, {
9 | id: 'UA-XXX-X',
10 | debug: {
11 | sendHitTask: false
12 | }
13 | })
14 | ```
15 |
16 | or assign directly your NODE_ENV variable to enable/disable it automatically
17 |
18 | ```js
19 | Vue.use(VueAnalytics, {
20 | id: 'UA-XXX-X',
21 | debug: {
22 | sendHitTask: process.env.NODE_ENV === 'production'
23 | }
24 | })
25 | ```
26 |
27 | Google Analytics docs: [debugging](https://developers.google.com/analytics/devguides/collection/analyticsjs/debugging)
28 |
--------------------------------------------------------------------------------
/docs/untracked-hits.md:
--------------------------------------------------------------------------------
1 | ## Untracked hits
2 |
3 | Due to different types of connections, loading Google Analytics script and having the application up and running at the same time can be difficult and leading to untracked hits.
4 |
5 | VueAnalytics takes care of this eventuality by storing all untracked events and track them later on, but if for some reasons you don't like that, is possible to turn this feature off
6 |
7 | ```js
8 | import Vue from 'vue'
9 | import VueAnalytics from 'vue-analytics'
10 |
11 | Vue.use(VueAnalytics, {
12 | id: 'UA-XXX-X',
13 | autotracking: {
14 | untracked: false
15 | }
16 | })
17 | ```
--------------------------------------------------------------------------------
/docs/user-timings.md:
--------------------------------------------------------------------------------
1 | ## User timings
2 |
3 | User timing measurement can be achieved in different ways, following Google specifications
4 |
5 | passing parameters in this exact order
6 |
7 | ```js
8 | this.$ga.time('category', 'variable', 123, 'label')
9 | ```
10 |
11 | or use an object literal
12 |
13 | ```js
14 | this.$ga.time({
15 | timingCategory: 'category',
16 | timingVar: 'variable',
17 | timingValue: 123,
18 | timingLabel: 'label'
19 | })
20 | ```
21 |
22 | Google Analytics docs: [user timings](https://developers.google.com/analytics/devguides/collection/analyticsjs/user-timings)
23 |
24 | ##
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/docs/v-ga.md:
--------------------------------------------------------------------------------
1 | ## v-ga
2 |
3 | This directive allows us to centralize all track events in one object and share it across the entire application without needs to add extra logic to our component methods
4 |
5 | Taking as an example a button that only has to log a name in the console
6 |
7 | ```html
8 |
9 |
10 |
11 |
12 |
27 | ```
28 |
29 | To start tracking the value of `name` we can start by adding a method in the commands object that handles this action
30 |
31 | ```js
32 | import Vue from 'vue'
33 | import VueAnalytics from 'vue-analytics'
34 |
35 | Vue.use(VueAnalytics, {
36 | id: 'UA-XXX-X',
37 | commands: {
38 | trackName (name = 'unknown') {
39 | this.$ga.event('randomClicks', 'click', 'name', name)
40 | }
41 | }
42 | })
43 | ```
44 | Lets take in mind that every function we write in the `commands` object is also bound to the current component scope, so that we have access to the Vue instance prototype object and eventually to methods, data and computed values of the component itself. __(I do not recommend to use any component specific properties to avoid the method to be coupled to a specific component structure)__
45 |
46 | Then we only need to add the `v-ga` directive to your element and access the method from the `commands` list that now is shared in the `$ga` object
47 |
48 | ```html
49 |
50 |
55 |
56 |
57 |
72 | ```
73 |
74 | By default, the directive is executed when the element is clicked. However, if you want to change the event type for the logging, you can add the proper event as a modifier.
75 |
76 | ```html
77 |
78 |
81 |
82 |
83 |
98 | ```
99 |
100 | If there's no need to pass any arguments, we could also just pass the name of the method as a string, and the plugin will look it up for us
101 |
102 | ```html
103 |
104 |
105 |
106 |
107 |
112 | ```
113 |
114 | ### v-ga in v-for loops
115 | 'this' is not available on child elements in a v-for loop. To get the current component scope, use '$parent'.
116 |
117 | ```html
118 |
119 |