Как получить API Secret для GA4 (Инструкция)

Чтобы настроить Measurement Protocol, вам понадобится секретный ключ (API Secret). Без него серверы Google отклонят любые входящие HTTP-запросы от вашего Web Worker.

  1. Откройте панель Google Analytics и выберите ваш ресурс GA4.
  2. В левом нижнем углу нажмите на шестеренку Администратор (Admin).
  3. В столбце параметров ресурса выберите пункт Потоки данных (Data Streams) и кликните на ваш текущий Веб-поток.
  4. В открывшемся окне настроек потока прокрутите вниз до блока Дополнительные настройки и выберите Секретные ключи Measurement Protocol (Measurement Protocol API secrets).
  5. Нажмите кнопку Создать (Create), задайте для ключа понятное имя (например, web-worker-prod) и скопируйте сгенерированное буквенно-цифровое значение.

⚠️ Важно: Храните этот ключ в секрете. В кодовой базе воркера рекомендуется подставлять его через переменные окружения на этапе сборки проекта, чтобы не «светить» в публичном репозитории.

Миграция данных: Маппинг параметров из Universal Analytics в GA4

В старом Universal Analytics (UA) все кастомные события жестко загонялись в иерархию трех параметров: Категория (Event Category), Действие (Event Action) и Ярлык (Event Label). В Google Analytics 4 эта концепция полностью упразднена. Теперь модель данных стала событийно-ориентированной (Event-driven): существует просто имя события и плоский объект с любым количеством кастомных параметров.

Вот как выглядит маппинг старой структуры под новый формат GA4 при передаче через Web Worker:

Параметр в UA (v1)Обозначение в UAЭквивалент в GA4Описание в новой концепции
Event ActioneaИмя события (Event Name)Становится главным идентификатором действия (например, generate_lead, click_podcast).
Event CategoryecКастомный параметрПереносится внутрь параметров (например, traffic_type или event_category).
Event LabelelПлоские ключиБольше не нужно упаковывать данные в JSON-строку. Любые контекстные данные (ID статьи, поисковый запрос) передаются отдельными свойствами.

Пример трансформации кода

Раньше в воркере приходилось склеивать параметры в строку или отправлять фиксированные ключи. Теперь мы раскладываем объект params напрямую в тело JSON, избавляясь от JSON.stringify:

// Было (Universal Analytics v1):
const eventParams = {
  v: '1',
  tid: currentGaId,
  t: 'event',            
  ea: payload.action,          // Event Action -> Имя действия
  ec: 'Рантайм Блога',          // Event Category -> Категория
  el: JSON.stringify(payload.params) // Event Label -> Сжатый JSON-строкой контекст
};

// Стало (Google Analytics 4):
const ga4Payload = {
  client_id: payload.clientId,
  events: [{
    name: payload.action,      // Имя события теперь на верхнем уровне
    params: {
      ...payload.params,       // Плоский объект параметров (например, { search_term: "next.js" })
      event_category: 'Рантайм Блога' // Бывшая категория передается обычным свойством
    }
  }]
};

Такой подход позволяет строить гибкие воронки и отчеты в интерфейсе GA4, оперируя понятными бизнес-метриками, а не пытаясь вспомнить, что именно было зашито в «Ярлык события».

Локальная отладка и валидация событий

Поскольку в режиме no-cors браузер скрывает статус-коды и ответы от серверов Google Analytics 4, разработчик не видит, если в параметрах события допущена опечатка. Google просто молча проигнорирует хит.

Для решения этой проблемы у Google есть специальный валидационный эндпоинт — /debug/mp/collect. В отличие от «боевого», он полностью поддерживает CORS-запросы. Это позволяет нам переключать воркер в режим отладки на локальной машине и видеть детальный JSON-ответ с описанием всех ошибок прямо в консоли браузера.

1. Модификация Web Worker

Добавим в воркер флаг isDebug. Если он включен, воркер переключается на mode: 'cors', меняет эндпоинт и выводит ответ валидатора Google в консоль:

public/analytics/analytics-worker.js

function sendGA4Event(bodyObject, isDebug = false) {
  if (!currentGaId) return;

  // Если включен дебаг, используем валидационный путь, иначе боевой
  const path = isDebug ? '/debug/mp/collect' : '/mp/collect';
  const url = new URL(path, 'https://google-analytics.com');
  
  url.searchParams.set('measurement_id', currentGaId);
  url.searchParams.set('api_secret', API_SECRET);

  const endpoint = url.toString();

  // Настройки fetch меняются в зависимости от режима окружения
  const fetchOptions = {
    method: 'POST',
    body: isDebug ? JSON.stringify(bodyObject) : new Blob([JSON.stringify(bodyObject)], { type: 'text/plain;charset=UTF-8' }),
    mode: isDebug ? 'cors' : 'no-cors' // В дебаге CORS разрешен серверами Google
  };

  if (isDebug) {
    // Выставляем заголовок JSON, так как в режиме cors браузер его не заблокирует
    fetchOptions.headers = { 'Content-Type': 'application/json' };
  }

  fetch(endpoint, fetchOptions)
    .then(res => {
      if (isDebug && res.ok) {
        return res.json();
      }
    })
    .then(validationData => {
      if (isDebug && validationData) {
        const messages = validationData.validationMessages || [];
        if (messages.length === 0) {
          console.log('✅ [GA4 Валидатор]: Событие успешно прошло проверку!', bodyObject.events[0].name);
        } else {
          console.warn('❌ [GA4 Валидатор]: Ошибка в структуре события:', messages);
        }
      }
    })
    .catch(err => console.error('❌ Ошибка отправки из воркера:', err));
}

2. Как передать флаг из Next.js

Чтобы воркер знал, в какой среде он запущен, передайте флаг isDebug во время инициализации (init) из основного потока вашего приложения:

pages/_app.tsx

// Внутри useEffect в файле _app.tsx
const isDevelopment = process.env.NODE_ENV === 'development';

// Инициализируем воркер токеном и флагом окружения
worker.postMessage({ 
  type: 'init', 
  payload: { 
    gaId: GA_ID,
    isDebug: isDevelopment // true при локальной разработке (npm run dev)
  } 
});

Не забудьте обновить обработчик case 'init' внутри самого воркера, чтобы он сохранял этот флаг в глобальную переменную:

let isDebugMode = false;

// Внутри switch (type)
case 'init':
  if (payload && payload.gaId) {
    currentGaId = payload.gaId;
    isDebugMode = !!payload.isDebug;
    console.log(`📡 [Analytics Worker]: Инициализирован. Режим отладки: ${isDebugMode}`);
  }
  break;

Теперь при отправке события функция будет вызываться с актуальным контекстом: sendGA4Event(payload, isDebugMode). Если вы случайно передадите неподдерживаемый параметр или забудете client_id, Google вернет развернутый массив ошибок прямо в Console вашего браузера.