PS PrestaShop Beginner

DataFirefly Live Counters — Complete guide

Install, configure and operate the 17 animated social-proof counters for PrestaShop 8 and 9: customers, shipped orders, Facebook & Instagram followers, 5 visual themes, multi-layer cache and AJAX live refresh.

Updated Module version 1.0.1

DataFirefly Live Counters displays on your PrestaShop shop an animated counters widget partly fed automatically from your database (active customers, shipped orders, products, countries served) and partly from values you enter (reviews, satisfaction, social followers…). The widget hooks natively into several display zones (home, footer, cart, columns) or anywhere in your theme via the Smarty tag widget name="dflivecounters". This documentation covers installation, configuration of the 17 available counters, the 5 visual themes, the cache strategy, hooking up the Facebook and Instagram APIs, AJAX live refresh and troubleshooting.

Installation

  1. Download the dflivecounters.zip archive from your DataFirefly account.
  2. PrestaShop back-office → ModulesUpload a module → send the ZIP.
  3. On install, the module registers 7 display hooks and initializes about a dozen configuration variables. No SQL table is created: all settings live in ps_configuration.
  4. The module loads its standalone PSR-4 autoloader — no composer install required on the server.

Compatible with PrestaShop 8.0 to 9.x, PHP 8.1+. Native multi-shop, multilingual via Polylang Pro or PrestaShop’s native multilingual system. Demo mode compatible.

Widget appearance

Open Modules → DataFirefly Live Counters → Configure. The first section groups the global appearance settings.

Visual theme

Five ready-to-use themes:

  • Minimal: utmost soberness, white background, ideal for clean themes.
  • Glassmorphism: frosted glass with backdrop-blur, background slightly tinted with the primary color. Very trendy.
  • Gradient: full-width gradient background from the primary color to a darker shade. Strong visual impact, white text.
  • Card: elevated white cards with soft shadow and hover. Premium classic.
  • Flat: background slightly tinted with the primary color, values colored in primary.

Title and subtitle

Displayed above the counters grid. Leave empty to hide the header (useful in the footer where context is already provided by the environment).

Colors

Three main colors drive the entire widget via CSS variables (--dflc-primary, --dflc-text, --dflc-bg):

  • Primary color: default icons, Flat theme accent, Gradient theme gradient.
  • Text color: title, subtitle, values and labels.
  • Background color: section background (ignored on Glassmorphism and Gradient themes which apply their own background).

Each counter can also have its own icon color (the “Icon color” field on the counter row), which lets you for example keep the Facebook and Instagram icons in their brand colors while keeping the rest consistent.

Columns

Two independent settings:

  • Desktop columns: 1 to 6 (default 4).
  • Mobile columns: 1 to 3 (default 2). Breakpoint is 768 px.

CountUp animation duration

Duration in milliseconds during which the digits count up from 0 to their target (default 2,000 ms). An ease-out cubic curve is applied for smooth deceleration. Set to 0 to disable the animation and display the final value immediately.

On devices with prefers-reduced-motion: reduce, the animation is automatically disabled, whatever the duration configured.

AJAX live refresh (optional)

When enabled, the widget periodically queries a JSON endpoint to update the values without a page reload. Two parameters:

  • Live refresh: ON/OFF.
  • Interval: in seconds, minimum 30 (default 60). Forced to 30 if you enter less.

The endpoint responds with a Cache-Control: public, max-age=30 header so your CDN can absorb the traffic. The transition animation from one value to the next starts from the currently displayed value, not from zero — visually more natural.

“Date from”

Reference date used by two counters:

  • Shipped orders: only counts orders created after this date (filter WHERE date_add >= ?).
  • Years of expertise: automatically computes the number of years elapsed from this date until today.

Counters catalog

17 counters are available, split into three groups by computation mode.

Automatic counters (5)

