diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..7830f40 --- /dev/null +++ b/.npmignore @@ -0,0 +1,28 @@ +/sample +.editorconfig +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/README.md b/README.md index 4dad51e..8473db2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@ -![full_logo_color_light_transparent](https://user-images.githubusercontent.com/4896588/224442362-45dd92e7-e118-46ac-a423-83d479a9654b.png) - - # Wide Angle Analytics for Vue.js +[![License][license-src]][license-href] +[![Latest][npm-version-src]][npm-version-href] +[![Downloads][npm-downloads-src]][npm-downloads-href] +[![Wide Angle][wideangle-src]][wideangle-href] + +![wide-angle-analytics-logo.png](assets/full_logo_color_light_transparent.png) + Enable **privacy-friendly** web analytics in your Vue.js 3.x application with our official plugin. [Wide Angle Analytics](https://wideangle.co) is powerful, strictly-GDPR compliant Google Analytics alternative. @@ -36,10 +40,11 @@ option|description|required|default|example siteId| The Site ID from Wide Angle Site settings| :white_check_mark: | _none_ | 8D27G3B9ACA01F4241 domain| Domain hosting the script, can be found in Wide Angle Analytics Site settings | :white_check_mark: | _none_ | stats.wideangle.co fingerprint | Should script use browser fingerprinting; this might require collecting consent depeing on the applicable laws | :x: | false | true -supressDnt | Should script ingore Do Not Track browser setting. If not enabled, not events will be sent if user's browser has DNT enabled | :x: | false | true +suppressDnt | Should script ingore Do Not Track browser setting. If not enabled, not events will be sent if user's browser has DNT enabled | :x: | false | true includeParams | An array of query parameters that can be passed as part of tracking event. By default only `utm_*` and `ref` parameters are passed in the event | :x: | `[]` | `['sessionId', 'offset']` excludePaths | An array of URL paths that should not trigger default events such as page view, page leave | :x: | `[]` | `['^/wp-admin/.*', ]` ignoreHash | If enabled, change in the URL fragment will not trigger page view event | :x: | false | true +consentMarker | Cookie (with or without) value which present implies consent and absence lack its lack | :x: | n/a | `WAA_CONSENT=true` You will find more details about these settings in [Wide Angle Analytics documentation](https://wideangle.co/documentation/configure-site). @@ -55,7 +60,7 @@ app.use(WideAngle, { siteId: "8D27G3B9ACA01F4241", domain: "stats.example.com", fingerprint: true, - supressDnt: true + suppressDnt: true }); ``` @@ -89,18 +94,12 @@ Site has to have these event enable in Wide Angle Analytics configuration prior Currently **Click Events** are [emitted automatically](https://wideangle.co/documentation/tracking-click-events) based on element data attributes. -| :warning: The tracker script does not listen to events inside shadow DOM. This is known limitation to be addressed in near term. | -|--------------------------------------------------------------------------------------------------------------------------------------------| - ### Tracking Downloads Depending on the configured mode, the **Download Event** will fire automatically when either: * a file with recognized extension is being downloaded, or * when a link is marked with `data-waa-name` attribute. -| :warning: Currently the tracker script does not listen to events inside shadow DOM. This is known limitation to be addressed in near term. | -|--------------------------------------------------------------------------------------------------------------------------------------------| - ### Tracking Custom Actions Custom action are the most flexible and can be triggered directly from Vue components. As such their usage is not limitted due to Shadow DOM. @@ -120,7 +119,78 @@ const sendEvent = async () => { session: 'cjhw92nf9aq', cohort: 'c1233' } - waa.dispatchEvent('interest', params); + waa.value.dispatchEvent('interest', params); } ``` + +# Consent Handling + +By default, Wide Angle Analytics does nore require consent thanks to its privacy-first, anonymous tracking and principaled approached to compliance. + +However, you have additional toggles should you wish to control consent, either in **Opt-In** or **Opt-Out** mode. + +## Opt-Out by default + +If the visitors browsers has `DoNotTrack` setting enabled in the browser, it will be understood as opt-out and not tracking events will be issued. + +You website can't overwrite this behaviour by specifying `suppressDnt` setting. + +```javascript +app.use(WideAngle, { + siteId: "8D27G3B9ACA01F4241", + suppressDnt: true +}); +``` + +## Opt-In or Opt-Out based on Cookie + +Wide Angle can be configure to handle presence of a cookie, or a cookie with specific value, as an implicit consent. Lack of the cookie will be handled as implicit opt-out. + +Example configuration with cookie marker, expecting cookie name `WAA_CONSENT` with value `true`: + +```javascript +app.use(WideAngle, { + siteId: "8D27G3B9ACA01F4241", + consentMarker: "WAA_CONSENT=true" +}); +``` + + +## Programmatic consent + +The Wide Angle serving offers two additional methods, which allow for recording tracking consent: + +- `recordConsent(subjectId: String): void`, and +- `revokeConsent()` + + +Calling above methods on `waa` service will overwrite other consent mechanism (ie. DoNotTrack, and cookie marker). + +Example usage: + +```vue + +``` + + + + +[license-src]: https://img.shields.io/npm/l/wideangle-vuejs.svg?style=flat&colorA=18181B&colorB=28CF8D +[license-href]: https://opensource.org/license/apache-2-0/ + +[npm-downloads-src]: https://img.shields.io/npm/dm/wideangle-vuejs.svg?style=flat&colorA=18181B&colorB=28CF8DD +[npm-downloads-href]: https://npmjs.com/package/wideangle-vuejs + +[npm-version-src]: https://img.shields.io/npm/v/wideangle-vuejs/latest.svg?style=flat&colorA=18181B&colorB=28CF8DD +[npm-version-href]: https://npmjs.com/package/wideangle-vuejs + +[wideangle-src]: https://img.shields.io/badge/logo-wideangle-blue?label=&logo=data:image/png;base64,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 +[wideangle-href]: https://wideangle.co?utm_source=github&utm_content=wideangle-vuejs + + + diff --git a/assets/full_logo_color_light_transparent.png b/assets/full_logo_color_light_transparent.png new file mode 100755 index 0000000..6f98b15 Binary files /dev/null and b/assets/full_logo_color_light_transparent.png differ diff --git a/index.js b/index.js index 9136f09..1d0b8d4 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,16 @@ -import { initWideAngle } from "./src"; +import { initWideAngle } from "./dist"; +import { ref } from 'vue'; +export { initWideAngle } from "./dist"; export default { install: (app, options) => { + const waaRef = ref() + app.provide('waa', waaRef); initWideAngle(options) - .then(waa => { app.provide('waa', waa); }) - .catch(e => { console.error("Failed to load Wide Angle Plugin", e)}); + .then(waa => { + waaRef.value = waa; + console.debug("[WAA] Wide Angle Analytics instance available"); + }).catch(e => { console.error("[WAA] Failed to load Wide Angle Plugin", e)}); + return waaRef; } } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..d422b80 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,37 @@ +{ + "name": "wideangle-vuejs", + "version": "0.0.3", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "wideangle-vuejs", + "version": "0.0.3", + "license": "Apache-2.0", + "devDependencies": { + "typescript": "^5.0.4" + } + }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + } + }, + "dependencies": { + "typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true + } + } +} diff --git a/package.json b/package.json index 420482e..16d27b5 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,18 @@ { "name": "wideangle-vuejs", - "version": "0.0.1", + "version": "2.0.0", "description": "Wide Angle Analytics web analytics Plugin for Vue.js 3.x", "homepage": "https://wideangle.co", - "repository": "github:inputobjects/wideangle-vuejs", + "repository": { + "type": "git", + "url": "https://cloud.inputobjects.eu/forge/wideangle/wideangle-vuejs.git" + }, "main": "index.js", "scripts": { + "build": "tsc -p tsconfig.json", + "clear": "rimraf dist", + "rebuild": "npm run clear && npm run build", + "prepublishOnly": "npm run rebuild" }, "keywords": [ "wide angle analytics", @@ -13,8 +20,13 @@ "vue.js", "vuejs", "plugin", - "vuejs plugin" + "vuejs plugin", + "privacy web analytics", + "privacy" ], "author": "Wide Angle Analytics ", - "license": "Apache-2.0" + "license": "Apache-2.0", + "devDependencies": { + "typescript": "^5.0.4" + } } diff --git a/sample/vue-sample/package-lock.json b/sample/vue-sample/package-lock.json index edcac82..30c61a4 100644 --- a/sample/vue-sample/package-lock.json +++ b/sample/vue-sample/package-lock.json @@ -9,8 +9,7 @@ "version": "0.0.0", "dependencies": { "vue": "^3.2.47", - "vue-router": "^4.1.6", - "wideangle-vue": "file:../../" + "vue-router": "^4.1.6" }, "devDependencies": { "@vitejs/plugin-vue": "^4.0.0", @@ -18,9 +17,12 @@ } }, "../..": { - "name": "wideangle-vuejs", - "version": "0.0.1", - "license": "Apache-2.0" + "version": "2.0.0", + "extraneous": true, + "license": "Apache-2.0", + "devDependencies": { + "typescript": "^5.0.4" + } }, "node_modules/@babel/parser": { "version": "7.21.2", @@ -771,10 +773,6 @@ "peerDependencies": { "vue": "^3.2.0" } - }, - "node_modules/wideangle-vue": { - "resolved": "../..", - "link": true } }, "dependencies": { @@ -1175,9 +1173,6 @@ "requires": { "@vue/devtools-api": "^6.4.5" } - }, - "wideangle-vue": { - "version": "file:../.." } } } diff --git a/sample/vue-sample/package.json b/sample/vue-sample/package.json index cc7d528..2a8f55d 100644 --- a/sample/vue-sample/package.json +++ b/sample/vue-sample/package.json @@ -3,14 +3,13 @@ "version": "0.0.0", "private": true, "scripts": { - "dev": "vite", + "dev": "vite --host 0.0.0.0", "build": "vite build", "preview": "vite preview" }, "dependencies": { "vue": "^3.2.47", - "vue-router": "^4.1.6", - "wideangle-vue": "file:../../" + "vue-router": "^4.1.6" }, "devDependencies": { "@vitejs/plugin-vue": "^4.0.0", diff --git a/sample/vue-sample/src/App.vue b/sample/vue-sample/src/App.vue index 013fed3..9940d3c 100644 --- a/sample/vue-sample/src/App.vue +++ b/sample/vue-sample/src/App.vue @@ -28,5 +28,7 @@ nav { display: flex; flex-direction: column; gap: 2rem; + width: 100%; + align-items: center; } diff --git a/sample/vue-sample/src/assets/main.css b/sample/vue-sample/src/assets/main.css index 02ffe70..4acaa04 100644 --- a/sample/vue-sample/src/assets/main.css +++ b/sample/vue-sample/src/assets/main.css @@ -1,3 +1,13 @@ body { + background-color: azure; + margin: 2rem; font-size: 1.5rem; + font-weight: 800; + font-family: 'Courier New', Courier, monospace; +} + +button { + border-width: 4px; + border-style: solid; + border-color: lightpink; } diff --git a/sample/vue-sample/src/components/EmbeddedButton.vue b/sample/vue-sample/src/components/EmbeddedButton.vue new file mode 100644 index 0000000..b5df187 --- /dev/null +++ b/sample/vue-sample/src/components/EmbeddedButton.vue @@ -0,0 +1,19 @@ + + + + diff --git a/sample/vue-sample/src/main.js b/sample/vue-sample/src/main.js index 04c128c..d9e8e45 100644 --- a/sample/vue-sample/src/main.js +++ b/sample/vue-sample/src/main.js @@ -1,7 +1,7 @@ import { createApp } from 'vue' import App from './App.vue' import router from './router' -import WideAngle from 'wideangle-vue' +import WideAngle from 'wideangle-vuejs' import './assets/main.css' @@ -10,8 +10,8 @@ const app = createApp(App) app.use(router) app.use(WideAngle, { siteId: "8D27G3B9ACA01F4241", - domain: "wideangle.local:3000", + domain: "events.wideangle.test", fingerprint: true, - supressDnt: true + suppressDnt: true }) app.mount('#app') diff --git a/sample/vue-sample/src/views/SampleView.vue b/sample/vue-sample/src/views/SampleView.vue index a739891..145bd60 100644 --- a/sample/vue-sample/src/views/SampleView.vue +++ b/sample/vue-sample/src/views/SampleView.vue @@ -1,13 +1,16 @@ @@ -29,6 +32,6 @@ main { display: flex; flex-direction: column; gap: 1rem; - max-width: 300px; + max-width: 600px; } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c8b7297 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "include": ["src/**/*"], + "compilerOptions": { + "target": "es2016", + // "module": "commonjs", + "declaration": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "allowJs": true, + "outDir": "dist", + "skipLibCheck": true + } +}