@ssheleg/sheleg-dev 0.4.0
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/CHANGELOG.md +172 -0
- package/LICENSE +21 -0
- package/README.md +132 -0
- package/SECURITY.md +63 -0
- package/bin/sheleg-dev.js +99 -0
- package/package.json +45 -0
- package/plugins/sheleg-dev/.claude-plugin/plugin.json +28 -0
- package/plugins/sheleg-dev/skills/ad-tracking/SKILL.md +442 -0
- package/plugins/sheleg-dev/skills/ad-tracking/references/consent-mode.md +257 -0
- package/plugins/sheleg-dev/skills/ad-tracking/references/event-tracking.md +201 -0
- package/plugins/sheleg-dev/skills/ad-tracking/references/gtag-api.md +389 -0
- package/plugins/sheleg-dev/skills/ad-tracking/references/meta-linkedin.md +103 -0
- package/plugins/sheleg-dev/skills/ad-tracking/references/performance-security.md +288 -0
- package/plugins/sheleg-dev/skills/crypto-payments/SKILL.md +384 -0
- package/plugins/sheleg-dev/skills/crypto-payments/references/heleket-provider.md +1357 -0
- package/plugins/sheleg-dev/skills/frontend-performance/SKILL.md +147 -0
- package/plugins/sheleg-dev/skills/frontend-performance/references/accessibility-perf.md +172 -0
- package/plugins/sheleg-dev/skills/frontend-performance/references/css-performance.md +180 -0
- package/plugins/sheleg-dev/skills/frontend-performance/references/nextjs.md +271 -0
- package/plugins/sheleg-dev/skills/google-auth/SKILL.md +275 -0
- package/plugins/sheleg-dev/skills/google-auth/references/adc-and-service-accounts.md +464 -0
- package/plugins/sheleg-dev/skills/google-auth/references/oauth2-web-server.md +615 -0
- package/plugins/sheleg-dev/skills/google-auth/references/sign-in-with-google.md +593 -0
- package/plugins/sheleg-dev/skills/google-auth/references/workload-identity.md +376 -0
- package/plugins/sheleg-dev/skills/google-signin/SKILL.md +121 -0
- package/plugins/sheleg-dev/skills/google-signin/references/full-guide.md +421 -0
- package/plugins/sheleg-dev/skills/stripe-billing/SKILL.md +458 -0
- package/plugins/sheleg-dev/skills/stripe-billing/references/price-integrity.md +201 -0
- package/plugins/sheleg-dev/skills/stripe-billing/references/stripe-agent-toolchain.md +173 -0
- package/plugins/sheleg-dev/skills/stripe-billing/references/subscription-lifecycle.md +294 -0
- package/plugins/sheleg-dev/skills/stripe-billing/references/testing-and-local-dev.md +214 -0
- package/plugins/sheleg-dev/skills/stripe-billing/references/webhook-events.md +211 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Consent Mode v2 — Detailed Patterns
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Contents
|
|
5
|
+
|
|
6
|
+
- [Table of Contents](#table-of-contents)
|
|
7
|
+
- [Status check — 2026](#status-check--2026)
|
|
8
|
+
- [Advanced vs Basic Mode](#advanced-vs-basic-mode)
|
|
9
|
+
- [All Consent Types](#all-consent-types)
|
|
10
|
+
- [Region-Specific Defaults](#region-specific-defaults)
|
|
11
|
+
- [Granular Consent](#granular-consent)
|
|
12
|
+
- [Consent Update Flow](#consent-update-flow)
|
|
13
|
+
- [GTM Implementation](#gtm-implementation)
|
|
14
|
+
- [Tag Behavior When Denied](#tag-behavior-when-denied)
|
|
15
|
+
- [URL Passthrough](#url-passthrough)
|
|
16
|
+
- [Ads Data Redaction](#ads-data-redaction)
|
|
17
|
+
- [Verification](#verification)
|
|
18
|
+
|
|
19
|
+
## Table of Contents
|
|
20
|
+
|
|
21
|
+
- [Advanced vs Basic Mode](#advanced-vs-basic-mode)
|
|
22
|
+
- [All Consent Types](#all-consent-types)
|
|
23
|
+
- [Region-Specific Defaults](#region-specific-defaults)
|
|
24
|
+
- [Granular Consent](#granular-consent)
|
|
25
|
+
- [Consent Update Flow](#consent-update-flow)
|
|
26
|
+
- [GTM Implementation](#gtm-implementation)
|
|
27
|
+
- [Tag Behavior When Denied](#tag-behavior-when-denied)
|
|
28
|
+
- [Verification](#verification)
|
|
29
|
+
|
|
30
|
+
## Status check — 2026
|
|
31
|
+
|
|
32
|
+
Consent Mode v2 has been required since **March 2024** for anyone using Google
|
|
33
|
+
advertising products with EEA or UK traffic, and by 2026 Google additionally
|
|
34
|
+
expects a **certified CMP** from the Consent Management Platform programme —
|
|
35
|
+
a hand-rolled banner that sets the signals correctly is no longer sufficient on
|
|
36
|
+
its own for Google's ad products. Verify your CMP's certification status before
|
|
37
|
+
treating this box as ticked. *(Checked 2026-08-06.)*
|
|
38
|
+
|
|
39
|
+
## Advanced vs Basic Mode
|
|
40
|
+
|
|
41
|
+
| Mode | Tags load before consent? | Cookieless pings? | Conversion modeling? |
|
|
42
|
+
|------|--------------------------|-------------------|---------------------|
|
|
43
|
+
| **Basic** | No — tags blocked until consent granted | No | No |
|
|
44
|
+
| **Advanced** | Yes — tags load with denied defaults | Yes | Yes (recovers ~65-70% of lost data) |
|
|
45
|
+
|
|
46
|
+
**Always prefer Advanced mode** — it allows Google to model conversions from users who deny
|
|
47
|
+
consent without storing any cookies or identifying individuals.
|
|
48
|
+
|
|
49
|
+
Advanced mode = `gtag('consent', 'default', { ... 'denied' ... })` then load tags normally.
|
|
50
|
+
Basic mode = physically block `<script>` tags until consent granted.
|
|
51
|
+
|
|
52
|
+
## All Consent Types
|
|
53
|
+
|
|
54
|
+
| Signal | Controls | Required for |
|
|
55
|
+
|--------|----------|-------------|
|
|
56
|
+
| `ad_storage` | Advertising cookies/identifiers (e.g. `_gcl_*`) | Google Ads, remarketing |
|
|
57
|
+
| `ad_user_data` | Sending user data to Google for advertising | Google Ads conversion tracking |
|
|
58
|
+
| `ad_personalization` | Personalized advertising/remarketing | Remarketing audiences |
|
|
59
|
+
| `analytics_storage` | Analytics cookies (e.g. `_ga`, `_ga_*`) | GA4 full measurement |
|
|
60
|
+
| `functionality_storage` | Functional cookies (e.g. language prefs) | Optional |
|
|
61
|
+
| `personalization_storage` | Personalization cookies (e.g. recommendations) | Optional |
|
|
62
|
+
| `security_storage` | Security cookies (e.g. CSRF tokens) | Optional |
|
|
63
|
+
|
|
64
|
+
For GA4 + Google Ads, the four required signals are: `ad_storage`, `ad_user_data`,
|
|
65
|
+
`ad_personalization`, `analytics_storage`.
|
|
66
|
+
|
|
67
|
+
## Region-Specific Defaults
|
|
68
|
+
|
|
69
|
+
Scope consent defaults to specific regions to avoid blocking measurement where not required:
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
// Deny by default in EEA + UK
|
|
73
|
+
gtag('consent', 'default', {
|
|
74
|
+
'ad_storage': 'denied',
|
|
75
|
+
'ad_user_data': 'denied',
|
|
76
|
+
'ad_personalization': 'denied',
|
|
77
|
+
'analytics_storage': 'denied',
|
|
78
|
+
'region': ['AT','BE','BG','HR','CY','CZ','DK','EE','FI','FR',
|
|
79
|
+
'DE','GR','HU','IE','IT','LV','LT','LU','MT','NL',
|
|
80
|
+
'PL','PT','RO','SK','SI','ES','SE','IS','LI','NO','GB'],
|
|
81
|
+
'wait_for_update': 500
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Grant by default everywhere else (no banner needed)
|
|
85
|
+
gtag('consent', 'default', {
|
|
86
|
+
'ad_storage': 'granted',
|
|
87
|
+
'ad_user_data': 'granted',
|
|
88
|
+
'ad_personalization': 'granted',
|
|
89
|
+
'analytics_storage': 'granted'
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The most specific region match wins. If a user is in Germany (`DE`), the first block applies.
|
|
94
|
+
If in the US, the second block applies (no consent banner needed).
|
|
95
|
+
|
|
96
|
+
**When to use region-specific defaults:**
|
|
97
|
+
- Site serves both EEA and non-EEA users
|
|
98
|
+
- Want to avoid showing consent banner to US/non-EU users
|
|
99
|
+
- Need to maximize measurement while staying compliant
|
|
100
|
+
|
|
101
|
+
**When to deny globally:**
|
|
102
|
+
- Simpler implementation
|
|
103
|
+
- Want consistent UX worldwide
|
|
104
|
+
- Targeting primarily EEA/UK audience
|
|
105
|
+
|
|
106
|
+
## Granular Consent
|
|
107
|
+
|
|
108
|
+
For sites that want separate analytics vs advertising consent:
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
// User accepts analytics but declines ads
|
|
112
|
+
gtag('consent', 'update', {
|
|
113
|
+
'ad_storage': 'denied',
|
|
114
|
+
'ad_user_data': 'denied',
|
|
115
|
+
'ad_personalization': 'denied',
|
|
116
|
+
'analytics_storage': 'granted'
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
This requires a more complex consent banner with multiple toggles/categories.
|
|
121
|
+
For most sites, a simple accept-all / decline-all is sufficient.
|
|
122
|
+
|
|
123
|
+
### localStorage Schema for Granular Consent
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
// Simple (binary)
|
|
127
|
+
localStorage.setItem('app_cookie_consent', 'granted'); // or 'denied'
|
|
128
|
+
|
|
129
|
+
// Granular (JSON)
|
|
130
|
+
localStorage.setItem('app_cookie_consent', JSON.stringify({
|
|
131
|
+
analytics: 'granted',
|
|
132
|
+
advertising: 'denied',
|
|
133
|
+
timestamp: Date.now()
|
|
134
|
+
}));
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Consent Update Flow
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
User clicks "Accept All"
|
|
141
|
+
└─> localStorage.setItem('key', 'granted')
|
|
142
|
+
└─> gtag('consent', 'update', {
|
|
143
|
+
'ad_storage': 'granted',
|
|
144
|
+
'ad_user_data': 'granted',
|
|
145
|
+
'ad_personalization': 'granted',
|
|
146
|
+
'analytics_storage': 'granted'
|
|
147
|
+
})
|
|
148
|
+
└─> Hide banner
|
|
149
|
+
|
|
150
|
+
User clicks "Decline"
|
|
151
|
+
└─> localStorage.setItem('key', 'denied')
|
|
152
|
+
└─> gtag('consent', 'update', {
|
|
153
|
+
'ad_storage': 'denied',
|
|
154
|
+
'ad_user_data': 'denied',
|
|
155
|
+
'ad_personalization': 'denied',
|
|
156
|
+
'analytics_storage': 'denied'
|
|
157
|
+
})
|
|
158
|
+
└─> Hide banner
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
After `gtag('consent', 'update', ...)`:
|
|
162
|
+
- If changed to `granted`: GA4 writes cookies and begins full tracking
|
|
163
|
+
- If changed to `denied`: GA4 switches to cookieless pings (advanced mode)
|
|
164
|
+
- Queued events from before the update are processed with the new consent state
|
|
165
|
+
|
|
166
|
+
## GTM Implementation
|
|
167
|
+
|
|
168
|
+
When using Google Tag Manager instead of gtag.js directly:
|
|
169
|
+
|
|
170
|
+
1. Create a **Consent Initialization** trigger (fires before all other triggers)
|
|
171
|
+
2. Add a tag with the default consent state
|
|
172
|
+
3. Use the CMP's built-in GTM template (if available) or custom HTML tag
|
|
173
|
+
4. The CMP updates consent via `gtag('consent', 'update', ...)`
|
|
174
|
+
5. GTM built-in consent checks gate tag firing automatically
|
|
175
|
+
|
|
176
|
+
GTM consent overview is configured in Admin > Container Settings > Enable consent overview.
|
|
177
|
+
|
|
178
|
+
## Tag Behavior When Denied
|
|
179
|
+
|
|
180
|
+
When `analytics_storage` is denied, GA4 in advanced mode:
|
|
181
|
+
- Sends cookieless pings (no `_ga` cookie written)
|
|
182
|
+
- Pings include: page URL, timestamp, user agent, referrer
|
|
183
|
+
- Does NOT include: client ID, session ID, user-scoped dimensions
|
|
184
|
+
- Google uses these pings for **behavioral modeling** to estimate metrics
|
|
185
|
+
|
|
186
|
+
When `ad_storage` is denied:
|
|
187
|
+
- No `_gcl_*` cookies written
|
|
188
|
+
- Conversion linker disabled
|
|
189
|
+
- Google uses **conversion modeling** to estimate conversions
|
|
190
|
+
|
|
191
|
+
## URL Passthrough
|
|
192
|
+
|
|
193
|
+
When `ad_storage` is denied, ad click info (gclid, dclid) can't be stored in cookies.
|
|
194
|
+
URL passthrough appends this data as URL parameters across pages instead:
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
gtag('set', 'url_passthrough', true);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Place this **before** any `config` commands. When enabled, these query params may appear in URLs:
|
|
201
|
+
`gclid`, `dclid`, `gclsrc`, `_gl`, `wbraid`.
|
|
202
|
+
|
|
203
|
+
**When to use:** Running Google Ads with users who may deny consent. Not needed for analytics-only setups.
|
|
204
|
+
|
|
205
|
+
Ensure:
|
|
206
|
+
1. Redirects on your site pass all query parameters through
|
|
207
|
+
2. Analytics tools ignore these parameters in page URLs
|
|
208
|
+
3. Parameters don't interfere with site behavior
|
|
209
|
+
|
|
210
|
+
## Ads Data Redaction
|
|
211
|
+
|
|
212
|
+
Further redact ad data when `ad_storage` is denied:
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
gtag('set', 'ads_data_redaction', true);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
When enabled and `ad_storage` is `denied`:
|
|
219
|
+
- Ad click identifiers in network requests are redacted
|
|
220
|
+
- Network requests are sent through a cookieless domain
|
|
221
|
+
- No effect when `ad_storage` is `granted`
|
|
222
|
+
|
|
223
|
+
**When to use:** Extra privacy compliance; recommended for EU-focused sites.
|
|
224
|
+
|
|
225
|
+
## Verification
|
|
226
|
+
|
|
227
|
+
### Using Tag Assistant (tagassistant.google.com)
|
|
228
|
+
|
|
229
|
+
1. Open Tag Assistant and connect to your site
|
|
230
|
+
2. Check the "Consent" tab for each tag
|
|
231
|
+
3. Verify:
|
|
232
|
+
- "On-page Default" shows `denied` for all signals
|
|
233
|
+
- "On-page Update" shows correct state after user action
|
|
234
|
+
- "Current State" reflects the actual consent
|
|
235
|
+
|
|
236
|
+
### Using Browser DevTools
|
|
237
|
+
|
|
238
|
+
```javascript
|
|
239
|
+
// Check dataLayer for consent commands
|
|
240
|
+
dataLayer.filter(e => e[0] === 'consent');
|
|
241
|
+
|
|
242
|
+
// Check if GA cookies exist (should be absent when denied)
|
|
243
|
+
document.cookie.split(';').filter(c => c.trim().startsWith('_ga'));
|
|
244
|
+
|
|
245
|
+
// Check localStorage consent value
|
|
246
|
+
localStorage.getItem('app_cookie_consent');
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### GA4 DebugView
|
|
250
|
+
|
|
251
|
+
Enable debug mode to see real-time events:
|
|
252
|
+
|
|
253
|
+
```javascript
|
|
254
|
+
gtag('config', 'G-XXXXXXXXXX', { 'debug_mode': true });
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Events appear in GA4 > Admin > DebugView with consent state indicators.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# GA4 Event Tracking — Reference
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Contents
|
|
5
|
+
|
|
6
|
+
- [Table of Contents](#table-of-contents)
|
|
7
|
+
- [Event Types](#event-types)
|
|
8
|
+
- [Recommended Events](#recommended-events)
|
|
9
|
+
- [Custom Events](#custom-events)
|
|
10
|
+
- [Parameter Rules](#parameter-rules)
|
|
11
|
+
- [Ecommerce Events](#ecommerce-events)
|
|
12
|
+
- [SaaS / Subscription Events](#saas--subscription-events)
|
|
13
|
+
- [trackEvent Wrapper Pattern](#trackevent-wrapper-pattern)
|
|
14
|
+
|
|
15
|
+
## Table of Contents
|
|
16
|
+
|
|
17
|
+
- [Event Types](#event-types)
|
|
18
|
+
- [Recommended Events](#recommended-events)
|
|
19
|
+
- [Custom Events](#custom-events)
|
|
20
|
+
- [Parameter Rules](#parameter-rules)
|
|
21
|
+
- [Ecommerce Events](#ecommerce-events)
|
|
22
|
+
- [SaaS / Subscription Events](#saas--subscription-events)
|
|
23
|
+
- [trackEvent Wrapper Pattern](#trackevent-wrapper-pattern)
|
|
24
|
+
|
|
25
|
+
## Event Types
|
|
26
|
+
|
|
27
|
+
| Type | Description | Setup |
|
|
28
|
+
|------|-------------|-------|
|
|
29
|
+
| **Automatic** | `page_view`, `first_visit`, `session_start` | Always collected |
|
|
30
|
+
| **Enhanced measurement** | `scroll`, `click` (outbound), `file_download`, `video_*`, `site_search` | Toggle in GA4 Admin |
|
|
31
|
+
| **Recommended** | Predefined names Google recognizes (`login`, `sign_up`, `purchase`, etc.) | Implement with exact name |
|
|
32
|
+
| **Custom** | Any name you define for app-specific actions | Implement + create custom dimension in GA4 |
|
|
33
|
+
|
|
34
|
+
## Recommended Events
|
|
35
|
+
|
|
36
|
+
Use these exact names — GA4 recognizes them for built-in reports and features.
|
|
37
|
+
|
|
38
|
+
### Authentication & Engagement
|
|
39
|
+
|
|
40
|
+
| Event | Parameters | When |
|
|
41
|
+
|-------|-----------|------|
|
|
42
|
+
| `login` | `method` (string) | User logs in |
|
|
43
|
+
| `sign_up` | `method` (string) | User registers |
|
|
44
|
+
| `share` | `method`, `content_type`, `item_id` | User shares content |
|
|
45
|
+
| `search` | `search_term` | User searches |
|
|
46
|
+
|
|
47
|
+
### Ecommerce (Core Flow)
|
|
48
|
+
|
|
49
|
+
| Event | Required Params | When |
|
|
50
|
+
|-------|----------------|------|
|
|
51
|
+
| `view_item` | `currency`, `value`, `items[]` | User views product |
|
|
52
|
+
| `add_to_cart` | `currency`, `value`, `items[]` | Added to cart |
|
|
53
|
+
| `remove_from_cart` | `currency`, `value`, `items[]` | Removed from cart |
|
|
54
|
+
| `view_cart` | `currency`, `value`, `items[]` | Cart viewed |
|
|
55
|
+
| `begin_checkout` | `currency`, `value`, `items[]` | Checkout started |
|
|
56
|
+
| `add_payment_info` | `currency`, `value`, `payment_type` | Payment info added |
|
|
57
|
+
| `add_shipping_info` | `currency`, `value`, `shipping_tier` | Shipping selected |
|
|
58
|
+
| `purchase` | `transaction_id`, `currency`, `value`, `items[]` | Purchase completed |
|
|
59
|
+
| `refund` | `transaction_id`, `currency`, `value` | Refund issued |
|
|
60
|
+
|
|
61
|
+
### Content & Engagement
|
|
62
|
+
|
|
63
|
+
| Event | Parameters | When |
|
|
64
|
+
|-------|-----------|------|
|
|
65
|
+
| `select_content` | `content_type`, `content_id` | User selects content |
|
|
66
|
+
| `view_promotion` | `creative_name`, `promotion_id` | Promo viewed |
|
|
67
|
+
| `select_promotion` | `creative_name`, `promotion_id` | Promo clicked |
|
|
68
|
+
|
|
69
|
+
## Custom Events
|
|
70
|
+
|
|
71
|
+
For app-specific actions not covered by recommended events.
|
|
72
|
+
|
|
73
|
+
### Naming Rules
|
|
74
|
+
|
|
75
|
+
- Use `snake_case` (lowercase with underscores)
|
|
76
|
+
- Max 40 characters
|
|
77
|
+
- Must start with a letter
|
|
78
|
+
- No reserved prefixes: `_`, `firebase_`, `ga_`, `google_`, `gtag.`
|
|
79
|
+
- No reserved names: `ad_click`, `ad_impression`, `app_remove`, etc.
|
|
80
|
+
|
|
81
|
+
### Examples for SaaS Apps
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
trackEvent('send_message');
|
|
85
|
+
trackEvent('report_started');
|
|
86
|
+
trackEvent('report_completed', { tool_calls: 5, tokens: 1200 });
|
|
87
|
+
trackEvent('copy_report');
|
|
88
|
+
trackEvent('share_report');
|
|
89
|
+
trackEvent('generate_artifact', { artifact_type: 'pdf' });
|
|
90
|
+
trackEvent('feedback_prompt_shown');
|
|
91
|
+
trackEvent('submit_feedback', { rating: 5 });
|
|
92
|
+
trackEvent('upgrade_prompt_shown');
|
|
93
|
+
trackEvent('limit_reached_shown');
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Parameter Rules
|
|
97
|
+
|
|
98
|
+
### Built-in Parameters (Auto-populated)
|
|
99
|
+
|
|
100
|
+
These parameters automatically map to GA4 dimensions without extra configuration:
|
|
101
|
+
`method`, `search_term`, `currency`, `value`, `transaction_id`, `payment_type`,
|
|
102
|
+
`shipping_tier`, `coupon`, `item_id`, `item_name`, `item_category`.
|
|
103
|
+
|
|
104
|
+
### Custom Parameters
|
|
105
|
+
|
|
106
|
+
Custom parameters require creating a **custom dimension** or **custom metric** in GA4 Admin
|
|
107
|
+
to appear in reports:
|
|
108
|
+
|
|
109
|
+
1. GA4 Admin > Custom definitions > Create custom dimension
|
|
110
|
+
2. Set scope: Event-scoped (most common) or User-scoped
|
|
111
|
+
3. Map to the parameter name used in code
|
|
112
|
+
|
|
113
|
+
Limits per property:
|
|
114
|
+
- 50 event-scoped custom dimensions
|
|
115
|
+
- 25 user-scoped custom dimensions
|
|
116
|
+
- 50 custom metrics
|
|
117
|
+
|
|
118
|
+
### Parameter Value Limits
|
|
119
|
+
|
|
120
|
+
- String values: max 100 characters
|
|
121
|
+
- Event name: max 40 characters
|
|
122
|
+
- Up to 25 custom parameters per event
|
|
123
|
+
- `items[]` array: max 200 items
|
|
124
|
+
|
|
125
|
+
## Ecommerce Events
|
|
126
|
+
|
|
127
|
+
### Item Object Structure
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
gtag('event', 'purchase', {
|
|
131
|
+
transaction_id: 'T_12345',
|
|
132
|
+
value: 29.99,
|
|
133
|
+
currency: 'USD',
|
|
134
|
+
items: [{
|
|
135
|
+
item_id: 'plan_pro',
|
|
136
|
+
item_name: 'Pro Plan',
|
|
137
|
+
item_category: 'subscription',
|
|
138
|
+
price: 29.99,
|
|
139
|
+
quantity: 1
|
|
140
|
+
}]
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Ecommerce Funnel
|
|
145
|
+
|
|
146
|
+
Track the complete funnel for conversion analysis:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
view_item → add_to_cart → begin_checkout → add_payment_info → purchase
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Each step should include consistent `items[]` data for funnel analysis.
|
|
153
|
+
|
|
154
|
+
## SaaS / Subscription Events
|
|
155
|
+
|
|
156
|
+
Common event patterns for SaaS products:
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
// Paywall / upgrade flow
|
|
160
|
+
trackEvent('view_paywall');
|
|
161
|
+
trackEvent('begin_checkout', { plan_slug: 'pro_monthly' });
|
|
162
|
+
trackEvent('purchase', { plan: 'pro_monthly', value: 29.99, currency: 'USD' });
|
|
163
|
+
|
|
164
|
+
// Subscription management
|
|
165
|
+
trackEvent('view_subscription_panel');
|
|
166
|
+
trackEvent('change_plan', { plan_slug: 'enterprise_annual' });
|
|
167
|
+
trackEvent('cancel_subscription');
|
|
168
|
+
|
|
169
|
+
// Engagement quality
|
|
170
|
+
trackEvent('feature_used', { feature: 'export_pdf' });
|
|
171
|
+
trackEvent('onboarding_step', { step: 3, step_name: 'connect_data' });
|
|
172
|
+
trackEvent('activation_complete');
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## trackEvent Wrapper Pattern
|
|
176
|
+
|
|
177
|
+
Always use a wrapper to guard against gtag not being loaded:
|
|
178
|
+
|
|
179
|
+
```javascript
|
|
180
|
+
function trackEvent(name, params) {
|
|
181
|
+
if (typeof gtag === 'function') gtag('event', name, params);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Benefits:
|
|
186
|
+
- No errors if gtag hasn't loaded yet (deferred loading)
|
|
187
|
+
- No errors if user declined consent and gtag is unavailable
|
|
188
|
+
- Single point to add logging, filtering, or batching later
|
|
189
|
+
|
|
190
|
+
### Extended Wrapper with Debug Support
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
function trackEvent(name, params) {
|
|
194
|
+
if (typeof gtag !== 'function') return;
|
|
195
|
+
if (location.hostname === 'localhost') {
|
|
196
|
+
console.debug('[GA]', name, params);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
gtag('event', name, params);
|
|
200
|
+
}
|
|
201
|
+
```
|