@alexsab-ru/scripts 0.14.0 → 0.15.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.
@@ -0,0 +1,234 @@
1
+ # Persist Campaign Data
2
+
3
+ Функционал для сохранения данных рекламных кампаний (UTM параметры, gclid и др.) в cookies браузера и отправки в dataLayer. Основан на популярном Google Tag Manager шаблоне.
4
+
5
+ ## Возможности
6
+
7
+ - 🎯 Автоматическое сохранение UTM параметров и других данных кампании в cookies
8
+ - 📊 Отправка данных в dataLayer для интеграции с аналитикой
9
+ - 🔗 Сохранение referrer когда пользователь приходит с внешнего домена
10
+ - ⚙️ Гибкая настройка параметров и поведения
11
+ - 🚀 Простая интеграция с React, Vue, Next.js и другими фреймворками
12
+ - 📱 Поддержка SPA (Single Page Applications)
13
+
14
+ ## Установка
15
+
16
+ ```bash
17
+ npm install @alexsab-ru/scripts
18
+ ```
19
+
20
+ ## Быстрый старт
21
+
22
+ ```javascript
23
+ import { initPersistCampaignData } from '@alexsab-ru/scripts';
24
+
25
+ // Автоматическая инициализация при загрузке страницы
26
+ initPersistCampaignData();
27
+ ```
28
+
29
+ ### Установка отдельных модулей
30
+
31
+ ```javascript
32
+ // Всё сразу
33
+ import { persistCampaignData } from '@alexsab-ru/scripts';
34
+
35
+ // Только campaign модуль
36
+ import { persistCampaignData } from '@alexsab-ru/scripts/campaign';
37
+
38
+ // Конкретный файл
39
+ import { persistCampaignData } from '@alexsab-ru/scripts/campaign/persist';
40
+ ```
41
+
42
+ ## API
43
+
44
+ ### `persistCampaignData(options)`
45
+
46
+ Основная функция для сохранения данных кампании.
47
+
48
+ **Параметры:**
49
+
50
+ | Параметр | Тип | По умолчанию | Описание |
51
+ |----------|-----|--------------|----------|
52
+ | `storeInCookie` | boolean | `true` | Сохранять ли данные в cookies |
53
+ | `pushToDataLayer` | boolean | `true` | Отправлять ли данные в dataLayer |
54
+ | `triggerParameters` | string[] | `['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'utm_id', 'gclid', 'yclid', 'ysclid']` | Параметры URL, которые триггерят сохранение |
55
+ | `urlCookieName` | string | `'__gtm_campaign_url'` | Имя cookie для URL кампании |
56
+ | `referrerCookieName` | string | `'__gtm_referrer'` | Имя cookie для referrer |
57
+ | `dataLayerName` | string | `'dataLayer'` | Имя массива dataLayer |
58
+ | `dataLayerKey` | string | `'originalLocation'` | Ключ в dataLayer для оригинального URL |
59
+ | `cookieExpireDays` | number | `null` | Дни жизни cookie (null = session cookie) |
60
+
61
+ **Возвращает:** `boolean` - успешность операции
62
+
63
+ ### `getCampaignData(options)`
64
+
65
+ Получает сохраненные данные кампании из cookies.
66
+
67
+ **Параметры:**
68
+
69
+ | Параметр | Тип | По умолчанию | Описание |
70
+ |----------|-----|--------------|----------|
71
+ | `urlCookieName` | string | `'__gtm_campaign_url'` | Имя cookie для URL кампании |
72
+ | `referrerCookieName` | string | `'__gtm_referrer'` | Имя cookie для referrer |
73
+
74
+ **Возвращает:**
75
+ ```javascript
76
+ {
77
+ campaignUrl: string | undefined,
78
+ referrer: string | undefined
79
+ }
80
+ ```
81
+
82
+ ### `extractUtmParameters(url)`
83
+
84
+ Извлекает UTM параметры из URL.
85
+
86
+ **Параметры:**
87
+
88
+ | Параметр | Тип | По умолчанию | Описание |
89
+ |----------|-----|--------------|----------|
90
+ | `url` | string | `window.location.href` | URL для анализа |
91
+
92
+ **Возвращает:**
93
+ ```javascript
94
+ {
95
+ utm_source: string | null,
96
+ utm_medium: string | null,
97
+ utm_campaign: string | null,
98
+ utm_term: string | null,
99
+ utm_content: string | null,
100
+ utm_id: string | null,
101
+ gclid: string | null,
102
+ yclid: string | null,
103
+ ysclid: string | null
104
+ }
105
+ ```
106
+
107
+ ### `initPersistCampaignData(options)`
108
+
109
+ Автоматическая инициализация при загрузке страницы.
110
+
111
+ **Параметры:** те же, что у `persistCampaignData`
112
+
113
+ ## Примеры использования
114
+
115
+ ### Базовое использование
116
+
117
+ ```javascript
118
+ import { persistCampaignData } from '@alexsab-ru/scripts';
119
+
120
+ // Запуск с настройками по умолчанию
121
+ persistCampaignData();
122
+ ```
123
+
124
+ ### Кастомная настройка
125
+
126
+ ```javascript
127
+ persistCampaignData({
128
+ storeInCookie: true,
129
+ pushToDataLayer: true,
130
+ triggerParameters: ['utm_source', 'utm_medium', 'fbclid', 'custom_param'],
131
+ cookieExpireDays: 30,
132
+ urlCookieName: 'my_campaign_url'
133
+ });
134
+ ```
135
+
136
+ ### React приложение
137
+
138
+ ```javascript
139
+ import React, { useEffect } from 'react';
140
+ import { initPersistCampaignData } from '@alexsab-ru/scripts';
141
+
142
+ function App() {
143
+ useEffect(() => {
144
+ initPersistCampaignData({
145
+ cookieExpireDays: 30
146
+ });
147
+ }, []);
148
+
149
+ return <div>Your App</div>;
150
+ }
151
+ ```
152
+
153
+ ### Next.js
154
+
155
+ ```javascript
156
+ // pages/_app.js
157
+ import { useEffect } from 'react';
158
+ import { initPersistCampaignData } from '@alexsab-ru/scripts';
159
+
160
+ function MyApp({ Component, pageProps }) {
161
+ useEffect(() => {
162
+ initPersistCampaignData();
163
+ }, []);
164
+
165
+ return <Component {...pageProps} />;
166
+ }
167
+
168
+ export default MyApp;
169
+ ```
170
+
171
+ ### Vue.js
172
+
173
+ ```javascript
174
+ // main.js или App.vue
175
+ import { initPersistCampaignData } from '@alexsab-ru/scripts';
176
+
177
+ export default {
178
+ mounted() {
179
+ initPersistCampaignData();
180
+ }
181
+ };
182
+ ```
183
+
184
+ ### Получение сохраненных данных
185
+
186
+ ```javascript
187
+ import { getCampaignData, extractUtmParameters } from '@alexsab-ru/scripts';
188
+
189
+ // Получить данные из cookies
190
+ const campaignData = getCampaignData();
191
+ console.log('Campaign URL:', campaignData.campaignUrl);
192
+ console.log('Referrer:', campaignData.referrer);
193
+
194
+ // Извлечь UTM параметры
195
+ const utmParams = extractUtmParameters();
196
+ console.log('UTM Source:', utmParams.utm_source);
197
+ ```
198
+
199
+ ## Как это работает
200
+
201
+ 1. **Сохранение URL кампании**: Если в URL есть параметры из списка `triggerParameters`, полный URL сохраняется в cookie
202
+ 2. **Сохранение referrer**: Если пользователь пришел с внешнего домена, referrer сохраняется в отдельный cookie
203
+ 3. **DataLayer**: Текущий URL отправляется в dataLayer с событием `originalLocation`
204
+ 4. **Session cookies**: По умолчанию cookies создаются как session (удаляются при закрытии браузера)
205
+
206
+ ## Интеграция с аналитикой
207
+
208
+ Данные из dataLayer можно использовать в Google Analytics, Adobe Analytics и других системах:
209
+
210
+ ```javascript
211
+ // Google Analytics 4
212
+ gtag('config', 'GA_MEASUREMENT_ID', {
213
+ page_title: 'Custom Page',
214
+ page_location: dataLayer.find(item => item.originalLocation)?.originalLocation
215
+ });
216
+
217
+ // Google Tag Manager
218
+ // Используйте dataLayer переменные в тегах и триггерах
219
+ ```
220
+
221
+ ## Совместимость
222
+
223
+ - ✅ Vanilla JavaScript
224
+ - ✅ React
225
+ - ✅ Vue.js
226
+ - ✅ Next.js
227
+ - ✅ Nuxt.js
228
+ - ✅ Angular
229
+ - ✅ SPA (Single Page Applications)
230
+ - ✅ SSR (Server Side Rendering)
231
+
232
+ ## Лицензия
233
+
234
+ MIT
@@ -0,0 +1,126 @@
1
+ // Примеры использования Persist Campaign Data
2
+
3
+ import {
4
+ persistCampaignData,
5
+ getCampaignData,
6
+ extractUtmParameters,
7
+ initPersistCampaignData
8
+ } from '@alexsab-ru/scripts';
9
+
10
+ // 1. Простой запуск с настройками по умолчанию
11
+ // Сохранит UTM параметры и gclid в cookies, отправит данные в dataLayer
12
+ persistCampaignData();
13
+
14
+ // 2. Автоматическая инициализация при загрузке страницы
15
+ initPersistCampaignData();
16
+
17
+ // 3. Настройка с кастомными параметрами
18
+ persistCampaignData({
19
+ storeInCookie: true,
20
+ pushToDataLayer: true,
21
+ triggerParameters: ['utm_source', 'utm_medium', 'utm_campaign', 'fbclid', 'custom_param'],
22
+ urlCookieName: 'my_campaign_url',
23
+ referrerCookieName: 'my_referrer',
24
+ dataLayerName: 'customDataLayer',
25
+ dataLayerKey: 'originalPageUrl',
26
+ cookieExpireDays: 30 // cookie будет жить 30 дней
27
+ });
28
+
29
+ // 4. Только сохранение в cookies (без dataLayer)
30
+ persistCampaignData({
31
+ storeInCookie: true,
32
+ pushToDataLayer: false,
33
+ cookieExpireDays: 90
34
+ });
35
+
36
+ // 5. Только отправка в dataLayer (без cookies)
37
+ persistCampaignData({
38
+ storeInCookie: false,
39
+ pushToDataLayer: true,
40
+ dataLayerName: 'myDataLayer'
41
+ });
42
+
43
+ // 6. Получение сохраненных данных кампании
44
+ const campaignData = getCampaignData();
45
+ console.log('Campaign URL:', campaignData.campaignUrl);
46
+ console.log('Referrer:', campaignData.referrer);
47
+
48
+ // 7. Получение данных с кастомными именами cookies
49
+ const customCampaignData = getCampaignData({
50
+ urlCookieName: 'my_campaign_url',
51
+ referrerCookieName: 'my_referrer'
52
+ });
53
+
54
+ // 8. Извлечение UTM параметров из текущего URL
55
+ const utmParams = extractUtmParameters();
56
+ console.log('UTM Source:', utmParams.utm_source);
57
+ console.log('UTM Medium:', utmParams.utm_medium);
58
+ console.log('UTM Campaign:', utmParams.utm_campaign);
59
+
60
+ // 9. Извлечение UTM параметров из конкретного URL
61
+ const specificUtmParams = extractUtmParameters('https://example.com/?utm_source=google&utm_medium=cpc');
62
+ console.log('Specific UTM params:', specificUtmParams);
63
+
64
+ // 10. Инициализация для SPA (Single Page Application)
65
+ // Запускать только на первоначальной загрузке страницы
66
+ if (!window.campaignDataPersisted) {
67
+ persistCampaignData();
68
+ window.campaignDataPersisted = true;
69
+ }
70
+
71
+ // 11. Интеграция с React
72
+ import React, { useEffect } from 'react';
73
+
74
+ function App() {
75
+ useEffect(() => {
76
+ // Запускаем только при первом рендере компонента
77
+ initPersistCampaignData({
78
+ cookieExpireDays: 30,
79
+ triggerParameters: ['utm_source', 'utm_medium', 'utm_campaign', 'gclid', 'fbclid']
80
+ });
81
+ }, []);
82
+
83
+ return <div>Your App</div>;
84
+ }
85
+
86
+ // 12. Интеграция с Vue.js
87
+ // В main.js или App.vue
88
+ import { initPersistCampaignData } from '@alexsab-ru/scripts';
89
+
90
+ export default {
91
+ mounted() {
92
+ initPersistCampaignData();
93
+ }
94
+ };
95
+
96
+ // 13. Интеграция с Next.js
97
+ // В _app.js
98
+ import { useEffect } from 'react';
99
+ import { initPersistCampaignData } from '@alexsab-ru/scripts';
100
+
101
+ function MyApp({ Component, pageProps }) {
102
+ useEffect(() => {
103
+ initPersistCampaignData();
104
+ }, []);
105
+
106
+ return <Component {...pageProps} />;
107
+ }
108
+
109
+ // 14. Обработка ошибок
110
+ const success = persistCampaignData({
111
+ storeInCookie: true,
112
+ pushToDataLayer: true
113
+ });
114
+
115
+ if (!success) {
116
+ console.error('Failed to persist campaign data');
117
+ // Можно отправить ошибку в систему мониторинга
118
+ }
119
+
120
+ // 15. Условное выполнение
121
+ // Запускать только для определенных страниц
122
+ if (window.location.pathname.includes('/landing/')) {
123
+ persistCampaignData({
124
+ cookieExpireDays: 7 // Короткий срок жизни для лендингов
125
+ });
126
+ }
@@ -0,0 +1,280 @@
1
+ // Примеры использования NoBounce модуля
2
+
3
+ import {
4
+ initNoBounce,
5
+ startNoBounce,
6
+ getNoBounceStats,
7
+ stopNoBounce,
8
+ sendNoBounceNow
9
+ } from '@alexsab-ru/scripts/nobounce';
10
+
11
+ // ============================================
12
+ // БАЗОВОЕ ИСПОЛЬЗОВАНИЕ
13
+ // ============================================
14
+
15
+ // 1. Простой запуск с настройками по умолчанию (15 секунд)
16
+ startNoBounce();
17
+
18
+ // 2. Запуск с кастомной задержкой
19
+ startNoBounce(30); // 30 секунд
20
+
21
+ // 3. Запуск с кастомным названием цели
22
+ startNoBounce(20, 'EngagedUser');
23
+
24
+ // ============================================
25
+ // ПРОДВИНУТАЯ НАСТРОЙКА
26
+ // ============================================
27
+
28
+ // 4. Полная настройка
29
+ initNoBounce({
30
+ delay: 25, // 25 секунд
31
+ goalName: 'QualityVisit', // Кастомное название цели
32
+ goalParams: { // Дополнительные параметры
33
+ page_type: 'landing',
34
+ source: 'organic'
35
+ },
36
+ oncePerSession: true, // Один раз за сессию
37
+ checkVisibility: true, // Учитывать видимость страницы
38
+ debug: true // Включить отладку
39
+ });
40
+
41
+ // 5. Настройка для разных типов страниц
42
+ const pageType = document.body.dataset.pageType;
43
+
44
+ switch(pageType) {
45
+ case 'homepage':
46
+ initNoBounce({
47
+ delay: 10,
48
+ goalName: 'HomepageEngagement',
49
+ goalParams: { page_type: 'homepage' }
50
+ });
51
+ break;
52
+
53
+ case 'product':
54
+ initNoBounce({
55
+ delay: 20,
56
+ goalName: 'ProductPageEngagement',
57
+ goalParams: {
58
+ page_type: 'product',
59
+ product_id: document.body.dataset.productId
60
+ }
61
+ });
62
+ break;
63
+
64
+ case 'blog':
65
+ initNoBounce({
66
+ delay: 30,
67
+ goalName: 'BlogEngagement',
68
+ goalParams: { page_type: 'blog' }
69
+ });
70
+ break;
71
+
72
+ default:
73
+ startNoBounce(15, 'DefaultEngagement');
74
+ }
75
+
76
+ // ============================================
77
+ // УСЛОВНЫЙ ЗАПУСК
78
+ // ============================================
79
+
80
+ // 6. Запуск только для новых пользователей
81
+ if (!localStorage.getItem('returning_user')) {
82
+ initNoBounce({
83
+ delay: 20,
84
+ goalName: 'NewUserEngagement',
85
+ goalParams: { user_type: 'new' }
86
+ });
87
+ }
88
+
89
+ // 7. Запуск только для трафика с рекламы
90
+ const urlParams = new URLSearchParams(window.location.search);
91
+ if (urlParams.get('utm_source') || urlParams.get('gclid')) {
92
+ initNoBounce({
93
+ delay: 15,
94
+ goalName: 'PaidTrafficEngagement',
95
+ goalParams: {
96
+ traffic_type: 'paid',
97
+ utm_source: urlParams.get('utm_source') || 'unknown'
98
+ }
99
+ });
100
+ }
101
+
102
+ // 8. Разная задержка в зависимости от источника трафика
103
+ const utmSource = urlParams.get('utm_source');
104
+ let delay = 15; // по умолчанию
105
+
106
+ if (utmSource === 'google') {
107
+ delay = 10; // быстрее для Google трафика
108
+ } else if (utmSource === 'facebook') {
109
+ delay = 20; // медленнее для Facebook
110
+ } else if (document.referrer.includes('organic')) {
111
+ delay = 25; // еще медленнее для органики
112
+ }
113
+
114
+ initNoBounce({
115
+ delay,
116
+ goalName: 'SourceBasedEngagement',
117
+ goalParams: { utm_source: utmSource || 'direct' }
118
+ });
119
+
120
+ // ============================================
121
+ // КОНТРОЛЬ И МОНИТОРИНГ
122
+ // ============================================
123
+
124
+ // 9. Мониторинг статистики
125
+ setInterval(() => {
126
+ const stats = getNoBounceStats();
127
+ if (stats) {
128
+ console.log('Время на странице:', stats);
129
+
130
+ // Отправляем промежуточные цели
131
+ if (stats.visibleTime === 60 && !window.oneMinuteSent) {
132
+ reachGoal('OneMinuteOnPage', { visible_time: 60 });
133
+ window.oneMinuteSent = true;
134
+ }
135
+
136
+ if (stats.visibleTime === 300 && !window.fiveMinutesSent) {
137
+ reachGoal('FiveMinutesOnPage', { visible_time: 300 });
138
+ window.fiveMinutesSent = true;
139
+ }
140
+ }
141
+ }, 10000); // каждые 10 секунд
142
+
143
+ // 10. Принудительная отправка при определенных действиях
144
+ document.addEventListener('scroll', () => {
145
+ const scrollPercent = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
146
+
147
+ if (scrollPercent > 75 && !window.deepScrollSent) {
148
+ sendNoBounceNow(); // Принудительно отправляем NoBounce
149
+ window.deepScrollSent = true;
150
+ }
151
+ });
152
+
153
+ // 11. Остановка таймера при определенных условиях
154
+ window.addEventListener('beforeunload', () => {
155
+ const stats = getNoBounceStats();
156
+
157
+ // Если пользователь быстро покидает страницу, не отправляем цель
158
+ if (stats && stats.visibleTime < 5) {
159
+ stopNoBounce();
160
+ }
161
+ });
162
+
163
+ // ============================================
164
+ // ИНТЕГРАЦИЯ С ФРЕЙМВОРКАМИ
165
+ // ============================================
166
+
167
+ // 12. React Hook
168
+ import { useEffect } from 'react';
169
+
170
+ function useNoBounce(options = {}) {
171
+ useEffect(() => {
172
+ const manager = initNoBounce({
173
+ delay: 15,
174
+ ...options
175
+ });
176
+
177
+ return () => {
178
+ if (manager) {
179
+ manager.stop();
180
+ }
181
+ };
182
+ }, []);
183
+ }
184
+
185
+ // В компоненте
186
+ function MyComponent() {
187
+ useNoBounce({
188
+ goalName: 'ReactPageEngagement',
189
+ goalParams: { framework: 'react' }
190
+ });
191
+
192
+ return <div>My Component</div>;
193
+ }
194
+
195
+ // 13. Vue.js Composable
196
+ import { onMounted, onUnmounted } from 'vue';
197
+
198
+ function useNoBounce(options = {}) {
199
+ let manager = null;
200
+
201
+ onMounted(() => {
202
+ manager = initNoBounce({
203
+ delay: 15,
204
+ ...options
205
+ });
206
+ });
207
+
208
+ onUnmounted(() => {
209
+ if (manager) {
210
+ manager.stop();
211
+ }
212
+ });
213
+
214
+ return { manager };
215
+ }
216
+
217
+ // 14. Next.js App integration
218
+ // В _app.js
219
+ import { useRouter } from 'next/router';
220
+ import { useEffect } from 'react';
221
+
222
+ function MyApp({ Component, pageProps }) {
223
+ const router = useRouter();
224
+
225
+ useEffect(() => {
226
+ const handleRouteChange = () => {
227
+ // Новая страница - инициализируем NoBounce
228
+ setTimeout(() => {
229
+ initNoBounce({
230
+ goalName: 'NextJSPageEngagement',
231
+ goalParams: {
232
+ route: router.pathname,
233
+ framework: 'nextjs'
234
+ }
235
+ });
236
+ }, 100);
237
+ };
238
+
239
+ handleRouteChange(); // Для первой загрузки
240
+ router.events.on('routeChangeComplete', handleRouteChange);
241
+
242
+ return () => {
243
+ router.events.off('routeChangeComplete', handleRouteChange);
244
+ };
245
+ }, [router]);
246
+
247
+ return <Component {...pageProps} />;
248
+ }
249
+
250
+ // ============================================
251
+ // ТЕСТИРОВАНИЕ И ОТЛАДКА
252
+ // ============================================
253
+
254
+ // 15. Тестовый режим
255
+ if (window.location.search.includes('nobounce_test=true')) {
256
+ initNoBounce({
257
+ delay: 3, // 3 секунды для тестирования
258
+ goalName: 'TestNoBounce',
259
+ debug: true,
260
+ oncePerSession: false // Позволяем многократную отправку
261
+ });
262
+ }
263
+
264
+ // 16. Отладочная информация
265
+ window.debugNoBounce = () => {
266
+ const stats = getNoBounceStats();
267
+ console.table(stats);
268
+
269
+ console.log('Manager:', getNoBounceManager());
270
+ };
271
+
272
+ // Добавляем в глобальный объект для отладки
273
+ if (typeof window !== 'undefined') {
274
+ window.noBounceDebug = {
275
+ getStats: getNoBounceStats,
276
+ sendNow: sendNoBounceNow,
277
+ stop: stopNoBounce,
278
+ reset: resetNoBounce
279
+ };
280
+ }
package/index.js CHANGED
@@ -2,3 +2,5 @@ export * from './lib/analytics';
2
2
  export * from './lib/calltouch';
3
3
  export * from './lib/cookie';
4
4
  export * from './lib/form';
5
+ export * from './lib/campaign';
6
+ export * from './lib/nobounce';
@@ -0,0 +1,5 @@
1
+ // Campaign module exports
2
+ export * from './persist-campaign-data';
3
+
4
+ // Re-export default
5
+ export { default } from './persist-campaign-data';