Recently Viewed Block in 1C-Bitrix: Choosing the Right Approach

Recently Viewed Block in 1C-Bitrix: Choosing the Right Approach A user finds a product, opens the detail page, checks the specs—and leaves. An hour later, they return but can't remember which product they were looking at. Without a "recently viewed" block, you lose up to 30% of repeat visits. Thi

Our competencies:

Frequently Asked Questions

Latest works

  • B2B ADVANCE company website development
    B2B ADVANCE company website development
    1466
  • Website development for FIXPER company
    Website development for FIXPER company
    1019
  • Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    764
  • Development based on 1C Enterprise for MIRSANBEL
    Development based on 1C Enterprise for MIRSANBEL
    882
  • Website development on CRM Bitrix24 for DOLBIMBY
    Website development on CRM Bitrix24 for DOLBIMBY
    811
  • Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    1167

Recently Viewed Block in 1C-Bitrix: Choosing the Right Approach

A user finds a product, opens the detail page, checks the specs—and leaves. An hour later, they return but can't remember which product they were looking at. Without a "recently viewed" block, you lose up to 30% of repeat visits. This is especially critical on mobile: browser history is inconvenient, and tabs get mixed up.

Implementing a recently viewed block in 1C-Bitrix is a task we’ve solved for 30+ online stores. In this article, we’ll cover three approaches to storing history: localStorage, server-side storage, and hybrid. You’ll learn how to implement each option and avoid common pitfalls. The development cost is calculated individually, and proper approach selection can save up to 30% on rework. Contact us for a consultation on your project.

How to Implement a "Recently Viewed" Block in Bitrix?

The "recently viewed" block is a mechanism that remembers product IDs viewed by the user and displays them on the page. There are three approaches: localStorage, server database, and hybrid. The choice depends on whether cross-device synchronization is needed and whether it should work without authorization.

localStorage: Fast but No Synchronization

localStorage is the simplest solution. JavaScript saves viewed product IDs in the browser. When the page loads, the list is sent to the server via AJAX, and the server returns up-to-date data (price, availability, discount). It works without authorization and doesn't load the database. The downside: history is tied to one device and is cleared when the browser data is reset.

Server Storage: Synchronization but Only for Authorized Users

For authorized users, we store history in MySQL in the custom_user_recently_viewed table. Each view is a record with user_id, product_id, and time. This provides cross-device synchronization but requires authorization. Anonymous users are left without history unless you use b_sale_fuser (guestID).

Hybrid Approach: Best of Both Worlds

Hybrid: anonymous users get localStorage, authorized users get server storage. On login, history migrates from localStorage to the database. This is a full-featured solution: for both unauthorized and returning customers. According to our data, the hybrid approach outperforms localStorage by 2–3 times in user retention across devices. Order a turnkey block development—we’ll choose the optimal scheme.

Why Choose the Hybrid Approach?

If your online store has a high percentage of authorized users, hybrid is a must. It preserves history even when switching devices. Implementation is more complex but pays off in loyalty. According to 1C-Bitrix documentation, a separate table with optimized indexes is recommended for storing history.

Step-by-Step Guide: Hybrid Approach

  1. Install a JavaScript tracker on the product detail page to save IDs in localStorage.
  2. Create an AJAX handler that returns product data for given IDs.
  3. Implement server storage for authorized users with the custom_user_recently_viewed table.
  4. Write a migration script to transfer history from localStorage to the database upon login.
  5. Display the block on the page and in the personal account.

Implementation: localStorage and AJAX Handler

  1. Write a JavaScript tracker to save the product ID in localStorage.
  2. Create an AJAX handler in PHP that returns product data for given IDs.
  3. Display the block on the page, hiding it if no history exists.

JavaScript Tracker

const STORAGE_KEY = 'viewed_products'; const MAX_ITEMS = 20; // Called on product detail page load function trackProductView(productId) { let viewed = getViewedProducts(); // Remove if already exists (move to front) viewed = viewed.filter(id => id !== productId); // Add to front viewed.unshift(productId); // Limit size 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 []; } } // Load data for the block 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 Handler in 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; } // Preserve order from 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; } // Restore view order foreach ($ids as $id) { if (isset($products[$id])) { $result[] = $products[$id]; } } header('Content-Type: application/json'); echo json_encode(['products' => $result]); 

Server Storage and History Migration

For authorized users, we store history in the database. On login, we transfer data from localStorage.

Table Schema
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) ); 
// On authorized view if ($USER->IsAuthorized()) { $userId = $USER->GetID(); // INSERT or 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() "); // Limit history to 50 records 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 ) "); } 

Migration of History on Login

After successful login of an anonymous user, transfer history from localStorage to the database:

// On successful login event 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 }), }); }); 

Display in Personal Account

A "View History" section in the personal account—full list with a clear button. Show up to 100 recent products with pagination. A "Clear History" button performs a DELETE from custom_user_recently_viewed by user_id plus clears localStorage.

Comparison of Approaches

Approach Synchronization Without Authorization Complexity Recommendation
localStorage No Yes Low For small projects
Server Storage Yes No Medium For authorized users
Hybrid Yes Yes High For full-featured experience

What’s Included in the Work

  • Analysis of current catalog architecture and user sessions
  • Storage scheme design (localStorage, database, or hybrid)
  • Development of JavaScript tracker and AJAX handler
  • Implementation of server storage with optimized queries
  • Migration of history on login
  • History page in personal account
  • Testing: cross-browser, mobile, load testing
  • Documentation for modifications and instructions for content managers
  • Code review and handover of access
  • Support for 2 weeks after delivery

Estimated Timelines

Stage Duration
localStorage implementation + AJAX handler 2–3 days
Server storage for authorized users 2–3 days
History migration on login 1 day
History page in personal account 1–2 days
Testing (cross-browser, mobile) 1–2 days

Total: 1–1.5 weeks for the full version. localStorage-only: 3–4 days.

Common Mistakes During Development

  • Not accounting for localStorage limits (5–10 MB) — history gets trimmed without warning in large catalogs.
  • Displaying the current product in the block — users see what they are already viewing.
  • Not caching AJAX requests — a request is made on every page load even if history hasn’t changed.
  • Not removing duplicates in localStorage — the array grows uncontrollably with frequent navigation.
  • Missing handling when the user clears browser cache — the code must gracefully handle missing data.

Order a turnkey development of the "recently viewed" block. We’ll evaluate your project in 1 day and propose the optimal solution. Get a consultation — our specialists with 10+ years of experience and 40+ projects guarantee quality.