Walk past two restaurants with identical menus and you'll pick the busy one without thinking about it. Online, the customer can't see the queue — so the product page has to tell them. "847 sold" or "32 people viewing right now," sitting next to the Add to Cart button, does for a product what a full dining room does for a restaurant: it tells a hesitating buyer that other people already made this decision and were fine. This post is specifically about the live, per-product version of that signal on a PrestaShop product page — the sales count and the view count that update for the actual product the customer is looking at, not a store-wide badge and not a corner popup.

Last updated: June 2026.

Two close cousins are worth separating out before we start, because mixing them up is where most merchants get the implementation wrong. A site-wide "12,400 products sold" trust number is a different tool with a different job — that's covered in total products sold counter. A floating "Someone in Kraków just bought this" toast is a different format again — see sales popup and the question of whether those toasts actually move the needle in live sales notifications. This post stays on the one thing those don't do: inline per-product numbers, drawn from your real order and visit data, rendered on the product page itself.

The two numbers, and what each one actually says

A product on a pedestal flanked by two glowing glass badges, an eye icon for views and a cart icon for sales
Views and sales tell two different stories; shown together on a product page, they nudge undecided shoppers.

Sales count and view count look similar but do opposite psychological work, and that difference decides where you'd use each.

SignalExampleWhat it tells the buyerStrongest on
Lifetime sales"1,247 sold"Proven choice — over a thousand people committed money to thisHigh-value or unfamiliar-brand items where the customer fears making the wrong call
Recent sales"23 sold in the last 7 days"Current demand — this isn't a stale listing, it's selling nowFast-moving consumables, trend items, anything where "is this still relevant?" is a real doubt
Live viewers"32 people viewing this now"Competition — you're not the only one eyeing it, decideLimited-stock items, flash sales, single-unit/vintage products
Today's views"156 viewed today"Interest without the pressure of a live counterMid-traffic stores where a real-time number would look thin

So what? Lifetime sales reassure; recent activity and live viewers create gentle urgency. A nervous buyer on a €600 item wants reassurance — show the lifetime count. A bargain-hunter on a discounted accessory responds to "7 sold today." Showing the wrong one for the context is why some merchants try counters, see nothing, and conclude social proof "doesn't work." It works; the number has to match the doubt.

One thing this post deliberately leaves out: star ratings and review counts are social proof too, but they're a separate system with their own moderation, spam, and SEO concerns — that's built-in vs third-party reviews, not this.

Where PrestaShop already keeps these numbers

The good news is that PrestaShop is already recording most of what you need — it just doesn't surface it on the front office. Knowing where the data lives tells you what's a query versus what needs new tracking.

Sales are already in the database. Every line item lives in ps_order_detail (the product_id and product_quantity columns), joined to ps_orders for the date and order state. A lifetime sales count for a product is a SUM(product_quantity) over ps_order_detail for that product_id; a "last 7 days" count adds a WHERE on the order's date_add. The decision that matters here is which order states count. Counting every cart that ever reached a placeholder state will inflate the number and arguably make it a lie; most merchants count only valid/paid states. PrestaShop also maintains a separate ps_product_sale table (the quantity column, surfaced as sales in best-seller queries) — a denormalised sales aggregate that PrestaShop maintains when orders are validated — but when you need custom order-state or date logic, querying ps_order_detail directly with explicit valid states may be preferable to the cached total.

The lifetime-sales read is a single query. PrestaShop sets ps_orders.valid = 1 when an order reaches a paid/accepted state, so joining on that flag is the honest way to count only orders that really happened (adjust the ps_ prefix to your install). This is read-only — it changes nothing:

-- Lifetime units sold for one product, counting only valid orders
SELECT SUM(od.product_quantity) AS units_sold
FROM ps_order_detail od
JOIN ps_orders o ON o.id_order = od.id_order
WHERE od.product_id = 123      -- the product you're displaying
  AND o.valid = 1;

-- "Sold in the last 7 days" — same query, with a date window
SELECT SUM(od.product_quantity) AS units_7d
FROM ps_order_detail od
JOIN ps_orders o ON o.id_order = od.id_order
WHERE od.product_id = 123
  AND o.valid = 1
  AND o.date_add >= DATE_SUB(NOW(), INTERVAL 7 DAY);

