Интеграция с SPA

В одностраничном приложении переход между разделами не перезагружает страницу: ядро само не узнаёт, что контекст сменился. Поэтому приложение сообщает о переходах явно — вызовом GF.API('spa', …).

Базовая установка описана на странице Установка скрипта — здесь только то, что добавляется для SPA.

Два варианта установки

Выбор зависит от одного: известен ли контекст страницы в момент, когда сервер отдаёт HTML.

Вариант 1. Контекст известен при загрузке страницы

Подходит, если приложение рендерится на сервере или тип страницы можно определить сразу — например, по URL маршрута.

<script>
  window.GF = window.GF || {};
  GF.q = GF.q || [];
  GF.API = GF.API || function () { GF.q.push(arguments); };

  GF.section = "ИДЕНТИФИКАТОР_СЕКЦИИ";
  GF.pageContext = { type: "PRODUCT", data: ["SKU-12345"] };
</script>

<script src="//cdn-01.gravityfield.ai/core/core.js"></script>

Сниппет тот же, что и при обычной установке. Ядро запускает кампании сразу при загрузке и само отправляет просмотр страницы. О последующих переходах приложение сообщает событием spa.

Вариант 2. Контекст известен только приложению

Подходит, если на момент загрузки HTML тип страницы неизвестен — контекст появляется, когда отработает роутер. Добавьте GF.isSpa = true:

<script>
  window.GF = window.GF || {};
  GF.q = GF.q || [];
  GF.API = GF.API || function () { GF.q.push(arguments); };

  GF.section = "ИДЕНТИФИКАТОР_СЕКЦИИ";
  GF.isSpa = true;
</script>

<script src="//cdn-01.gravityfield.ai/core/core.js"></script>

С этим флагом ядро не запускает кампании на старте, а ждёт первого события spa — чтобы не проверять таргетинг по ещё неизвестному контексту. Отсюда два следствия:

  • отправьте spa для стартового маршрута сразу, как только приложение узнало контекст, — иначе на первой странице не покажется ни одна кампания;

  • просмотр первой страницы ядро само не засчитывает, поэтому в стартовом событии нужен countAsPageview: true.

Загрузка конфигурации своими силами

По умолчанию ядро загружает конфигурацию секции (dynamic.js) само. Если вы хотите управлять этим — например, отдавать файл со своего домена, — включите GF.syncLoad = true и подключите его тегом. Тег dynamic.js должен идти перед core.js:

<script>
  window.GF = window.GF || {};
  GF.q = GF.q || [];
  GF.API = GF.API || function () { GF.q.push(arguments); };

  GF.section = "ИДЕНТИФИКАТОР_СЕКЦИИ";
  GF.isSpa = true;
  GF.syncLoad = true;
</script>

<script src="//cdn-01.gravityfield.ai/sections/ИДЕНТИФИКАТОР_СЕКЦИИ/dynamic.js"></script>
<script src="//cdn-01.gravityfield.ai/core/core.js"></script>

В этом варианте preload из базового сниппета не нужен — файл и так подключён обычным тегом. Если поставить теги в обратном порядке, ядро запустится раньше конфигурации и будет ждать её появления, добавляя лишнюю задержку к каждой загрузке страницы.

Режим syncLoad не связан с isSpa — его можно включать и без SPA.

Событие перехода

GF.API('spa', {
  context: {
    type: 'PRODUCT',
    data: ['SKU-12345']
  },
  url: 'https://store.example.com/product/SKU-12345',
  countAsPageview: true
});
Параметр Обязательный Назначение
context да Новый контекст страницы. Ядро обновляет его до перепроверки таргетинга.
countAsPageview нет true — переход считается новым просмотром страницы: отправляется pageview, сбрасываются данные предыдущей страницы. false — контент изменился, но это тот же просмотр.
url нет Адрес нового маршрута. Нужен, если приложение меняет history после вызова: иначе ядро возьмёт текущий location.href, а он ещё старый. Используется при countAsPageview: true.

Когда вызывать

  • При каждой смене маршрута — с countAsPageview: true.
  • При смене контекста без смены маршрута — например, переключение товара внутри одной карточки или смена языка либо валюты — с тем контекстом, который стал актуальным.

Вызывайте после того, как приложение обновило маршрут и знает новый контекст. Ждать окончания отрисовки не нужно: если кампания привязана к элементу, ядро дождётся его появления само.

Когда не вызывать

Событие spa — это не «что-то поменялось в DOM». Каждый вызов запускает полный цикл: перепроверку таргетинга всех SPA-кампаний и плейсментов, обновление вставок и новый показ (impression) для каждой сработавшей кампании.

Поэтому не отправляйте spa на раскрытие аккордеона, открытие модального окна, подгрузку следующей порции бесконечного списка и подобные изменения внутри одного экрана — это исказит статистику показов и создаст лишнюю нагрузку. Для таких случаев используйте триггер «ожидание элемента» в настройках кампании или обычные события.

Поведение кампаний при переходе

Режим SPA у кампании

В настройках кампании (и рекламного плейсмента) есть флаг работы в SPA. Перезапускаются при переходе только кампании с этим флагом. Кампания без него отрабатывает один раз при загрузке страницы и на смену маршрута не реагирует.

Если кампания настроена и работает при полной перезагрузке, но не появляется после перехода — в первую очередь проверьте этот флаг.

Что происходит со вставками

При получении события spa ядро:

  1. Убирает из своего реестра вставки, которые уже удалил сам фреймворк при перерисовке маршрута.

  2. Для оставшихся вставок SPA-кампаний перепроверяет условия таргетинга в новом контексте. Если условия больше не выполняются — вставка удаляется.

  3. Заново проверяет SPA-кампании и плейсменты для нового контекста. Если кампания срабатывает повторно, её прежний блок заменяется на месте, а не дублируется рядом.

Всплывающие окна и уведомления (overlay, notification) живут своим циклом: переход маршрута их не закрывает.

Рекомендация по разметке

Размещайте целевые контейнеры для вставок внутри компонентов приложения, а не в общем каркасе страницы. Тогда фреймворк сам удалит вставку при смене маршрута, а ядро это увидит и корректно вставит блок заново. Контейнеры, живущие вне зоны перерисовки, приходится снимать по результату перепроверки таргетинга — это работает, но менее предсказуемо.

Очистка эффектов из кода кампании

Если JS-код кампании навешивает обработчики, заводит таймеры или меняет что-то за пределами своего блока, зарегистрируйте функцию очистки:

GF.Utils.onCampaignRemove('ИДЕНТИФИКАТОР_КАМПАНИИ', function () {
  // снять обработчики, остановить таймеры и т.п.
});

Она вызовется один раз, когда вставка кампании будет удалена или заменена — при смене маршрута или при повторном показе. При новом показе код кампании выполнится заново и может зарегистрировать хук снова.

Если кампания не перезапустилась

  • Не включён режим SPA у кампании или плейсмента — самая частая причина.

  • Не отправлено событие spa для этого перехода либо в нём не обновлён context.

  • Условия таргетинга не подходят новому контексту.

  • Предыдущий запуск ещё ждёт свой триггер — например, кампания с триггером «время на странице» или «событие», который так и не сработал. Пока триггер занят, повторный запуск на этом переходе пропускается.

  • На первой странице ничего не показалось при isSpa: true — стартовое событие spa не дошло до ядра; проверьте, что в сниппете есть очередь GF.q.

Подробный лог решений по каждой кампании включается в консоли:

GF.Log.enable();   // затем совершить переход
GF.Log.disable();