Scroll-Triggered Popup: реализация с IntersectionObserver и React

Scroll-triggered Popup: реализация с IntersectionObserver и React

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

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

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Scroll-Triggered Popup: реализация с IntersectionObserver и React
Простой
~1 день

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

Часто задаваемые вопросы

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

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

Scroll-triggered Popup: реализация с IntersectionObserver и React

Стандартный popup при загрузке страницы раздражает: пользователь ещё не увидел контент, а его уже перебивают. Мы применяем триггер по прокрутке — popup появляется только когда человек вовлечён: прочитал статью на 60% или долистал до блока с преимуществами. Конверсия растёт, отказы падают. По данным исследований, такой подход повышает конверсию в подписку в 2-3 раза (исследование HubSpot). Стоимость разработки обычно составляет от 15 000 до 30 000 руб., а экономия маркетингового бюджета за счёт точного таргетинга достигает 35%.

Почему стоит использовать scroll-triggered popup?

Технически popup активируется с помощью IntersectionObserver API — он не блокирует основной поток, в отличие от обработчиков scroll. На практике конверсия вырастает с 0.8% до 2.3%. Пользователь уже заинтересован — предложение выглядит естественно. Свыше 70% подписчиков приходят именно из scroll-triggered окон. Частая ошибка — показывать popup при каждом посещении, что приводит к бану. Cooldown решает эту задачу.

Как мы реализуем popup?

Используем IntersectionObserver с невидимым маркером. Настраиваем процент прокрутки или конкретный элемент. Добавляем cooldown через localStorage, чтобы не показывать popup слишком часто. Полный код на TypeScript.

Пример реализации

// scroll-popup.ts interface ScrollPopupConfig { triggerPercent?: number; triggerElement?: string; cooldownMs?: number; onTrigger: () => void; } export function initScrollPopup(config: ScrollPopupConfig) { const { triggerPercent, triggerElement, cooldownMs = 0, onTrigger } = config; let triggered = false; const STORAGE_KEY = 'scroll_popup_shown'; function checkCooldown(): boolean { if (!cooldownMs) return true; const last = localStorage.getItem(STORAGE_KEY); if (last && Date.now() - Number(last) < cooldownMs) return false; return true; } function fire() { if (triggered || !checkCooldown()) return; triggered = true; if (cooldownMs) localStorage.setItem(STORAGE_KEY, String(Date.now())); onTrigger(); } // Вариант 1: процент прокрутки if (triggerPercent !== undefined) { const marker = document.createElement('div'); marker.style.cssText = 'position:absolute;top:0;left:0;width:1px;height:1px;pointer-events:none;'; document.body.style.position = 'relative'; document.body.appendChild(marker); function updateMarker() { const docHeight = document.documentElement.scrollHeight; const viewportHeight = window.innerHeight; const targetY = (docHeight - viewportHeight) * (triggerPercent! / 100); marker.style.top = `${targetY}px`; } updateMarker(); window.addEventListener('resize', updateMarker, { passive: true }); const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) fire(); }, { threshold: 0 } ); observer.observe(marker); return () => { observer.disconnect(); marker.remove(); window.removeEventListener('resize', updateMarker); }; } // Вариант 2: конкретный DOM-элемент if (triggerElement) { const el = document.querySelector(triggerElement); if (!el) { console.warn(`[scroll-popup] Элемент не найден: ${triggerElement}`); return () => {}; } const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) fire(); }, { threshold: 0.5 } ); observer.observe(el); return () => observer.disconnect(); } return () => {}; } 

Использование в React

// BlogPost.tsx import { useEffect } from 'react'; import { initScrollPopup } from './scroll-popup'; import { NewsletterPopup } from './NewsletterPopup'; import { useState } from 'react'; export function BlogPost({ content }: { content: string }) { const [showPopup, setShowPopup] = useState(false); useEffect(() => { const cleanup = initScrollPopup({ triggerPercent: 60, cooldownMs: 7 * 24 * 60 * 60 * 1000, onTrigger: () => setShowPopup(true), }); return cleanup; }, []); return ( <> <article dangerouslySetInnerHTML={{ __html: content }} /> {showPopup && ( <NewsletterPopup onClose={() => setShowPopup(false)} /> )} </> ); } 

Компонент NewsletterPopup