Run those in Advanced Parameters → Database → SQL Manager to sanity-check a product's real numbers before you ever put a counter on the page — if the honest figure is small, that's the product to leave the counter off.

Views are partly there, partly not. PrestaShop already counts page views per day in ps_page_viewed (joined through ps_page / ps_page_type to resolve which product a "product" page hit belongs to) — that's the data used by PrestaShop stats modules, such as Best viewed products when the stats module is installed/enabled. So "viewed today / this week" can be read straight from existing tables. What PrestaShop does not track natively is the live, concurrent "X people viewing now" — there's no built-in session-presence counter. That number requires its own lightweight tracking: a small AJAX heartbeat that registers a session against a product and expires it after a couple of minutes of silence. Worth knowing before you promise yourself a real-time counter — half of it is a SQL query, the other half is something you have to build or buy.

Getting it onto the product page — the PrestaShop-specific part

However you generate the numbers, they have to render in the right place in the theme, and PrestaShop gives you clean hooks so you never have to edit core files (which an upgrade would overwrite anyway).

  • displayProductPriceBlock — fires around the price area, with a $type you can check ('after_price', 'weight', etc.). This is where a sales count belongs: right next to the price, in the customer's primary line of sight.
  • displayProductButtons / displayProductActions — next to Add to Cart, the natural home for a "32 viewing now" urgency line because it's the last thing read before the click.
  • displayProductAdditionalInfo — below the buy box, a calmer slot for "156 viewed today" where it informs without shouting.

The cleaner pattern is a module that registers these hooks and ships its own .tpl templates, so a theme update doesn't blow your changes away and disabling the module cleanly removes the feature. The alternative — editing product.tpl (or the templates/catalog/_partials/ partials in 1.7+ themes) directly — works but couples the feature to one theme and one version, and you'll re-do it at the next upgrade. If you're touching the product template for this, it's worth reading the broader layout logic first: product page design best practices and what actually drives the click in product page anatomy.

One performance note that matters at scale: a naive implementation runs a fresh COUNT/SUM against the order tables on every single product-page load. On a busy catalogue that's real database pressure for a number that doesn't need to be exact to the second. Cache it — compute counts on a schedule (hourly is plenty for lifetime figures) or use PrestaShop's cache layer — and read the cached value on render. "Lightweight and cached" is the difference between a feature that helps conversion and one that drags your page speed down on the very page where speed matters most.

The honesty rules — and why per-product display makes them strict

This is where displaying numbers on a specific product is unforgiving in a way a store-wide badge isn't. A site total of "12,400 sold" can quietly absorb a few weak products. An inline counter sits on each product individually, so every awkward number is exposed.

  • Set a display threshold. Show "X sold" only above a floor — 50, 100, whatever fits your volume. "3 sold" under a price doesn't read as proof; it reads as "nobody's buying this," which is worse than showing nothing. Below the threshold, hide the counter entirely. A good module exposes this as a setting so you set it once.
  • Never fabricate. No invented "fake-base + real" view counts, no "only 2 left!" on a product with 400 in stock, no randomised "people viewing" that resets on refresh. Customers screenshot and compare; getting caught manufacturing scarcity does lasting reputation damage, and it's increasingly easy to spot. If the real traffic isn't there, don't show the viewer count on that product — show it only on your genuinely busy ones.
  • Match the number to real activity. "Viewed today" should reflect actual ps_page_viewed data, not a multiplier. The whole value of inline stats is that they're true; the moment a savvy customer suspects one number is invented, every other number on your page — price, stock, reviews — inherits the doubt.

If your honest numbers aren't impressive yet, that's not a failure of the tactic — it's a signal to use it selectively. Run it on the products that already have the traffic and sales, leave it off the long tail, and the page tells the truth everywhere.

Combining stats without crowding the page

Live counters are one persuasion element among several, and stacking all of them produces a noisy, used-car-lot product page that converts worse than a calm one. The job is pairing, not piling.