These counters read your PrestaShop data live. No input required.

  • Customers: active customers (active = 1 AND deleted = 0), scoped to the shop context. TTL 15 min.
  • Shipped orders: orders whose history contains at least one of the selected order states (“Order states counted as shipped” field). If no state is selected, the module automatically uses the shipped = 1 flag from ps_order_state. TTL 15 min.
  • Orders processed: all orders whose current state has the logable = 1 flag (PrestaShop’s canonical flag for orders that count in statistics). Excludes cancellations and refunds. TTL 15 min.
  • Products: active, visible products in the catalog, scoped to the shop context. TTL 30 min.
  • Countries served: number of distinct countries that received at least one order (COUNT(DISTINCT id_country) on ps_address joined to ps_orders). TTL 1 h.

Hybrid counters (4)

These counters first attempt an automatic calculation, then fall back to the manual value you entered as backup.

  • Years of expertise: computed from the “Date from”; manual value if you prefer setting a rounded figure (e.g. “12” instead of “11”). TTL 24 h.
  • Articles published: auto-detection of the main PrestaShop blog tables (smart_blog_post, prestablog_news, psblog_post, ph_simpleblog_post) via INFORMATION_SCHEMA. If no match, use the manual value. TTL 24 h.
  • Facebook followers: call to the Facebook Graph API with a long-lived Page Access Token. Manual fallback if not configured or if the API fails. TTL 1 h.
  • Instagram followers: call to the Instagram Graph API (Business or Creator account required). Manual fallback. TTL 1 h.

Manual counters (8)

These counters simply display the value you enter. Ideal for metrics PrestaShop cannot compute or that you want full control over.

  • Customer reviews: number of reviews (from Trustpilot, Avis Vérifiés, Google, etc.).
  • Satisfaction: satisfaction rate. Tip: use a “%” suffix and a 0–100 value.
  • CO₂ saved: kg of emissions avoided. Tip: ” kg” suffix.
  • Awards: awards, certifications, distinctions.
  • Support hours: ” h” suffix.
  • TikTok followers: the TikTok Display API requires per-user OAuth, impractical for a public widget. Manual entry.
  • X (Twitter) followers: the X API v2 is paid. Manual entry.
  • LinkedIn followers: LinkedIn Organization Followers require Marketing Developer Platform partner approval. Manual entry.

Per-counter configuration

Every counter row in the admin proposes the same settings:

  • Enabled (ON/OFF): only enabled counters appear in the widget. Display order follows the admin order.
  • Custom label: overrides the default label. Leave empty to use the native label, translated in the visitor’s language.
  • Value (manual): for manual counters and the fallback of hybrid counters.
  • Offset: integer added to the computed value. Handy to start from a flattering figure without touching your database. For “Customers” and “Shipped orders” for example, you can add +500 and +2,000 respectively if your shop has just been migrated. The “Current live” label next to the Offset field shows you the raw value computed by PrestaShop, before offset.
  • Prefix / Suffix: 4 and 6 characters respectively. Prefix and suffix stay fixed even during the animation.
  • Decimals: 0 to 3. Formatting uses Intl.NumberFormat with the visitor’s locale (localized thousands separators and decimal point).
  • Icon color: overrides the primary color for that icon only.

Custom labels are stored in configuration per shop and per language via PrestaShop’s native system. So you can have “Happy customers” in English and “Clients heureux” in French — or even a different label per shop in multi-shop.

“Shipped” order states

The “Shipped orders” counter relies on the status history by default. The Order states counted as shipped setting lets you pick precisely which states count. On a standard PrestaShop install, state IDs 4 (Shipped) and 5 (Delivered) are pre-selected.

If your shop uses custom statuses (e.g. “In-store pickup”, “Click & Collect collected”), don’t forget to add them to the selection — otherwise these orders won’t be counted.

If no state is selected, the module falls back to querying the shipped = 1 flag on ps_order_state. This approach is more permissive and captures most common setups.

