@ampless/plugin-analytics-ga4 0.2.0-alpha.1 → 0.2.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +43 -0
- package/README.md +43 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +68 -1
- package/package.json +18 -3
package/README.ja.md
CHANGED
|
@@ -40,6 +40,49 @@ export default defineConfig({
|
|
|
40
40
|
|---|---|---|
|
|
41
41
|
| `measurementId` | 必須 | GA4 の計測 ID。例: `G-XXXXXXXX`。空文字 `''` を渡すとプラグインを残したまま注入だけ無効化できる。 |
|
|
42
42
|
| `instanceId` | `'analytics-ga4'` | 生成される `<script>` 要素 id の namespace。同じサイトに複数の GA4 プロパティを入れる場合に分ける。 |
|
|
43
|
+
| `consentCategory` | `''` | オプションの同意カテゴリ slug。設定すると `window.amplessConsent.has(<この値>)` が true になるまで GA4 loader を発火しない。詳細は[同意ゲーティング](#同意ゲーティング)を参照。 |
|
|
44
|
+
|
|
45
|
+
## 同意ゲーティング
|
|
46
|
+
|
|
47
|
+
デフォルトでは GA4 loader は訪問者の同意有無にかかわらずページロードごとに発火します。訪問者が同意を付与するまで発火を遅延させるには、`consentCategory` に同意カテゴリ slug を設定し、同じ `cms.config.ts` に `@ampless/plugin-cookie-consent` を登録します:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { defineConfig } from 'ampless'
|
|
51
|
+
import cookieConsent from '@ampless/plugin-cookie-consent'
|
|
52
|
+
import analyticsGa4Plugin from '@ampless/plugin-analytics-ga4'
|
|
53
|
+
|
|
54
|
+
export default defineConfig({
|
|
55
|
+
plugins: [
|
|
56
|
+
// cookie-consent は analytics plugin より前に置く
|
|
57
|
+
cookieConsent({
|
|
58
|
+
categories: [{ id: 'analytics', label: 'アナリティクス', defaultEnabled: false }],
|
|
59
|
+
}),
|
|
60
|
+
analyticsGa4Plugin({
|
|
61
|
+
measurementId: 'G-XXXXXXXX',
|
|
62
|
+
consentCategory: 'analytics',
|
|
63
|
+
}),
|
|
64
|
+
],
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`consentCategory` を設定すると plugin は **gated mode** に切り替わります: 標準 GA4 の 2 descriptor の代わりに単一のインライン script を emit し、以下の動作をします:
|
|
69
|
+
|
|
70
|
+
1. 直ちに `window.amplessConsent.has('analytics')` を確認(前回の訪問で同意が付与されて `localStorage` から復元されているケースに対応)。
|
|
71
|
+
2. false なら `window.amplessConsent.on('analytics', ...)` で同意イベントを購読して待機。
|
|
72
|
+
3. analytics plugin が cookie-consent plugin の API install より先にロードされたケースに備え、`ampless:consent-ready` イベントも購読。
|
|
73
|
+
|
|
74
|
+
**Fail-closed 契約:** `consentCategory` を設定したまま `@ampless/plugin-cookie-consent` を登録しなかった場合、`window.amplessConsent` は install されません。GA4 は**永久に発火しない**まま 5 秒後に `console.warn` が出力されます:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
[ampless:analytics-ga4] consentCategory is set but window.amplessConsent never installed.
|
|
78
|
+
Did you forget to register @ampless/plugin-cookie-consent?
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
この warning は本番環境でも発火します。設定ミスを早期に検出するためのものであり、抑制する仕組みはありません。
|
|
82
|
+
|
|
83
|
+
**プラグインの順序:** `plugins` 配列内で `@ampless/plugin-cookie-consent` を analytics plugin より前に置いてください。runtime はプラグインを順番に処理するため、cookie-consent を先に置くことで analytics の gating ロジック実行時に `window.amplessConsent` が確実に install されます。
|
|
84
|
+
|
|
85
|
+
Consent Convention および `window.amplessConsent` API の詳細は [docs/architecture/08-plugin-architecture.md](https://github.com/heavymoons/ampless/blob/main/docs/architecture/08-plugin-architecture.md) を参照してください。
|
|
43
86
|
|
|
44
87
|
## measurement ID の取得
|
|
45
88
|
|
package/README.md
CHANGED
|
@@ -40,6 +40,49 @@ export default defineConfig({
|
|
|
40
40
|
|---|---|---|
|
|
41
41
|
| `measurementId` | required | Your GA4 measurement ID, e.g. `G-XXXXXXXX`. Set to `''` to disable the plugin without removing it from `cms.config.ts`. |
|
|
42
42
|
| `instanceId` | `'analytics-ga4'` | Namespace used for the script element ids. Set distinct values when registering multiple GA4 properties on the same site. |
|
|
43
|
+
| `consentCategory` | `''` | Optional consent category slug. When set, the GA4 loader fires only after `window.amplessConsent.has(<this>)` returns true. See [Consent gating](#consent-gating) below. |
|
|
44
|
+
|
|
45
|
+
## Consent gating
|
|
46
|
+
|
|
47
|
+
By default the GA4 loader fires on every page load regardless of visitor consent. To make it fire only after the visitor has granted consent, set `consentCategory` to a category slug and register `@ampless/plugin-cookie-consent` in the same `cms.config.ts`:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { defineConfig } from 'ampless'
|
|
51
|
+
import cookieConsent from '@ampless/plugin-cookie-consent'
|
|
52
|
+
import analyticsGa4Plugin from '@ampless/plugin-analytics-ga4'
|
|
53
|
+
|
|
54
|
+
export default defineConfig({
|
|
55
|
+
plugins: [
|
|
56
|
+
// cookie-consent must appear before the analytics plugin
|
|
57
|
+
cookieConsent({
|
|
58
|
+
categories: [{ id: 'analytics', label: 'Analytics', defaultEnabled: false }],
|
|
59
|
+
}),
|
|
60
|
+
analyticsGa4Plugin({
|
|
61
|
+
measurementId: 'G-XXXXXXXX',
|
|
62
|
+
consentCategory: 'analytics',
|
|
63
|
+
}),
|
|
64
|
+
],
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
When `consentCategory` is set the plugin switches to **gated mode**: instead of the two standard GA4 descriptors, it emits a single inline script that:
|
|
69
|
+
|
|
70
|
+
1. Checks `window.amplessConsent.has('analytics')` immediately (covers the case where consent was granted in a previous visit and restored from `localStorage`).
|
|
71
|
+
2. Otherwise subscribes to the consent event via `window.amplessConsent.on('analytics', ...)` and waits.
|
|
72
|
+
3. Also listens for `ampless:consent-ready` in case the analytics plugin loads before the cookie-consent plugin has installed its global API.
|
|
73
|
+
|
|
74
|
+
**Fail-closed contract:** if `consentCategory` is set but `@ampless/plugin-cookie-consent` is never registered, `window.amplessConsent` is never installed. GA4 will **never fire**, and after 5 seconds a `console.warn` appears:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
[ampless:analytics-ga4] consentCategory is set but window.amplessConsent never installed.
|
|
78
|
+
Did you forget to register @ampless/plugin-cookie-consent?
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
This warning fires in production too — it is intended to help operators catch misconfiguration quickly. There is no mechanism to suppress it.
|
|
82
|
+
|
|
83
|
+
**Plugin ordering:** register `@ampless/plugin-cookie-consent` before the analytics plugin in the `plugins` array. The runtime processes plugins in order; placing cookie-consent first ensures `window.amplessConsent` is installed before the analytics gating logic runs.
|
|
84
|
+
|
|
85
|
+
For full details on the Consent Convention and the `window.amplessConsent` API see [docs/architecture/08-plugin-architecture.md](https://github.com/heavymoons/ampless/blob/main/docs/architecture/08-plugin-architecture.md).
|
|
43
86
|
|
|
44
87
|
## Getting your measurement ID
|
|
45
88
|
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,13 @@ interface AnalyticsGa4Options {
|
|
|
22
22
|
* site).
|
|
23
23
|
*/
|
|
24
24
|
instanceId?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Optional consent category. When set, the analytics loader does
|
|
27
|
+
* not run until window.amplessConsent.has(consentCategory) returns
|
|
28
|
+
* true. See @ampless/plugin-cookie-consent and the Consent
|
|
29
|
+
* Convention in docs/architecture/08-plugin-architecture.md.
|
|
30
|
+
*/
|
|
31
|
+
consentCategory?: string;
|
|
25
32
|
}
|
|
26
33
|
/**
|
|
27
34
|
* Factory for the GA4 plugin. Returns a plugin manifest that emits
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { definePlugin } from "ampless";
|
|
3
3
|
function analyticsGa4Plugin(options = {}) {
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
measurementId = "",
|
|
6
|
+
instanceId = "analytics-ga4",
|
|
7
|
+
consentCategory = ""
|
|
8
|
+
} = options;
|
|
5
9
|
return definePlugin({
|
|
6
10
|
name: "analytics-ga4",
|
|
11
|
+
packageName: "@ampless/plugin-analytics-ga4",
|
|
7
12
|
instanceId,
|
|
8
13
|
displayName: { en: "Google Analytics 4", ja: "Google Analytics 4" },
|
|
9
14
|
apiVersion: 1,
|
|
@@ -29,12 +34,74 @@ function analyticsGa4Plugin(options = {}) {
|
|
|
29
34
|
pattern: "^$|^G-[A-Z0-9]+$",
|
|
30
35
|
placeholder: "G-XXXXXXXX",
|
|
31
36
|
default: measurementId
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
key: "consentCategory",
|
|
41
|
+
label: { en: "Consent category", ja: "\u540C\u610F\u30AB\u30C6\u30B4\u30EA" },
|
|
42
|
+
description: {
|
|
43
|
+
en: "Optional. When set, the analytics loader fires only after `window.amplessConsent.has(<this>)` returns true. Requires `@ampless/plugin-cookie-consent` to also be registered \u2014 fail-closed otherwise (no tracking, console warning after 5s). See the Consent Convention in the plugin author guide.",
|
|
44
|
+
ja: "\u30AA\u30D7\u30B7\u30E7\u30F3\u3002\u8A2D\u5B9A\u3059\u308B\u3068 `window.amplessConsent.has(<value>)` \u304C true \u306B\u306A\u308B\u307E\u3067 analytics loader \u3092\u767A\u706B\u3057\u307E\u305B\u3093\u3002`@ampless/plugin-cookie-consent` \u306E\u4F75\u7528\u304C\u5FC5\u9808 \u2014 \u672A\u5C0E\u5165\u6642\u306F\u5B8C\u5168\u306B\u767A\u706B\u305B\u305A 5 \u79D2\u5F8C\u306B console warning (fail-closed)\u3002\u8A73\u7D30\u306F plugin author guide \u306E Consent Convention \u7BC0\u3092\u53C2\u7167\u3002"
|
|
45
|
+
},
|
|
46
|
+
pattern: "^$|^[a-z][a-z0-9_-]*$",
|
|
47
|
+
maxLength: 32,
|
|
48
|
+
placeholder: "analytics",
|
|
49
|
+
default: consentCategory
|
|
32
50
|
}
|
|
33
51
|
]
|
|
34
52
|
},
|
|
35
53
|
publicHead(ctx) {
|
|
36
54
|
const id = (ctx.setting("measurementId") ?? "").trim();
|
|
37
55
|
if (!id) return [];
|
|
56
|
+
const category = (ctx.setting("consentCategory") ?? "").trim();
|
|
57
|
+
if (category) {
|
|
58
|
+
const loaderSrc = `https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(id)}`;
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
type: "inlineScript",
|
|
62
|
+
id: `ga4-gated-${instanceId}`,
|
|
63
|
+
strategy: "afterInteractive",
|
|
64
|
+
body: [
|
|
65
|
+
"(function () {",
|
|
66
|
+
" var initialized = false",
|
|
67
|
+
" function init() {",
|
|
68
|
+
" if (initialized) return",
|
|
69
|
+
" initialized = true",
|
|
70
|
+
" var s = document.createElement('script')",
|
|
71
|
+
` s.src = ${JSON.stringify(loaderSrc)}`,
|
|
72
|
+
" s.async = true",
|
|
73
|
+
" document.head.appendChild(s)",
|
|
74
|
+
" // Bind dataLayer + gtag to `window` so later page code",
|
|
75
|
+
" // (e.g. window.gtag('event', ...) in custom handlers)",
|
|
76
|
+
" // can find them. The non-gated snippet relies on a",
|
|
77
|
+
" // top-level `function gtag(){}` hoisting to global,",
|
|
78
|
+
" // which inside this IIFE would only be a local \u2014 so",
|
|
79
|
+
" // we assign explicitly and preserve any gtag that a",
|
|
80
|
+
" // user script may have installed first.",
|
|
81
|
+
" window.dataLayer = window.dataLayer || []",
|
|
82
|
+
" window.gtag = window.gtag || function () { window.dataLayer.push(arguments) }",
|
|
83
|
+
" window.gtag('js', new Date())",
|
|
84
|
+
` window.gtag('config', ${JSON.stringify(id)})`,
|
|
85
|
+
" }",
|
|
86
|
+
" function wait() {",
|
|
87
|
+
` if (window.amplessConsent.has(${JSON.stringify(category)})) init()`,
|
|
88
|
+
` else window.amplessConsent.on(${JSON.stringify(category)}, init)`,
|
|
89
|
+
" }",
|
|
90
|
+
" if (window.amplessConsent) {",
|
|
91
|
+
" wait()",
|
|
92
|
+
" } else {",
|
|
93
|
+
" window.addEventListener('ampless:consent-ready', wait, { once: true })",
|
|
94
|
+
" setTimeout(function () {",
|
|
95
|
+
" if (!window.amplessConsent) {",
|
|
96
|
+
" console.warn('[ampless:analytics-ga4] consentCategory is set but window.amplessConsent never installed. Did you forget to register @ampless/plugin-cookie-consent?')",
|
|
97
|
+
" }",
|
|
98
|
+
" }, 5000)",
|
|
99
|
+
" }",
|
|
100
|
+
"})()"
|
|
101
|
+
].join("\n")
|
|
102
|
+
}
|
|
103
|
+
];
|
|
104
|
+
}
|
|
38
105
|
return [
|
|
39
106
|
{
|
|
40
107
|
type: "script",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ampless/plugin-analytics-ga4",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.10",
|
|
4
4
|
"description": "Google Analytics 4 plugin for ampless",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
".": {
|
|
9
9
|
"import": "./dist/index.js",
|
|
10
10
|
"types": "./dist/index.d.ts"
|
|
11
|
-
}
|
|
11
|
+
},
|
|
12
|
+
"./package.json": "./package.json"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
|
14
15
|
"dist",
|
|
@@ -25,15 +26,29 @@
|
|
|
25
26
|
"homepage": "https://github.com/heavymoons/ampless/tree/main/packages/plugin-analytics-ga4#readme",
|
|
26
27
|
"bugs": "https://github.com/heavymoons/ampless/issues",
|
|
27
28
|
"dependencies": {
|
|
28
|
-
"ampless": "1.0.0-alpha.
|
|
29
|
+
"ampless": "1.0.0-alpha.26"
|
|
29
30
|
},
|
|
30
31
|
"keywords": [
|
|
31
32
|
"ampless",
|
|
32
33
|
"plugin",
|
|
34
|
+
"ampless-plugin",
|
|
33
35
|
"analytics",
|
|
34
36
|
"ga4",
|
|
35
37
|
"google-analytics"
|
|
36
38
|
],
|
|
39
|
+
"amplessPlugin": {
|
|
40
|
+
"apiVersion": 1,
|
|
41
|
+
"name": "analytics-ga4",
|
|
42
|
+
"trustLevel": "untrusted",
|
|
43
|
+
"capabilities": [
|
|
44
|
+
"publicHead",
|
|
45
|
+
"adminSettings"
|
|
46
|
+
],
|
|
47
|
+
"displayName": {
|
|
48
|
+
"en": "Google Analytics 4",
|
|
49
|
+
"ja": "Google Analytics 4"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
37
52
|
"scripts": {
|
|
38
53
|
"build": "tsup",
|
|
39
54
|
"dev": "tsup --watch",
|