Реализация динамического контента на лендинге по UTM-меткам

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация динамического контента на лендинге по UTM-меткам
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Реализация динамического контента на лендинге по UTM-меткам

Лендинг с динамическим контентом по UTM — это один URL, который показывает разный текст, изображения и офферы в зависимости от рекламной кампании, которая привела пользователя. Вместо создания десятков отдельных посадочных страниц для каждой кампании достаточно настроить замену контентных блоков на основе параметров URL.

Извлечение и хранение UTM-параметров

Параметры нужно читать при загрузке страницы и сохранять — они пропадают при переходах по внутренним ссылкам:

function extractUtmParams(): Record<string, string> {
  const params = new URLSearchParams(location.search);
  const utm: Record<string, string> = {};

  ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'].forEach(key => {
    const val = params.get(key);
    if (val) utm[key] = val;
  });

  return utm;
}

function saveAndGetUtm(): Record<string, string> {
  const fromUrl = extractUtmParams();

  if (Object.keys(fromUrl).length > 0) {
    sessionStorage.setItem('utm', JSON.stringify(fromUrl));
    return fromUrl;
  }

  // Возвращаемся — параметров в URL нет, берём из сессии
  return JSON.parse(sessionStorage.getItem('utm') ?? '{}');
}

const utm = saveAndGetUtm();

Карта замен контента

Создаётся JSON-конфиг (может лежать в файле, в CMS или в базе) — правила подстановки контента:

const contentMap = {
  // По utm_campaign
  campaigns: {
    'google-search-brand': {
      hero_title: 'Официальный сайт — лучший выбор для вашего бизнеса',
      hero_subtitle: 'Прямые поставки. Без посредников.',
      cta_text: 'Получить персональное предложение',
      badge: 'Официальный партнёр',
    },
    'facebook-retargeting-cart': {
      hero_title: 'Вы забыли кое-что важное',
      hero_subtitle: 'Ваша корзина ждёт — завершите заказ сегодня.',
      cta_text: 'Вернуться к корзине',
      cta_url: '/cart',
    },
    'email-promo-march': {
      hero_title: 'Спецпредложение для подписчиков',
      hero_subtitle: 'Скидка 15% действует до конца месяца.',
      cta_text: 'Активировать скидку',
      badge: '-15%',
    },
  },

  // По utm_source (фолбэк если нет совпадения по кампании)
  sources: {
    'yandex': {
      hero_title: 'Нашли нас в Яндексе? Правильный выбор.',
      cta_text: 'Узнать подробнее',
    },
    'vk': {
      hero_title: 'Добро пожаловать из ВКонтакте',
      cta_text: 'Смотреть каталог',
    },
  },

  // Дефолт
  default: {
    hero_title: 'Решение для вашего бизнеса',
    hero_subtitle: 'Надёжно, быстро, без лишних затрат.',
    cta_text: 'Начать работу',
  },
};

function getContent(utm: Record<string, string>) {
  return contentMap.campaigns[utm.utm_campaign]
    ?? contentMap.sources[utm.utm_source]
    ?? contentMap.default;
}

Замена DOM-элементов

Атрибуты data-utm-key указывают, какое поле контента подставлять в элемент:

<h1 data-utm-key="hero_title">Решение для вашего бизнеса</h1>
<p data-utm-key="hero_subtitle">Надёжно, быстро, без лишних затрат.</p>
<a href="/start" data-utm-key="cta_text" data-utm-href="cta_url" id="main-cta">
  Начать работу
</a>
<span class="badge" data-utm-key="badge" data-utm-hide-if-empty="true"></span>
function applyDynamicContent(content: Record<string, string>): void {
  document.querySelectorAll('[data-utm-key]').forEach(el => {
    const key = el.getAttribute('data-utm-key')!;
    const value = content[key];

    if (!value) {
      if (el.getAttribute('data-utm-hide-if-empty') === 'true') {
        (el as HTMLElement).style.display = 'none';
      }
      return;
    }

    el.textContent = value;

    const hrefKey = el.getAttribute('data-utm-href');
    if (hrefKey && content[hrefKey]) {
      (el as HTMLAnchorElement).href = content[hrefKey];
    }
  });
}

// Запуск при загрузке
const content = getContent(utm);
applyDynamicContent(content);

Замена происходит до первого рендера если скрипт стоит в <head> с атрибутом defer, или сразу в конце <body>. При SSR лучше передавать UTM на сервер и рендерить нужный вариант сразу.

SSR-вариант на PHP/Laravel

// В Blade-шаблоне
@php
$utm = [
    'utm_source'   => request('utm_source') ?? session('utm_source'),
    'utm_campaign' => request('utm_campaign') ?? session('utm_campaign'),
];

// Сохраняем в сессию при первом посещении
if (request('utm_source')) {
    session(['utm_source' => request('utm_source')]);
    session(['utm_campaign' => request('utm_campaign')]);
}

$content = App\Services\UtmContentService::resolve($utm);
@endphp

<h1>{{ $content['hero_title'] }}</h1>
<p>{{ $content['hero_subtitle'] }}</p>
<a href="{{ $content['cta_url'] ?? '/start' }}">{{ $content['cta_text'] }}</a>

SSR-подход не вызывает мерцания контента (flash of default content) — пользователь сразу получает персонализированную версию.

Трекинг эффективности вариантов

// Отправляем в GA4 какой вариант видит пользователь
gtag('event', 'utm_content_variant', {
  utm_campaign: utm.utm_campaign ?? 'none',
  utm_source: utm.utm_source ?? 'direct',
  variant_key: utm.utm_campaign ?? utm.utm_source ?? 'default',
  hero_title: content.hero_title?.substring(0, 50),
});

// На клик по CTA
document.getElementById('main-cta')?.addEventListener('click', () => {
  gtag('event', 'utm_cta_click', {
    cta_text: content.cta_text,
    utm_campaign: utm.utm_campaign,
  });
});

В GA4 строится сегментация по utm_content_variant — видно, какие кампании приводят к кликам по CTA, а какие заканчиваются отказом.

Сроки

JS-замена контента с картой кампаний до 20 вариантов: 4–6 часов. SSR-версия на PHP с сессионным хранением UTM: 3–4 часа. Трекинг вариантов в GA4 с сегментацией: 2 часа. Интеграция с CMS (редактор вариантов в админке): 1–2 дня.