Configure Facebook

  1. Go to developers.facebook.com and create a “Business” app.
  2. In the Graph API Explorer, select your app then your Facebook Page.
  3. Generate a Page Access Token with the pages_read_engagement and pages_show_list scopes.
  4. Exchange this short-lived token (1 h) for a long-lived token (60 days) via the /oauth/access_token?grant_type=fb_exchange_token endpoint.
  5. Get your Page ID from your Page settings (“Page Transparency” section, or directly in the Graph API Explorer).
  6. Fill the two fields in the Live Counters configuration and save. The Facebook counter updates on save.

The long-lived token expires after 60 days. Past that, the counter falls back to manual. Set a reminder to renew the token before expiration.

Configure Instagram

  1. Your Instagram account must be in Business or Creator mode. Personal accounts are not supported by the Graph API.
  2. Link your Instagram account to a Facebook Page (Page settings → Instagram).
  3. In the Graph API Explorer, query /me/accounts with your Page Access Token to retrieve the associated Instagram User ID (the instagram_business_account field).
  4. Use the same Facebook long-lived token for the Instagram API.
  5. Fill the IG User ID and the token in the Live Counters configuration.

Cache strategy

The cache works on two layers to guarantee a flat TTFB even under traffic.

Per-counter cache

Each counter has its own TTL:

  • 15 minutes: Customers, Shipped orders, Orders processed.
  • 30 minutes: Products.
  • 1 hour: Countries served, Facebook, Instagram.
  • 24 hours: Years of expertise, Articles published, and all manual counters.

The cache first uses the native PrestaShop Cache layer (memcached, APCu or Redis if configured on your server), then a filesystem fallback in var/cache/dflivecounters/. This guarantees TTLs are respected even if the native layer is in “no-cache” mode.

Rendered widget cache

The complete widget HTML is itself cached for 60 seconds per language and per hook (dflc_widget_LANG_HASH). This second layer absorbs most of the traffic even when the inner counters are already fresh.

Automatic purge

  • Saving the configuration automatically purges all module caches.
  • A Purge cache button is available in the admin panel for manual invalidation.
  • Uninstalling the module purges the cache automatically.

The admin panel shows live stats: number of cached entries, size in KB, folder path. Useful to verify the filesystem cache is active.

Placing the widget in your theme

The module registers 7 hooks on install:

  • displayHome — home page
  • displayFooter — footer
  • displayFooterBefore — right before the footer (PS 8+)
  • displayLeftColumn / displayRightColumn — side columns
  • displayShoppingCartFooter — cart page, below the summary
  • actionFrontControllerSetMedia — registers the CSS/JS assets

You can add or remove hooks from Design → Positions in the back-office.

Free placement via Smarty

To place the widget at a specific spot in your theme (e.g. on the product page, below a category title), use the Smarty widget tag:

{widget name="dflivecounters"}

The widget implements PrestaShop’s native WidgetInterface, making it callable from any .tpl template in your theme.

Customize the widget template

The main Smarty template is views/templates/hook/widget.tpl. To override it without modifying the module (to preserve updates), copy it into your theme, into the themes/your-theme/modules/dflivecounters/views/templates/hook/widget.tpl folder.

Smarty variables exposed:

  • {$dflc.counters} — array of each counter with the keys key, label, value, icon, prefix, suffix, decimals, icon_color
  • {$dflc.theme} — theme slug (minimal, glassmorphism, gradient, card, flat)
  • {$dflc.title}, {$dflc.subtitle}
  • {$dflc.primary_color}, {$dflc.text_color}, {$dflc.bg_color}
  • {$dflc.cols_desktop}, {$dflc.cols_mobile}
  • {$dflc.hook} — origin hook name (useful to adapt the rendering based on placement)

AJAX endpoint

The refresh front controller exposes a JSON URL usable by the live refresh or any third-party integration:

index.php?fc=module&module=dflivecounters&controller=refresh

