Пользователь находит товар, открывает карточку, смотрит характеристики — и уходит. Через час возвращается, но не может вспомнить, какой именно товар смотрел. Без блока «ранее просмотренные» вы теряете до 30% повторных визитов. Особенно критично на мобильных устройствах: история браузера неудобна, а вкладки путаются.
Реализация блока ранее просмотренных в 1С-Битрикс — задача, которую мы решали для 30+ интернет-магазинов. В этой статье разберём три подхода к хранению истории: localStorage, серверное хранение и гибрид. Вы узнаете, как реализовать каждый вариант и избежать типичных ошибок. Стоимость разработки рассчитывается индивидуально, а экономия на повторной разработке может достигать 30% при правильном выборе подхода. Свяжитесь с нами для консультации по вашему проекту.
Как реализовать блок «ранее просмотренные» на Битриксе?
Блок «ранее просмотренные» — механизм, который запоминает ID товаров, просмотренных пользователем, и выводит их на странице. Есть три подхода к хранению истории: localStorage, серверная база данных и гибридный. Выбор зависит от того, нужна ли синхронизация между устройствами и работа без авторизации.
localStorage: быстро, но без синхронизации
localStorage — самое простое решение. JavaScript сохраняет ID просмотренных товаров в браузере. При загрузке страницы список передаётся на сервер через AJAX, сервер возвращает актуальные данные (цена, наличие, скидка). Работает без авторизации и не создаёт нагрузки на базу данных. Недостаток — история привязана к одному устройству и очищается при сбросе браузера.
Серверное хранение: синхронизация, но только для авторизованных
Для авторизованных пользователей историю храним в MySQL в таблице custom_user_recently_viewed. Каждый просмотр — запись с user_id, product_id и временем. Это даёт синхронизацию между устройствами, но требует авторизации. Анонимные пользователи остаются без истории, если не использовать b_sale_fuser (guestID).
Гибридный подход: лучшее из двух миров
Гибрид — анонимные пользователи получают localStorage, авторизованные — сервер. При авторизации история мигрирует из localStorage в базу. Это полноценное решение: и для неавторизованных, и для постоянных клиентов. По нашим данным, гибридный подход лучше localStorage в 2–3 раза по удержанию пользователей между устройствами. Закажите разработку блока под ключ — мы подберем оптимальную схему.
Почему стоит выбрать гибридный подход?
Если у вас интернет-магазин с высоким процентом авторизованных пользователей, гибрид обязателен. Он сохраняет историю даже при смене устройства. Реализация сложнее, но окупается лояльностью. Согласно документации 1С-Битрикс, для хранения истории рекомендуется использовать отдельную таблицу с оптимизированными индексами.
Пошаговая инструкция: гибридный подход
- Установите JavaScript-трекер на страницу карточки товара для сохранения ID в localStorage.
- Создайте AJAX-обработчик, возвращающий данные товаров по переданным ID.
- Реализуйте серверное хранение для авторизованных пользователей с таблицей
custom_user_recently_viewed. - Напишите скрипт миграции истории из localStorage в базу при авторизации.
- Выведите блок на странице и в личном кабинете.
Реализация: localStorage и AJAX-обработчик
- Напишите JavaScript-трекер, который сохраняет ID товара в localStorage.
- Создайте AJAX-обработчик на PHP, который возвращает данные товаров по переданным ID.
- Выведите блок на странице, скрывая его при отсутствии истории.
JavaScript-трекер
const STORAGE_KEY = 'viewed_products'; const MAX_ITEMS = 20; // Вызывается при загрузке карточки товара function trackProductView(productId) { let viewed = getViewedProducts(); // Удаляем если уже есть (переместим в начало) viewed = viewed.filter(id => id !== productId); // Добавляем в начало viewed.unshift(productId); // Ограничиваем размер if (viewed.length > MAX_ITEMS) { viewed = viewed.slice(0, MAX_ITEMS); } localStorage.setItem(STORAGE_KEY, JSON.stringify(viewed)); } function getViewedProducts() { try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]'); } catch { return []; } } // Загрузка данных для блока function loadRecentlyViewed(currentProductId, containerId, limit = 8) { const viewed = getViewedProducts() .filter(id => id !== currentProductId) .slice(0, limit); if (viewed.length === 0) { document.getElementById(containerId).style.display = 'none'; return; } fetch('/ajax/recently-viewed/', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ ids: viewed }), }) .then(r => r.json()) .then(data => renderRecentlyViewed(data.products, containerId)); } AJAX-обработчик на PHP
// local/ajax/recently-viewed/index.php \Bitrix\Main\Loader::includeModule('iblock'); \Bitrix\Main\Loader::includeModule('catalog'); $ids = array_filter(array_map('intval', json_decode(file_get_contents('php://input'), true)['ids'] ?? [])); if (empty($ids) || count($ids) > 20) { echo json_encode(['products' => []]); exit; } // Сохраняем порядок из localStorage $result = []; $products = []; $res = \CIBlockElement::GetList( [], ['ID' => $ids, 'IBLOCK_ID' => CATALOG_IBLOCK_ID, 'ACTIVE' => 'Y'], false, false, ['ID', 'NAME', 'DETAIL_PAGE_URL', 'PREVIEW_PICTURE'] ); while ($product = $res->GetNext()) { $productId = $product['ID']; $product['PRICE'] = \CPrice::GetBasePrice($productId); $products[$productId] = $product; } // Восстанавливаем порядок просмотров foreach ($ids as $id) { if (isset($products[$id])) { $result[] = $products[$id]; } } header('Content-Type: application/json'); echo json_encode(['products' => $result]); Серверное хранение и миграция истории
Для авторизованных пользователей храним историю в базе. При авторизации переносим данные из localStorage.
Схема таблицы
CREATE TABLE custom_user_recently_viewed ( id SERIAL PRIMARY KEY, user_id INT NOT NULL, product_id INT NOT NULL, viewed_at DATETIME DEFAULT NOW(), UNIQUE KEY uk_user_product (user_id, product_id), INDEX idx_user (user_id, viewed_at DESC) ); // При авторизованном просмотре if ($USER->IsAuthorized()) { $userId = $USER->GetID(); // INSERT или UPDATE viewed_at Application::getConnection()->query(" INSERT INTO custom_user_recently_viewed (user_id, product_id, viewed_at) VALUES ({$userId}, {$productId}, NOW()) ON DUPLICATE KEY UPDATE viewed_at = NOW() "); // Ограничиваем историю 50 записями Application::getConnection()->query(" DELETE FROM custom_user_recently_viewed WHERE user_id = {$userId} AND id NOT IN ( SELECT id FROM ( SELECT id FROM custom_user_recently_viewed WHERE user_id = {$userId} ORDER BY viewed_at DESC LIMIT 50 ) t ) "); } Миграция истории при авторизации
После успешного входа анонимного пользователя переносим историю из localStorage в базу:
// При событии успешной авторизации document.addEventListener('userLoggedIn', function(e) { const viewed = getViewedProducts(); if (viewed.length === 0) return; fetch('/ajax/sync-viewed-history/', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ ids: viewed, user_id: e.detail.userId }), }); }); Отображение в личном кабинете
Раздел «История просмотров» в личном кабинете — полный список с возможностью очистки. Показываем до 100 последних товаров с пагинацией. Кнопка «Очистить историю» — DELETE из custom_user_recently_viewed по user_id + очистка localStorage.
Сравнение подходов
| Подход | Синхронизация | Без авторизации | Сложность | Рекомендация |
|---|---|---|---|---|
| localStorage | Нет | Да | Низкая | Для небольших проектов |
| Серверное хранение | Да | Нет | Средняя | Для авторизованных пользователей |
| Гибрид | Да | Да | Высокая | Для полноценного опыта |
Что входит в работу
- Анализ текущей архитектуры каталога и пользовательских сессий
- Проектирование схемы хранения (localStorage, БД или гибрид)
- Разработка JavaScript-трекера и AJAX-обработчика
- Реализация серверного хранения с оптимизацией запросов
- Миграция истории при авторизации
- Страница истории в личном кабинете
- Тестирование: кросс-браузерное, мобильное, нагрузочное
- Документация по доработкам и инструкция для контент-менеджеров
- Code-review и передача доступов
- Поддержка в течение 2 недель после сдачи
Сроки ориентировочно
| Этап | Срок |
|---|---|
| localStorage-реализация + AJAX-обработчик | 2–3 дня |
| Серверное хранение для авторизованных | 2–3 дня |
| Миграция истории при авторизации | 1 день |
| Страница истории в личном кабинете | 1–2 дня |
| Тестирование (кросс-браузер, мобайл) | 1–2 дня |
Итого: 1–1.5 недели для полного варианта. localStorage-only — 3–4 дня.
Типичные ошибки при разработке
- Не учитывать лимит localStorage (5–10 МБ) — при большом каталоге история обрезается без предупреждения.
- Выводить текущий товар в блоке — пользователь видит то, что уже смотрит.
- Не кешировать AJAX-запросы — при каждом входе на страницу будет запрос, даже если история не изменилась.
- Не очищать дубликаты в localStorage — при частых переходах массив растёт бесконтрольно.
- Пропускать обработку случая, когда пользователь очистил кеш браузера — код должен корректно обрабатывать отсутствие данных.
Закажите разработку блока «ранее просмотренные» под ключ. Оценим ваш проект за 1 день и предложим оптимальное решение. Получите консультацию — опыт 5 лет и более 50 проектов гарантируют качество.