A sales count next to the price, paired with an honest product photo and a clear delivery estimate, makes a coherent argument: popular, real, arriving soon. Adding a live-viewer line on top of a sales count on top of a "hot" badge on top of a countdown timer does the opposite — it reads as desperation. Pick the one or two signals that fit the specific doubt that product triggers. Where badges fit into this (and whether they earn their place at all), product badges and labels goes deep; for moving customers from a popular item to a bigger basket once they trust it, see cross-selling and upselling.

How to tell whether it actually worked

Don't judge this on a gut feeling or three days of data. Before you switch counters on, record the baseline for the products you're targeting: product-page conversion rate (views to add-to-cart, and add-to-cart to order), and bounce rate on those pages. Turn the counters on, then compare the same numbers over at least 30 days and a meaningful order volume — enough that you're reading a trend, not week-to-week noise. The cleanest read is to enable stats on one set of comparable products and leave a similar set untouched as a control, so seasonal swings hit both groups equally.

Most stores that do this honestly see a worthwhile lift on the products where the underlying numbers were already strong — and flat-to-negative results where they forced counters onto weak products. That pattern is the whole lesson of this post in one sentence: live sales and view stats don't create demand, they broadcast demand that already exists. Show real numbers, on the products that have them, in the slot that fits the doubt — and let the busy-restaurant instinct do the rest.

If you'd rather not hand-build the heartbeat tracking, the caching, the display threshold and the theme hooks yourself, our Product Sales & Views Live Stats module wires those parts together from the back office — counts drawn from your real order and visit data, a minimum-display floor so weak products stay quiet, and cached reads so the counter doesn't run a fresh query on every product-page load. The honesty rules above are the point; the module just enforces them for you instead of leaving them to discipline.

Frequently asked questions

Where does PrestaShop already store the sales count I want to show? In ps_order_detail (the product_id and product_quantity columns), joined to ps_orders for the date and validity flag. A lifetime count is a SUM(product_quantity) over valid orders for that product. PrestaShop also keeps a denormalised ps_product_sale aggregate, but querying ps_order_detail directly lets you control exactly which order states count.

Can PrestaShop show a real "X people viewing now" counter out of the box? No. PrestaShop counts page views per day in ps_page_viewed (so "viewed today / this week" is a query), but it has no built-in live session-presence counter. A real-time "viewing now" number needs its own lightweight tracking — an AJAX heartbeat that registers a session against a product and expires it after a couple of minutes.

What's the lowest number I should display? Set a floor — 50 or 100, whatever fits your volume — and hide the counter below it. "3 sold" under a price reads as "nobody's buying this," which is worse than showing nothing. A good module exposes this threshold as a setting.

Won't a counter on every product slow my store down? It will if it runs a fresh COUNT/SUM on every page load. Cache the figures — compute them on a schedule (hourly is plenty for lifetime counts) and read the cached value on render. "Lightweight and cached" is the difference between a feature that helps conversion and one that drags page speed on the page where speed matters most.

Is it OK to pad the numbers to look busier? No. No fake-base view counts, no "only 2 left" on a product with 400 in stock, no randomised viewer numbers that reset on refresh. Customers screenshot and compare; once one number looks invented, every other number on the page — price, stock, reviews — inherits the doubt. Show real figures only on the products that genuinely have them.

Share this post:
David Miller

David Miller

Founder, mypresta.rocks

David Miller is a PrestaShop specialist with over a decade of hands-on experience and the founder of mypresta.rocks, a software studio in Tychy, Poland. He builds and maintains a catalogue of 152 PrestaShop modules — including 21 "Revolution" suites spanning SEO, checkout, security, performance, marketing, search, support, and warehouse operations — that improve real stores every day, all tested against PrestaShop 1.7.8, 8.x, and 9.x. He also acts as caretaker for production stores turning over millions in annual sales, so his work is judged on live revenue, not demos. His experience runs the full breadth of ecommerce — performance, security, SEO, and marketing — and reaches beyond PrestaShop to WooCommerce, Shopify, and custom-built systems. On the blog he writes about the code-aware side of PrestaShop: what the platform really does under the hood, what breaks in production, and which fixes hold up.

Enjoyed this article?

Get our latest tips, guides and module updates delivered to your inbox.

Comments

No comments yet. Be the first!

Be the first to ask a question or share useful feedback.

Loading...
Back to top