The JSON response contains a success boolean, a Unix timestamp, and a counters object where each key is the counter identifier (customers, shipped_orders, facebook, instagram, etc.) and each value is the current number. The content reflects the counters enabled at call time, with offsets applied. The response is served with Cache-Control: public, max-age=30.

Accessibility

The widget is designed to follow WCAG 2.2 AA recommendations:

  • Semantic structure: section, header, ul role="list", li.
  • All SVG icons have aria-hidden="true" (decorative).
  • Strict respect of prefers-reduced-motion: reduce: animation disabled, final value displayed immediately.
  • Contrast: default colors meet a ratio above 4.5:1 on the Minimal and Card themes. Check your custom colors with a tool like axe DevTools.
  • Number formatting: font-variant-numeric: tabular-nums for constant digit width (avoids the visual “jump” during the animation).

GDPR

The widget is designed to require no consent banner:

  • No cookie set on the visitor side.
  • No third-party script loaded (no Facebook Pixel, no Google Tag Manager).
  • Facebook and Instagram API calls run server-side in PHP, never from the browser. No visitor data is sent to Meta.
  • No personal data collected or stored by the module.

Compatibility and technical notes

  • PrestaShop 8.0 to 9.x, PHP 8.1+.
  • Native multi-shop: all SQL queries are scoped to Shop::getContextListShopID().
  • Multilingual: Polylang Pro or PrestaShop’s native multilingual system.
  • No SQL table created: settings stored in ps_configuration.
  • Standalone PSR-4 autoloader (no composer install on the server).
  • Native PrestaShop WidgetInterface: usable via {widget name="dflivecounters"}.
  • Asset weight: 3 KB JS, 2 KB CSS. No external requests by default.
  • Compliant with PrestaShop 9 AJAX conventions: $this->module->l() instead of $this->l(), dedicated front controller for the refresh, never overrides ajaxRender.

FAQ and troubleshooting

The widget does not appear on the home page. Check that the module is hooked to displayHome in Design → Positions. Also check that at least one counter is enabled: without any counter enabled, the widget returns nothing (silently).

The Facebook counter stays at zero. Several possible causes: incorrect Page ID, expired token (60-day lifetime), missing scope (pages_read_engagement is required). Purge the module cache and reload the configuration: the value returned by the Graph API will appear next to the “Current live” label.

The Shipped orders counter is too low. Check the “Order states counted as shipped” selection: only selected states are counted. If you want to include custom statuses (e.g. “Click & Collect collected”), add them to the selection.

The numbers look frozen and don’t reflect my real traffic. That’s the cache doing its job. Default TTLs go from 15 minutes (customers, orders) to 24 hours (static counters). Use the Purge cache button to invalidate manually. For automatic refresh, enable Live refresh mode.

The CountUp animation does not trigger. The widget uses IntersectionObserver and triggers as it enters the viewport. If the widget is already visible on page load (e.g. placed at the top), the animation starts immediately. If it stays at zero: check your browser’s JavaScript console, another module might be breaking the JS bundle.

The widget breaks my Lighthouse / Core Web Vitals. With a bottom-of-page placement (footer) and the 60 s cache on the rendered HTML, the CLS / LCP impact is negligible. If you see an issue, check that you haven’t enabled Live refresh with too short an interval (the AJAX triggers while Lighthouse measures). For a clean audit, disable live refresh.

In multi-shop, are counters scoped per shop? Yes. All SQL queries use Shop::getContextListShopID(). In “all shops” mode, counters add up; in “single shop” mode, they only count that shop. Custom labels and the manual value are also per-shop-per-language.

How do I add a custom counter? Create a class extending Df/LiveCounters/Counter/AbstractCounter (or ManualCounter for a 100% manual counter), implement getKey(), getDefaultLabel() and getValue(), then add the instance to the CounterRegistry instances array. To avoid losing your code at the next update, create a small companion module that injects your counter into the registry via a custom hook — feel free to contact us for an example.

Was this page helpful?

Still stuck? Contact support