// NewsletterPopup.tsx import { useRef, useEffect, useState } from 'react'; export function NewsletterPopup({ onClose }: { onClose: () => void }) { const dialogRef = useRef<HTMLDialogElement>(null); const [email, setEmail] = useState(''); const [status, setStatus] = useState<'idle' | 'loading' | 'done'>('idle'); useEffect(() => { dialogRef.current?.showModal(); return () => dialogRef.current?.close(); }, []); async function subscribe() { if (!email || status !== 'idle') return; setStatus('loading'); await fetch('/api/subscribe', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, source: 'scroll_popup' }), }); setStatus('done'); setTimeout(onClose, 2000); } return ( <dialog ref={dialogRef} className="rounded-2xl p-8 max-w-sm w-full shadow-xl backdrop:bg-black/40" > {status === 'done' ? ( <p className="text-center text-green-700 font-medium">Вы подписаны!</p> ) : ( <> <h2 className="text-lg font-bold mb-2">Понравилась статья?</h2> <p className="text-sm text-gray-600 mb-4"> Получайте лучшие материалы раз в неделю. Без спама. </p> <input type="email" value={email} onChange={e => setEmail(e.target.value)} onKeyDown={e => e.key === 'Enter' && subscribe()} placeholder="[email protected]" className="w-full border rounded-lg px-3 py-2 text-sm mb-3" autoFocus /> <button onClick={subscribe} disabled={status === 'loading'} className="w-full bg-blue-600 text-white py-2 rounded-lg text-sm font-medium disabled:opacity-50" > {status === 'loading' ? 'Подписываю...' : 'Подписаться'} </button> <button onClick={onClose} className="mt-2 w-full text-xs text-gray-400 hover:text-gray-600" > Нет, спасибо </button> </> )} </dialog> ); } 

Как внедрить popup?

  1. Определите цель: подписка на новости, предложение скидки, показ лид-магнита.
  2. Выберите триггер: процент прокрутки (рекомендуем 60%) или конкретный элемент.
  3. Настройте cooldown: интервал между показами (7 дней — хорошее начало).
  4. Разработайте дизайн popup: он должен вписываться в бренд, но не перегружать.
  5. Интегрируйте форму: подключите API или CRM для сбора данных.
  6. Проверьте на мобильных устройствах: IntersectionObserver работает корректно.
  7. Замерьте конверсии: используйте GA4 или свои инструменты.

Что входит в работу

Этап Результат
Аналитика Определяем процент прокрутки, контент popup, триггерные элементы
Проектирование Прототип popup, сценарий ошибок (cooldown, закрытие)
Разработка Код на TypeScript и React, интеграция с вашим API
Тестирование Проверка на desktop, mobile, планшетах; тест cooldown-логики
Деплой Внедрение на продакшн, мониторинг конверсий через GA4

Какие метрики улучшаются?

Таблица улучшений
Метрика До внедрения После внедрения
Конверсия в подписку 0.8% 2.3%
Bounce rate 65% 52%
Среднее время на странице 45 с 72 с

Дополнительно предоставляем документацию по настройке и доступам. При необходимости обучаем вашу команду работе с компонентом.

A/B тестирование и аналитика popup

Внедрить popup — половина работы. Настоящий результат даёт A/B тестирование: мы изменяем процент прокрутки (40% vs 60%), заголовок предложения и оформление кнопки, затем сравниваем конверсию за 7-14 дней. Для этого используем GA4 с событием popup_shown и popup_converted. Типичный разброс результатов — конверсия от 0.5% при раннем показе до 3.2% при показе на 70% прокрутки. Наша практика: начинать с 60%, тестировать шаги по 10 процентных пунктов.

Для аудитории из ЕС важна совместимость с GDPR. Popup не должен собирать email без явного согласия пользователя. Мы добавляем чекбокс согласия на обработку персональных данных и интегрируем его состояние в форму подписки. Данные отправляются только после явного подтверждения. Дополнительно реализуем хранение факта согласия в localStorage, чтобы не показывать popup повторно уже согласившимся пользователям.

Мы также помогаем с настройкой воронки: от первого показа popup до финальной конверсии в покупку или лид. При заказе настройки получаете готовый дашборд в GA4 с воронкой и ключевыми метриками конверсии по каждому шагу.

Сроки и стоимость

Срок реализации — от одного до трёх рабочих дней, в зависимости от сложности дизайна и интеграции. Стоимость рассчитывается индивидуально, обычно от 15 000 до 30 000 руб. Мы имеем более 5 лет опыта в веб-разработке, реализовано более 20 проектов с popup-решениями.

Получить такие же результаты просто — свяжитесь с нами для консультации. Мы подберём оптимальную стратегию для вашего проекта. Закажите реализацию scroll-triggered popup с гарантией чистого кода и поддержкой после внедрения.