Easy return - no questions asked
Install, set up and take profit
Priority Help & Satisfaction Over Sales
LINE Chat Integration
LINE Chat Button — #1 Messenger in Japan, Thailand & Taiwan
LINE Chat — Connect with 200M+ Users Across Asia-Pacific
Add a LINE messenger button to your PrestaShop store and tap into the dominant messaging platform in Japan, Thailand, Taiwan, and Indonesia. LINE is not just a chat app — it is a lifestyle platform with 200+ million monthly active users who use it for messaging, payments, news, and shopping.
- Essential for Asian markets — LINE has 96M users in Japan, 54M in Thailand, 22M in Taiwan, 10M+ in Indonesia
- Official Account integration — link directly to your LINE Official Account for professional business communication
- Floating chat button — customizable position, size, and appearance from the back office
- Rich messaging support — customers can send photos, videos, stickers, and location pins
- Mobile-first design — 90%+ of LINE users are on mobile, and the button is optimized for touch interaction
- No external scripts — pure CSS + minimal JS, zero impact on page load speed
- Display controls — choose which pages show the LINE button
- PrestaShop 1.7 – 9.x — universal compatibility across all versions
If you sell to customers in Japan, Thailand, Taiwan, or Indonesia, LINE is not optional — it is the primary communication channel. This module makes integration instant.
Connect With Customers on LINE Directly From Your Store
LINE is the dominant messaging app across Japan, Thailand, Taiwan, and Indonesia — with over 90 million daily active users in markets where it's the primary communication channel. If your store serves customers in these regions, adding a LINE chat button is essential: it lets shoppers contact you in the app they already use all day, rather than navigating away to find contact information.
This module adds a LINE chat button to your PrestaShop store without theme edits. Configure your LINE ID, choose where the button appears, and customers can open a conversation with your account in the LINE app with one tap.
Meet Your Customers Where They Already Communicate
Expecting Asian customers to use email or a Western chat widget creates unnecessary friction. A visible LINE button removes that barrier — the chat opens in a familiar, trusted app. Pre-sale questions, product enquiries, order status checks, and after-sales support all happen naturally in LINE, where your customers are already comfortable communicating.
Response rates and customer satisfaction both improve when the communication channel matches the customer's preference. LINE messages are seen and responded to far faster than email enquiries, which often go unread for hours.
Simple Setup, Immediate Availability
Installation is straightforward: the module adds a LINE chat button linked to your LINE Official Account or personal LINE ID. The button is visible on all store pages and opens LINE on mobile with your account pre-loaded, ready for conversation. Customers on desktop are directed to the LINE web interface or prompted to open the mobile app.
See all communication and integration tools in our Integrations & Data Export collection. For Western markets, pair with Messenger Chat Integration, and for broader chat coverage add Tawk.to Chat Integration.
- Adds a LINE chat button to your store without theme file edits
- Links to your LINE Official Account or personal LINE ID
- Mobile-first: opens LINE app directly on phones, LINE web on desktop
- Essential for stores targeting customers in Japan, Thailand, Taiwan, or Indonesia
- Compatible with PrestaShop 1.6, 1.7, 8.x, and 9.x
- languageAsian market stores — serve Japanese, Thai, Taiwanese, and Indonesian customers on their preferred messaging platform
- chatPre-sale support — answer product questions in LINE to convert hesitant shoppers from Asian markets
- support_agentPost-purchase care — handle order status and return queries through a channel customers check regularly
- storefrontMulti-channel presence — complement Western chat tools with LINE coverage for a complete global support setup
Learn More
- Adding Live Chat to Your Store: Does It Actually Increase Sales?
- Live Chat for E-Commerce: WhatsApp, Messenger or Tawk.to — Which One Wins
-
Referencemprlinechatintegration
-
PrestaShop CompatibilityPS 1.6 – 9.x
-
Pricing ModelOne-time Purchase
-
Module TypeFront-office
-
GDPR RelevantYes
-
Business GoalCustomer Communication
-
External Account NeededYes
-
Module ComplexityLightweight Widget
-
Customer Journey StageEngage Shoppers
-
Works With PlatformChat & Messaging
For stores serving customers in Japan, Thailand, Taiwan, or Southeast Asia, a LINE contact button is often an expectation rather than a bonus — LINE is the primary messaging app millions of shoppers use daily and many will not contact you without it. The module links directly to your LINE account, Official Account, or group, opening a conversation instantly when tapped. LINE Official Accounts also support rich menus, automated replies, and broadcast messages to opted-in customers, enabling post-purchase engagement at scale.
OPcache is a PHP extension that caches compiled PHP code in memory, so PHP does not have to recompile it on every request. You should absolutely enable it — it can improve PrestaShop performance by 30-50% with zero downsides for production. Most hosting providers have it enabled by default. The important setting is opcache.validate_timestamps: set to 1 on development, but many production servers set it to 0 for maximum performance (which means you need to manually reset OPcache after deploying code changes).
How PrestaShop Email Templates Work
PrestaShop sends transactional emails at every key point in the customer journey: account creation, order confirmation, shipping notification, password reset, and more. These emails are generated from template files stored on your server, and they are fully customizable. Understanding how the template system works is the first step toward creating professional, branded order confirmation emails that reinforce your store's identity.
Every PrestaShop email consists of two template files: an HTML version for email clients that support rich formatting, and a plain text (TXT) version for email clients that do not. Both files must exist for an email to send correctly. The HTML version is what the vast majority of your customers will see. The TXT version serves as a fallback and is also used by accessibility tools and some corporate email filters.
Email templates live in the mails/ directory structure. The exact location depends on whether you are using core emails, theme-overridden emails, or module-specific emails. Understanding this hierarchy is essential because PrestaShop checks multiple locations for each template and uses the first one it finds.
The Email Template Directory Structure
PrestaShop organizes email templates in a specific directory hierarchy. When it needs to send an email, it searches these locations in order of priority:
Theme-Level Overrides (Highest Priority)
Templates in /themes/your-theme/mails/en/ (where en is the language ISO code) take priority over all other locations. If you want to customize an email template without modifying core files, this is where your custom templates should go. This approach survives PrestaShop updates because theme files are not overwritten during core updates.
Core Templates (Default)
The default templates live in /mails/en/ in your PrestaShop root directory. These are the templates that ship with PrestaShop and are used when no theme override exists. Editing these files directly works but is not recommended because your changes will be lost when you update PrestaShop.
Module-Specific Templates
Modules that send their own emails store templates in /modules/module-name/mails/en/. For example, the order notification emails sent by the core payment modules are stored in their respective module directories. You can override these by placing modified copies in your theme's mails/ directory with the same filename.
Language Subdirectories
Each mails/ directory contains subdirectories for each installed language, using the language ISO code: en for English, fr for French, de for German, and so on. When PrestaShop sends an email, it uses the template from the directory matching the customer's language preference. If a template does not exist in the customer's language, PrestaShop falls back to the default language.
Anatomy of an Order Confirmation Template
The order confirmation email is the most important transactional email your store sends. It is the file named order_conf.html (and its companion order_conf.txt) in your mails directory. Let us examine its structure.
HTML Template Structure
PrestaShop email templates are standalone HTML documents. They do not use external CSS files because most email clients strip external stylesheets. All styling must be inline CSS. A typical order confirmation template includes these sections:
The document starts with a standard HTML doctype and head section. The body contains a table-based layout (because email clients have poor support for modern CSS layout methods like flexbox and grid). Within this layout, you find a header section with your store logo, the main content area with order details, a product table listing each item ordered, pricing summary with subtotals and totals, shipping information, payment method details, and a footer with store contact information and legal notices.
The Variable System
PrestaShop uses a simple variable replacement system in email templates. Variables are enclosed in curly braces: {variable_name}. When the email is generated, PrestaShop replaces each variable with its actual value. The order confirmation template uses these key variables:
{firstname} and {lastname} contain the customer's name. {order_name} is the order reference number (like ABCDEF123). {shop_name} is your store's name as configured in the back office. {shop_url} is your store's URL. {shop_logo} is the path to your store's logo image. {date} is the order date. {payment} is the payment method used. {total_paid} is the total amount paid. {delivery_company} and {delivery_address} contain shipping carrier and address information.
For the product list, PrestaShop uses a special block syntax. The product items section is wrapped in a loop that repeats for each product in the order: {items} contains the pre-formatted HTML for the entire product list table, including product names, quantities, prices, and any customization details.
Available Variables Reference
To see all available variables for a specific email template, look at the PHP code that sends the email. For order confirmation, check the PaymentModule class (in /classes/PaymentModule.php). The validateOrder() method builds the array of template variables. Each key in the array corresponds to a variable name you can use in the template.
Common variables available in order confirmation emails include: {id_order}, {order_name}, {delivery_block_txt}, {invoice_block_txt}, {delivery_block_html}, {invoice_block_html}, {delivery_company}, {delivery_firstname}, {delivery_lastname}, {delivery_address1}, {delivery_address2}, {delivery_city}, {delivery_postal_code}, {delivery_country}, {delivery_phone}, {invoice_company}, {invoice_firstname}, {invoice_lastname}, {invoice_address1}, {invoice_address2}, {invoice_city}, {invoice_postal_code}, {invoice_country}, {invoice_phone}, {message}, and {total_products}.
Customizing the Order Confirmation Template
Step 1: Create a Theme Override
Never edit the core template files directly. Instead, copy the template to your theme's mails directory:
Copy /mails/en/order_conf.html to /themes/your-theme/mails/en/order_conf.html. Do the same for order_conf.txt. If the mails/en/ directory does not exist in your theme, create it.
If your store supports multiple languages, copy the templates for each language directory. Your French order confirmation goes in /themes/your-theme/mails/fr/order_conf.html and so on.
Step 2: Modify the HTML Layout
Open the HTML template in a text editor (not a visual editor that might add unwanted code). Email HTML is different from web HTML in several important ways:
Use tables for layout, not divs. Email clients, especially Outlook, have very limited CSS support. A three-column layout must use a <table> with three <td> elements, not CSS columns or flexbox.
Use inline styles on every element. Instead of <p class="heading"> with a separate stylesheet, use <p style="font-size:18px; font-weight:bold; color:#333333;">. Every styled element needs its own inline style attribute.
Set explicit widths on tables and cells. Email clients do not always respect percentage-based widths. Use a fixed width for your main content table (600 pixels is the standard) with percentage-based internal columns.
Use web-safe fonts. Not all email clients support custom fonts. Stick to Arial, Helvetica, Georgia, Times New Roman, Verdana, or Trebuchet MS. You can try loading a custom font as a fallback, but always specify a web-safe font as the final fallback.
Step 3: Add Your Branding
Replace the default PrestaShop header with your store's branding. This typically involves updating the logo (the {shop_logo} variable automatically uses your store's logo, but you might want a specific email version), changing the header background color to match your brand, adding your brand's color scheme to headings and links, and including your store's tagline or a brief marketing message.
Keep the overall structure simple. Overly complex email designs break in different email clients. A clean, single-column layout with your brand colors and logo is more effective and more reliable than an elaborate multi-column design.
Step 4: Customize the Product Table
The default product table in PrestaShop's order confirmation is functional but basic. You can enhance it by adding product images (use absolute URLs to images hosted on your server, not relative paths), adding links to product pages so customers can easily reorder or leave reviews, adding custom fields like estimated delivery dates or personalized messages, and adjusting the table styling to match your brand.
When adding product images, keep them small (50 to 80 pixels wide) and always include an alt attribute. Some email clients block images by default, and the alt text ensures customers can still identify their products.
Adding Custom Fields to Order Emails
PrestaShop's default variables cover the standard order information, but you might want to include additional data like loyalty points earned, estimated delivery date, a personalized thank-you message, or cross-sell product recommendations.
Adding Variables via a Module
The cleanest way to add custom variables is through a module that hooks into the email sending process. Create a module that registers the actionEmailSendBefore hook (available in PrestaShop 1.7.6 and later) or the actionGetExtraMailTemplateVars hook. In your hook handler, add your custom variables to the template variables array:
Your hook function receives the template variables array by reference. You can add new variables to this array, and they become available in the template using the standard {variable_name} syntax. For example, after adding loyalty_points to the array in your hook, you can use {loyalty_points} in your order confirmation HTML template.
Using Existing Database Data
You can pull any data from your PrestaShop database into email variables. Common examples include the customer's total order count (to show "Thank you for your 5th order!"), the customer's loyalty point balance, custom product fields stored in product features or attributes, and warehouse or supplier information for the ordered products.
Multilingual Email Setup
If your store serves customers in multiple languages, every email template needs a version for each language. PrestaShop handles language selection automatically based on the customer's language preference, but you need to provide the templates.
Creating Language-Specific Templates
For each language your store supports, create a directory under your theme's mails folder: /themes/your-theme/mails/en/, /themes/your-theme/mails/fr/, /themes/your-theme/mails/de/, and so on. Copy and translate each template file into the appropriate directory.
Do not use automated translation for transactional emails. These emails represent your store's communication with customers, and poor translations damage trust. Have each language version written or reviewed by a native speaker.
Right-to-Left Language Support
If you support languages like Arabic or Hebrew, your email templates need RTL (right-to-left) layout support. Add dir="rtl" to the main table element and adjust text alignment and padding in your inline styles. Create separate templates for RTL languages rather than trying to make a single template work for both directions.
Date and Currency Formatting
PrestaShop automatically formats dates and currency values according to the customer's language and currency settings. The {date}, {total_paid}, and other formatted values already reflect the correct locale. However, if you add custom variables with dates or currency values, make sure to format them correctly for the target language.
SMTP Configuration for Reliable Delivery
The best email template in the world is useless if your emails do not reach the inbox. PrestaShop's default email configuration uses PHP's built-in mail() function, which is unreliable for transactional emails. Most of these emails end up in spam folders or are rejected entirely by modern email providers.
Why SMTP Matters
SMTP (Simple Mail Transfer Protocol) with proper authentication is essential for email deliverability. When you send email through PHP's mail() function, the email comes from your web server's IP address with no authentication. Email providers like Gmail, Outlook, and Yahoo see this as a red flag and often classify these emails as spam.
With SMTP, your emails are sent through an authenticated email server with proper SPF, DKIM, and DMARC records. This proves to receiving email servers that the email is legitimate and authorized by your domain.
Configuring SMTP in PrestaShop
Go to Advanced Parameters > E-mail in your PrestaShop back office. Change the method from "Use PHP's mail() function" to "Set my own SMTP parameters." Enter your SMTP server details: the server address, port (typically 587 for TLS or 465 for SSL), encryption type, username, and password.
Common SMTP providers for PrestaShop include Gmail SMTP (smtp.gmail.com, port 587, TLS, requires an App Password if 2FA is enabled), Amazon SES (affordable for high volume), SendGrid (generous free tier), Mailgun (developer-friendly with good logging), and your hosting provider's SMTP server (check with your host for settings).
Testing SMTP Configuration
After configuring SMTP, use the "Send a test email" button at the bottom of the email configuration page. Enter your own email address and check that the test email arrives in your inbox (not spam). If the test email fails, check your SMTP credentials, verify that your server can reach the SMTP server on the configured port (some hosting providers block outgoing port 25 and 587), and check if your SMTP provider requires specific security settings.
SPF, DKIM, and DMARC Records
For maximum deliverability, configure these DNS records for your domain. SPF (Sender Policy Framework) specifies which servers are authorized to send email on behalf of your domain. DKIM (DomainKeys Identified Mail) adds a digital signature to your emails that proves they were sent by your domain. DMARC (Domain-based Message Authentication, Reporting, and Conformance) tells receiving servers what to do with emails that fail SPF or DKIM checks.
Your SMTP provider will give you the specific DNS records to add. For example, if you use SendGrid, they provide SPF and DKIM records during the domain authentication setup process. Add these as TXT records in your domain's DNS settings.
Testing Email Templates
Sending Test Emails
PrestaShop does not have a built-in way to preview specific email templates. To test your order confirmation template, you need to place a real test order. Create a test customer account, add products to the cart, and complete the checkout with a test payment method. If you have a sandbox payment module configured, use that. Otherwise, the bank wire or check payment methods let you complete an order without actual payment processing.
Testing Across Email Clients
Email rendering varies dramatically between email clients. What looks perfect in Gmail might be broken in Outlook. At minimum, test your templates in Gmail (web), Outlook (desktop and web), Apple Mail, Yahoo Mail, and at least one mobile email app. Services like Litmus or Email on Acid automate this testing by rendering your email in dozens of email clients simultaneously, but they are paid services.
Common Rendering Issues
If your email looks broken in Outlook, it is almost certainly a CSS issue. Outlook uses Microsoft Word's rendering engine for HTML emails, which has extremely limited CSS support. It does not support background images on table cells (use background colors instead), padding on block elements (use table cell padding), max-width (use fixed widths), margin for centering (use align="center" on tables), or CSS floats.
For mobile responsiveness, wrap your content table in a container with max-width:600px and add a media query in the head style block (which some email clients support) that sets table widths to 100% on small screens. This is not perfect responsive design, but it prevents horizontal scrolling on most mobile devices.
Common Issues and Troubleshooting
Missing Images in Emails
This is the most common email template problem. Images in emails must use absolute URLs (starting with https://), not relative paths. If your template references /img/logo.png, change it to https://www.yourdomain.com/img/logo.png. The {shop_logo} variable automatically generates an absolute URL, but any images you add manually must use full URLs.
Also verify that your images are accessible from outside your network. If your store is behind a firewall or HTTP authentication, email clients cannot load the images. Test by opening the image URL in a private/incognito browser window.
Broken Layout After Editing
Email HTML is fragile. A single unclosed tag or missing table cell can break the entire layout. Always validate your HTML after editing. Count your opening and closing table, tr, and td tags. Every <table> needs a </table>, every <tr> needs a </tr>, and every <td> needs a </td>. Check that every row in a table has the same number of cells (or uses colspan to make up the difference).
Variables Not Being Replaced
If you see literal {variable_name} text in your sent emails instead of actual values, check the variable name for typos. Variable names are case-sensitive. Also verify that the variable exists for the specific email type you are customizing. Not all variables are available in all email templates. The order-specific variables like {order_name} are only available in order-related emails.
Emails Not Sending at All
If emails are not being sent, check the PrestaShop back office under Advanced Parameters > E-mail. There you can see a log of sent emails. If the log shows failures, check your SMTP configuration. If no emails appear in the log, the email might not be triggered at all. Verify that your order status transitions are configured to send emails (Orders > Statuses > edit status > check "Send an email to the customer").
Also check your server's PHP error log for email-related errors. Common issues include PHP's mail() function being disabled by the hosting provider, SMTP authentication failures due to changed passwords, and network connectivity issues between your server and the SMTP server.
Emails Going to Spam
Even with proper SMTP configuration, emails can still land in spam. The most common reasons are missing or incorrect SPF/DKIM/DMARC records, email content that triggers spam filters (excessive use of capital letters, spam trigger words like "free" or "act now", too many images with little text), sending from an IP address with a poor reputation (common with shared hosting), and the "from" email address domain not matching the SMTP server domain.
Fix the DNS records first, then review your email content. Use a tool like mail-tester.com to analyze your emails for spam triggers. Send a test email to the address they provide, and they return a detailed report showing what might cause spam classification.
Theme-Specific Email Overrides
Some PrestaShop themes include their own email templates that match the theme's design. If your theme has templates in /themes/your-theme/mails/, these override the core templates automatically.
Checking for Theme Email Templates
Look in your active theme's directory for a mails folder. If it exists, the theme provides custom email templates. These templates usually match the theme's color scheme and header/footer design, giving your emails visual consistency with your storefront.
Customizing Theme Email Templates
If your theme provides email templates, edit those instead of copying from the core mails/ directory. The theme templates may use a different HTML structure or include additional CSS that is specific to the theme's design system. Starting from the theme's version ensures visual consistency.
Keeping Templates in Sync with Theme Updates
When you update your theme, check whether the update includes changes to email templates. If it does, your customizations might be overwritten. Before updating, back up your customized templates. After updating, compare the new templates with your backups and reapply your customizations to the updated versions. This is tedious but necessary to maintain both your customizations and any improvements or fixes the theme developer has made.
Best Practices for Order Confirmation Emails
A well-crafted order confirmation email does more than confirm the transaction. It builds trust, reduces support inquiries, and creates opportunities for engagement.
Include a clear order reference number prominently at the top. Customers need this number when contacting support or tracking their order. List every product with its name, quantity, price, and any options or customizations. Include the complete breakdown of subtotal, shipping cost, taxes, discounts, and total. Show the delivery address so customers can verify it and contact you immediately if it is wrong. Include the payment method used and any relevant transaction details. Provide a link to the order tracking page or the customer's order history in their account. Add your customer service contact information so customers know how to reach you if something is wrong.
Keep the design clean and mobile-friendly. More than half of all emails are read on mobile devices. Use a single-column layout, large readable text (minimum 14px for body text), and buttons with adequate touch targets (minimum 44px height). Your order confirmation email is a reflection of your store's professionalism. Invest the time to get it right.
For more details, read our guides: Email Configuration in PrestaShop: SMTP, Gmail and Transactional Email and Order Status Workflow in PrestaShop: Customization and Automation.
Why Regular Technical Audits Matter
PrestaShop stores degrade over time. Modules get installed and forgotten. PHP versions fall behind. Error logs fill up with warnings that nobody reads. Database tables grow bloated with abandoned cart data and expired sessions. Security patches go unapplied. Each of these issues is small on its own, but together they compound into slow page loads, security vulnerabilities, and eventually downtime or data loss.
The problem is that most store owners only discover these issues when something breaks. A customer complains about slow checkout. Google drops your rankings because your site fails Core Web Vitals. Or worse, you discover your admin panel is compromised because you never changed the default admin path and your PHP version had a known vulnerability.
A 30-minute technical health audit, performed monthly, prevents all of this. It is not a deep dive into every configuration setting. It is a focused checklist that catches the most common and most dangerous issues before they become emergencies. This guide walks through each check with approximate time estimates, giving you a repeatable process you can follow every month.
Check 1: PHP Version and Configuration (3 Minutes)
PHP is the engine that runs PrestaShop, and running an outdated version is both a performance and security risk. PHP versions receive active support for two years and security fixes for one additional year after that. After that, known vulnerabilities go unpatched.
Checking Your PHP Version
Go to your PrestaShop back office and navigate to Advanced Parameters > Information. The PHP version is listed in the Server Information section. Alternatively, you can check in your hosting control panel (cPanel, Plesk, or similar).
As of 2026, the actively supported PHP versions are 8.2, 8.3, and 8.4. If you are running PHP 8.1 or older, upgrading should be a priority. PrestaShop 8.x requires PHP 7.2 or later but performs significantly better on PHP 8.1 and above. PrestaShop 1.7.x supports PHP 7.1 through 8.1, depending on the specific version.
Key PHP Settings to Verify
While on the Information page, check these PHP configuration values:
memory_limit should be at least 256M for PrestaShop. If it is lower, you may experience white pages or incomplete operations when handling large catalogs or generating reports.
max_execution_time should be at least 300 (5 minutes). Lower values can cause timeouts during import operations, cache rebuilds, and module installations.
upload_max_filesize and post_max_size should be at least 16M, or higher if you regularly upload large product images or import files.
OPcache should be enabled. OPcache stores compiled PHP code in memory, dramatically reducing page load times. If it is disabled, your store is running significantly slower than it could be.
Check 2: Error Log Review (4 Minutes)
Error logs tell you what is breaking behind the scenes, even when the front end appears to work normally. Warnings and notices that do not crash the page still indicate problems that waste server resources and can escalate into real failures.
PrestaShop Logs
In the back office, go to Advanced Parameters > Logs. Sort by date (newest first) and scan the last week of entries. Focus on Severity 3 (Error) and Severity 4 (Critical) messages. Common critical errors include database connection failures, file permission errors, module exceptions, and payment processing errors.
If you see repeated errors from the same module, that module has a bug that needs attention. If you see database errors, your database server may be running out of connections or disk space.
PHP Error Log
The PHP error log location depends on your hosting environment. Common locations include /var/log/php/error.log, /var/log/apache2/error.log, or a path specified in your hosting control panel. Check the last 100 lines for fatal errors, warnings, and deprecation notices.
Deprecation notices are especially important to track. They warn you that a function or feature your code uses will be removed in a future PHP version. Addressing these now prevents your store from breaking when you upgrade PHP.
What to Do with Errors
Do not try to fix every error during the audit. The audit is for identification. Create a list of the most critical and most frequent errors, prioritized by severity. Fatal errors and critical errors need immediate attention. Warnings should be addressed within the month. Notices and deprecation warnings can be scheduled for your next maintenance window.
Check 3: Module Audit (5 Minutes)
Modules are the most common source of security vulnerabilities, performance problems, and compatibility issues in PrestaShop. A quick module audit identifies dead weight and potential risks.
Identifying Unused Modules
Go to Modules > Module Manager. Look for modules that are installed but disabled. These modules still have files on your server and potentially have database tables, but they are not serving any purpose. They increase your attack surface (a vulnerability in a disabled module's files can still be exploited) and slow down backups.
For each disabled module, decide whether you will use it again. If not, uninstall it completely (not just disable). Uninstalling removes the module's database tables and configuration. After uninstalling, also delete the module's directory from /modules/ to remove its files from the server entirely.
Checking for Updates
In the Module Manager, look for modules with available updates. Outdated modules are a primary vector for security exploits. Update notifications appear as badges on the module listing. Prioritize updates for modules that handle sensitive data: payment modules, customer account modules, and any module that processes forms.
Before updating any module, check the changelog to understand what changed. If the update includes security fixes, apply it immediately. If it is a feature update, test it on a staging environment first if possible.
Counting Total Modules
Check how many modules are installed in total. PrestaShop ships with many modules by default, and stores accumulate more over time. Each active module adds hooks that execute on every page load, increasing response time. If you have more than 80 to 100 active modules, review the list critically. Many default PrestaShop modules (like the social sharing buttons, customer data privacy notice, and statistics modules) can be disabled if you do not use them, resulting in measurable performance improvement.
Check 4: Database Health (4 Minutes)
Your PrestaShop database grows continuously. Every customer visit creates session data. Every abandoned cart stays in the database. Every log entry accumulates. Over months and years, this bloat slows down queries and increases backup times.
Checking Database Size
In your hosting control panel (cPanel > phpMyAdmin, for example), check the total database size. A healthy PrestaShop database for a small to medium store (under 10,000 products) should be under 500 MB. If yours is significantly larger, data bloat is likely the cause.
Identifying Large Tables
In phpMyAdmin, click on your database and sort tables by size. The usual culprits for bloat are: ps_connections and ps_connections_page (visitor tracking data that can grow to gigabytes), ps_log (PrestaShop's internal log table), ps_mail (email history), ps_cart and ps_cart_product (abandoned cart data), ps_guest (anonymous visitor records), and ps_pagenotfound (404 error tracking).
These tables can be safely cleaned of old data. For example, you do not need connection data from two years ago. PrestaShop has a built-in feature for cleaning some of these tables: go to Advanced Parameters > Administration and look for the "Automatically check for module updates" and data cleanup options. For more thorough cleanup, the free PrestaShop Cleaner module can purge old statistics data, abandoned carts, and expired sessions.
Checking for Missing Indexes
While in phpMyAdmin, check the structure of your most important tables (ps_product, ps_category_product, ps_stock_available) and verify that indexes exist on the columns used in search and filtering. Missing indexes cause slow queries that affect page load times. However, do not add indexes without understanding the trade-offs, as each index slows down write operations slightly.
Check 5: Security Basics (5 Minutes)
Security vulnerabilities in PrestaShop stores are actively exploited. Automated scanners continuously probe the internet for vulnerable installations. Five minutes of security checks can prevent a catastrophic breach.
Admin Panel URL
Your admin panel should not be accessible at a predictable URL like /admin/ or /backoffice/. PrestaShop generates a randomized admin directory name during installation (like /admin738xyz/). Verify that your admin URL is still randomized by checking the admin directory name on your server. If someone has renamed it to something guessable, rename it back to a random string.
SSL Certificate
Your entire store must run on HTTPS. Check by visiting your store's URL with http:// and verifying that it redirects to https://. In the back office, go to Shop Parameters > General and verify that "Enable SSL" and "Enable SSL on all pages" are both set to Yes.
Also check your SSL certificate's expiration date. Let's Encrypt certificates expire every 90 days and should auto-renew, but auto-renewal fails silently more often than you would expect. Click the padlock icon in your browser's address bar to see the certificate details and expiration date. If it expires within the next 30 days, verify that auto-renewal is configured and working.
File Permissions
Incorrect file permissions are a security risk. On Linux servers, your PrestaShop files should generally be owned by the web server user (typically www-data or apache) and have these permissions: directories at 755 (owner can read/write/execute, others can read/execute), files at 644 (owner can read/write, others can read only), and configuration files like config/settings.inc.php or app/config/parameters.php at 640 or 440 (restricted read access).
Check a few critical files to verify permissions are not too open. No file should be 777 (world-writable). If you find 777 permissions, fix them immediately. They allow any user on the server to modify those files.
Debug Mode
Verify that debug mode is disabled on your production store. Debug mode exposes detailed error messages, file paths, and database queries to visitors, which is valuable information for attackers. Check the file /config/defines.inc.php and ensure _PS_MODE_DEV_ is set to false. In PrestaShop 8.x, also check the .env file for the APP_DEBUG setting.
Known Vulnerabilities
Check whether your PrestaShop version has known security vulnerabilities. Visit the PrestaShop security advisories page and compare the listed versions with yours. If your version is affected by any advisory that you have not patched, prioritize applying the fix.
Check 6: Performance Quick Test (4 Minutes)
Performance directly affects conversion rates. Every additional second of page load time reduces conversions measurably. A quick performance test identifies major bottlenecks.
Running a Lighthouse Audit
Open Google Chrome, navigate to your store's homepage, open Chrome DevTools (F12), and click the Lighthouse tab. Run an audit for Performance, Best Practices, and SEO on a Mobile device. The test takes about 30 seconds.
Focus on the Performance score. A score below 50 indicates serious performance problems. Between 50 and 89 means there is room for improvement. Above 90 is good. The audit report shows specific issues and estimates of how much time each fix would save.
Key Metrics to Check
From the Lighthouse report, pay attention to Largest Contentful Paint (LCP), which measures how long it takes for the main content to appear. It should be under 2.5 seconds. First Input Delay (FID) or Interaction to Next Paint (INP) measures responsiveness. It should be under 200 milliseconds. Cumulative Layout Shift (CLS) measures visual stability. It should be under 0.1.
If LCP is high, the most common causes in PrestaShop are unoptimized images (large product images served without compression or proper sizing), slow server response time (check your hosting plan and database performance), render-blocking CSS and JavaScript (disable unnecessary modules that add their assets to every page), and disabled caching (Smarty cache and CCC should be enabled in production).
Checking Cache Configuration
In the back office, go to Advanced Parameters > Performance. Verify these settings: Smarty cache should be Yes with the cache type set to "File". CCC (Combine, Compress, Cache) should have CSS and JavaScript minification and combination enabled. Template compilation should be set to "Recompile templates if the files have been updated" (not "Force compilation" which is for development only).
If any of these are misconfigured, fixing them provides an immediate and noticeable performance improvement.
Check 7: SEO Basics (3 Minutes)
Technical SEO issues prevent search engines from properly crawling and indexing your store. A few quick checks catch the most impactful problems.
Robots.txt
Visit yourdomain.com/robots.txt in your browser. Verify that it exists and contains sensible rules. PrestaShop generates a robots.txt file automatically. Check that it is not blocking important pages. Your product pages, category pages, and CMS pages should not be disallowed. Common mistakes include blocking all URLs with parameters (which blocks filtered category pages and search results) and blocking the /modules/ directory (which can prevent CSS and JavaScript from being loaded by search engine renderers).
Also verify that the robots.txt includes a sitemap directive pointing to your XML sitemap: Sitemap: https://www.yourdomain.com/1_index_sitemap.xml.
XML Sitemap
Visit the sitemap URL listed in your robots.txt. Verify that it loads, that it is recent (check the last modification dates), and that it contains your important pages. If the sitemap is outdated or empty, regenerate it. If you use the built-in PrestaShop sitemap generator, go to Modules > Module Manager, find the Google Sitemap module, and click Configure to regenerate.
Check the number of URLs in the sitemap against your expected count. If you have 1,000 products but the sitemap only lists 200 URLs, something is wrong with the generation process. Common causes include products being disabled or out of stock being excluded from the sitemap, category visibility settings filtering out products, and the sitemap generation process timing out before completing.
Canonical URLs
Visit a few product pages and view the page source (Ctrl+U). Look for the <link rel="canonical"> tag in the head section. It should contain the clean URL of the current page without any query parameters. If canonical tags are missing or incorrect, duplicate content issues will harm your SEO. In the back office, go to Shop Parameters > Traffic & SEO and verify that "Disable Apache's MultiViews option" and "Disable Apache's mod_security module" are configured correctly for your server.
Check 8: Backup Verification (3 Minutes)
Backups that have never been tested are not backups. They are wishful thinking. This check verifies that your backup system is actually working.
Checking Backup Recency
Determine where your backups are stored. This varies by hosting provider. Check your hosting control panel for backup tools (cPanel has a Backup section, Plesk has a Backup Manager). If you use a backup module in PrestaShop, check its configuration and recent backup log.
Your most recent backup should be no more than 24 hours old for active stores. If your last backup is older than a week, your backup system is either not configured, not running, or failing silently. Fix this immediately. Data loss from a server failure or hack without a recent backup can be business-ending.
Verifying Backup Completeness
A complete PrestaShop backup includes the entire database (all tables, not just product data) and the file system (all PrestaShop files, including uploaded images, module files, and theme customizations). Many backup solutions only capture the database or only capture the files. Verify that yours captures both.
Check the backup file sizes. A database backup for a small store should be at least several megabytes. If it is suspiciously small (under 1 MB for an active store), it might be empty or corrupted. A file backup should include your /img/ directory, which is typically the largest directory and can be several gigabytes for stores with many product images.
Offsite Backup Storage
Backups stored on the same server as your store are vulnerable to the same failures. If the server's hard drive fails, you lose both the store and the backup. Verify that your backups are copied to a separate location: a different server, cloud storage (like Amazon S3, Google Cloud Storage, or Dropbox), or downloaded to a local computer.
Check 9: Update Status (2 Minutes)
Running outdated software is the single most common reason PrestaShop stores get hacked. This final check verifies that your core installation and critical modules are up to date.
PrestaShop Core Version
Check your current PrestaShop version in the back office footer or on the Advanced Parameters > Information page. Compare it against the latest stable release on the PrestaShop website or GitHub releases page. If you are more than one minor version behind (for example, running 8.1.2 when 8.1.5 is available), plan an update. If you are running a version with known security vulnerabilities, update urgently.
PrestaShop major version upgrades (like 1.7 to 8.x) are complex migration projects, not simple updates. Do not attempt these without thorough planning and testing. But minor version updates (like 8.1.2 to 8.1.5) are generally safe and primarily contain security and bug fixes.
Critical Module Updates
Some modules handle sensitive operations and must be kept current: payment modules (any module that processes credit cards, PayPal, or other payment methods), the PrestaShop autoupgrade module (used for core updates), and any security-related modules. Check the Module Manager for available updates on these specific modules.
Your 30-Minute Audit Checklist Summary
Here is the complete checklist with time allocations that you can follow each month:
Minutes 1-3: PHP Version and Configuration. Check PHP version is supported. Verify memory_limit, max_execution_time, and OPcache status.
Minutes 4-7: Error Log Review. Scan PrestaShop logs for Severity 3 and 4 entries. Check PHP error log for fatal errors and deprecation notices. Note recurring errors for follow-up.
Minutes 8-12: Module Audit. Review disabled modules and uninstall unused ones. Check for available updates, especially on payment and security modules. Count total active modules and identify candidates for removal.
Minutes 13-16: Database Health. Check total database size. Identify bloated tables. Plan cleanup of old connection, log, and cart data.
Minutes 17-21: Security Basics. Verify admin URL is randomized. Check SSL certificate and expiration. Verify file permissions. Confirm debug mode is off. Check for known vulnerabilities in your version.
Minutes 22-25: Performance Quick Test. Run Lighthouse audit on homepage. Check LCP, INP, and CLS metrics. Verify cache and CCC settings in back office.
Minutes 26-28: SEO Basics. Check robots.txt for errors. Verify sitemap is current and complete. Spot-check canonical URLs on product pages.
Minutes 29-30: Backup and Updates. Verify backup recency and completeness. Check PrestaShop core and critical module versions against latest releases.
This audit does not fix problems. It identifies them. After completing the checklist, you should have a prioritized list of issues to address. Critical security issues and broken functionality come first. Performance optimizations and cleanup tasks come second. Minor improvements and future planning come third. By performing this audit monthly, you catch problems early, maintain a clear picture of your store's technical health, and avoid the nasty surprises that come from months of neglected maintenance.
For more details, read our guides: Is Your Store Slow? How to Check and What to Do About It and Essential PrestaShop Modules: The Must-Have List for Every Store.
Lazy Loading in 2026: What Browsers Handle Natively vs What Needs a Module
Lazy loading is a performance optimization technique that defers the loading of off-screen resources until the user scrolls near them. In 2026, native browser support for lazy loading has matured significantly, but there are still scenarios where PrestaShop store owners need additional modules or custom implementations. This guide explains exactly what browsers handle on their own, what gaps remain, and how to implement the best lazy loading strategy for your PrestaShop store.
What Native Lazy Loading Covers in 2026
The HTML loading="lazy" attribute is now supported by over 95% of browsers worldwide. This includes Chrome (since v77), Firefox (since v75), Safari (since v15.4), Edge (since v79), and all Chromium-based browsers. This means for most visitors to your store, native lazy loading works out of the box.
How Native Lazy Loading Works
Adding loading="lazy" to an <img> or <iframe> tag tells the browser to defer loading that resource until it is within a certain distance from the viewport. The browser handles all the timing and intersection logic internally, with zero JavaScript overhead.
<!-- Native lazy loading for images -->
<img src="product-image.jpg"
loading="lazy"
width="800"
height="600"
alt="Product Name">
<!-- Native lazy loading for iframes -->
<iframe src="https://www.youtube.com/embed/VIDEO_ID"
loading="lazy"
width="560"
height="315"></iframe>What Browsers Handle Natively
| Feature | Native Support | Notes |
|---|---|---|
Images (<img>) | Yes - all major browsers | Use loading="lazy" attribute |
Iframes (<iframe>) | Yes - all major browsers | Use loading="lazy" attribute |
Responsive images (<picture>) | Yes | Put loading="lazy" on the <img> inside |
| srcset images | Yes | Works with loading="lazy" on the <img> |
| Above-the-fold detection | Partial | Browsers try to detect, but not always accurate |
What Browsers Do NOT Handle
| Feature | Native Support | Solution Needed |
|---|---|---|
| CSS background images | No | IntersectionObserver API or module |
| Video elements | No | Custom JavaScript or module |
| Placeholder/blur-up effects | No | JavaScript library or module |
| Priority hints for above-fold images | Partial | fetchpriority="high" attribute |
| Dynamic/AJAX-loaded content | No | JavaScript-based lazy loading |
| Third-party widget deferral | No | Custom implementation |
Implementing Native Lazy Loading in PrestaShop
For PrestaShop 8.x and 9.x Themes
Modern PrestaShop themes (like Hummingbird for PS 9) often include native lazy loading by default. To verify or add it to your theme, edit your template files where product images are rendered.
For product listing pages, find the template that renders product thumbnails (typically themes/yourtheme/templates/catalog/_partials/miniatures/product.tpl):
{* Before - no lazy loading *}
<img src="{$product.cover.bySize.home_default.url}"
alt="{$product.name}">
{* After - with native lazy loading *}
<img src="{$product.cover.bySize.home_default.url}"
loading="lazy"
width="{$product.cover.bySize.home_default.width}"
height="{$product.cover.bySize.home_default.height}"
alt="{$product.name}">Critical Rule: Never Lazy Load Above-the-Fold Images
The most common lazy loading mistake is applying it to images that are visible without scrolling. This actually hurts performance because the browser delays loading content that the user sees immediately. Google's Core Web Vitals will penalize you for this with a higher LCP (Largest Contentful Paint) score.
Images that should NOT be lazy loaded:
- Your store logo
- Hero/banner images at the top of the page
- The first 1-2 product images on category pages
- Any image visible in the initial viewport without scrolling
For these critical images, use eager loading with priority hints:
<img src="hero-banner.jpg"
loading="eager"
fetchpriority="high"
width="1200"
height="400"
alt="Summer Sale Banner">When You Need a Module: CSS Background Images
PrestaShop themes frequently use CSS background images for sliders, banners, category headers, and promotional blocks. The loading="lazy" attribute does not work for CSS backgrounds. You need JavaScript to handle these.
IntersectionObserver Approach
// Lazy load CSS background images
document.addEventListener('DOMContentLoaded', function() {
const lazyBackgrounds = document.querySelectorAll('[data-bg]');
const observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
const el = entry.target;
el.style.backgroundImage = 'url(' + el.dataset.bg + ')';
el.classList.add('bg-loaded');
observer.unobserve(el);
}
});
}, {
rootMargin: '200px 0px'
});
lazyBackgrounds.forEach(function(bg) {
observer.observe(bg);
});
});In your HTML/Smarty template:
{* Instead of inline background-image *}
<div class="category-banner" data-bg="{$category_image_url}"></div>When You Need a Module: Placeholder Effects
Native lazy loading shows nothing until the image loads, which can cause a jarring visual experience. Modules or libraries can add:
- Blur-up effect (LQIP) - Load a tiny, blurred version first, then replace with the full image. Creates a smooth perceived loading experience.
- Skeleton screens - Gray placeholder blocks that match the image dimensions, giving the user a sense of the page layout before images load.
- Dominant color placeholders - Extract the dominant color from the image and use it as the placeholder background. Pinterest popularized this approach.
When You Need a Module: Video Lazy Loading
Product videos and embedded YouTube/Vimeo players should be lazy loaded but cannot use the native attribute (except for iframes). For HTML5 <video> elements:
// Lazy load video elements
const lazyVideos = document.querySelectorAll('video[data-src]');
const videoObserver = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
const video = entry.target;
video.src = video.dataset.src;
video.load();
videoObserver.unobserve(video);
}
});
});
lazyVideos.forEach(function(video) {
videoObserver.observe(video);
});Impact on PrestaShop Performance and Core Web Vitals
Proper lazy loading directly impacts three Core Web Vitals metrics:
- LCP (Largest Contentful Paint) - Lazy loading above-the-fold images HURTS LCP. Only lazy load below-the-fold images.
- CLS (Cumulative Layout Shift) - Images without width/height attributes cause layout shifts when they load. Always specify dimensions.
- INP (Interaction to Next Paint) - Fewer resources loading simultaneously means the main thread is less congested, improving interactivity.
Must-Have: Width and Height Attributes
Without explicit width and height attributes, the browser does not know how much space to reserve for a lazy-loaded image. When the image finally loads, the page layout shifts, causing a high CLS score.
<!-- BAD - causes layout shift -->
<img src="product.jpg" loading="lazy" alt="Product">
<!-- GOOD - reserves space, no layout shift -->
<img src="product.jpg" loading="lazy"
width="400" height="400" alt="Product">
<!-- ALSO GOOD - CSS aspect-ratio -->
<img src="product.jpg" loading="lazy"
style="aspect-ratio: 1/1; width: 100%;" alt="Product">PrestaShop-Specific Lazy Loading Recommendations
Product Listing Pages (Category Pages)
Lazy load all product images except the first row (typically 3-4 products visible above the fold). Use native loading="lazy" for product images and apply fetchpriority="high" to the first row.
Product Detail Pages
The main product image should be loaded eagerly with fetchpriority="high". Thumbnail images in the gallery can be lazy loaded. Related/cross-sell product images at the bottom should be lazy loaded.
Homepage
Slider/carousel images above the fold should be eager loaded (at minimum the first slide). Module blocks below the fold (featured products, new products, etc.) should use lazy loading.
CMS Pages
Images embedded in CMS content are the hardest to optimize because they are typically stored as raw HTML in the database. A module or custom JavaScript is needed to add loading="lazy" to images within CMS content.
Quick Implementation Checklist
- Add
loading="lazy"to all<img>tags below the fold in your theme templates - Add
widthandheightattributes to ALL images (lazy or not) - Use
loading="eager"andfetchpriority="high"on above-the-fold hero images and the first row of products - If your theme uses CSS background images for sliders/banners, implement IntersectionObserver-based lazy loading
- Test with Google PageSpeed Insights to verify LCP and CLS improvements
- Test with real devices on slow connections (Chrome DevTools throttling) to ensure images load before users scroll to them
Summary: Module vs. Native
| Scenario | Solution |
|---|---|
| Standard product images | Native loading="lazy" - no module needed |
| CSS background images | Module or custom JS with IntersectionObserver |
| Blur-up / LQIP placeholders | Module or JS library (lazysizes, lozad) |
| Video lazy loading (HTML5) | Custom JS with IntersectionObserver |
| YouTube/Vimeo embeds | Native loading="lazy" on iframe - no module |
| CMS content images | Module to auto-add loading attribute to stored HTML |
| Third-party widget deferral | Custom JS implementation |
For more details, read our guides: PrestaShop Image Optimization: Alt Tags, Lazy Loading and Page Speed and Page Speed and SEO: How Slow Loading Kills Your Google Rankings.
Rate Limiting and Bot Protection for PrestaShop Without a WAF
Bots account for over 40% of all web traffic in 2026, and not all of them are benign search engine crawlers. Scraper bots steal your product data and pricing, credential-stuffing bots attack your login pages, and inventory-hoarding bots buy out limited stock before real customers can. A Web Application Firewall (WAF) like Cloudflare Pro is the ideal solution, but many PrestaShop store owners operate on budgets that do not include enterprise security tools. This guide shows you how to implement effective bot protection using only server configuration, .htaccess rules, and lightweight modules.
Understanding the Bot Threat Landscape
Types of Malicious Bots
- Scraper bots - Crawl your entire catalog to steal product data, descriptions, images, and prices for competitor sites or counterfeit marketplaces.
- Credential stuffing bots - Try stolen username/password combinations against your login page. They can test thousands of combinations per minute.
- Inventory hoarding bots - Add products to cart and hold them, preventing real customers from purchasing limited-stock items.
- Form spam bots - Submit contact forms, registration forms, and newsletter signups with spam content or phishing links.
- DDoS bots - Flood your server with requests to make your store unavailable.
- SEO spam bots - Inject spam links into your blog comments, product reviews, or contact forms.
Method 1 - Apache .htaccess Rate Limiting
If your server runs Apache with mod_evasive or mod_ratelimit, you can limit request rates at the server level.
Using mod_ratelimit
# Limit all connections to 10 requests per second
<IfModule mod_ratelimit.c>
SetOutputFilter RATE_LIMIT
SetEnv rate-limit 400
</IfModule>Block Known Bad User Agents
# Block common scraper and attack bots
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (SemrushBot|AhrefsBot|MJ12bot|DotBot|BLEXBot) [NC]
RewriteRule .* - [F,L]
# Block empty user agents (most legitimate browsers identify themselves)
RewriteCond %{HTTP_USER_AGENT} ^-?$
RewriteRule .* - [F,L]
# Block specific known bad IPs (update regularly)
# Deny from 192.168.1.100
# Deny from 10.0.0.0/8Protect Sensitive Endpoints
# Rate limit login page
<Location "/en/login">
<IfModule mod_evasive20.c>
DOSHashTableSize 3097
DOSPageCount 5
DOSSiteCount 50
DOSPageInterval 2
DOSSiteInterval 5
DOSBlockingPeriod 60
</IfModule>
</Location>Method 2 - Nginx Rate Limiting
If your PrestaShop runs behind Nginx (either as the web server or as a reverse proxy), Nginx has built-in rate limiting that is more powerful than Apache's.
# In nginx.conf or your site's server block
# Define rate limit zones
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/m;
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
server {
# Apply rate limit to login pages
location ~ /login$ {
limit_req zone=login burst=3 nodelay;
# ... your existing configuration
}
# Apply rate limit to API/webservice
location /api/ {
limit_req zone=api burst=10;
# ... your existing configuration
}
# General rate limit for all pages
location / {
limit_req zone=general burst=20;
# ... your existing configuration
}
}Method 3 - fail2ban for Brute Force Protection
fail2ban monitors your server logs and automatically bans IP addresses that show malicious behavior. It is available on most Linux servers and is free.
Install and Configure for PrestaShop
# Install fail2ban
sudo apt-get install fail2ban
# Create a PrestaShop login filter
sudo cat > /etc/fail2ban/filter.d/prestashop-login.conf << EOF
[Definition]
failregex = ^<HOST> .* "POST .*/login.*" (401|403)
datepattern = %%d/%%b/%%Y:%%H:%%M:%%S
EOF
# Create a jail for PrestaShop
sudo cat > /etc/fail2ban/jail.d/prestashop.conf << EOF
[prestashop-login]
enabled = true
port = http,https
filter = prestashop-login
logpath = /var/log/apache2/access.log
maxretry = 10
findtime = 300
bantime = 3600
EOF
# Restart fail2ban
sudo systemctl restart fail2banMethod 4 - PHP-Level Rate Limiting
For stores on shared hosting where you cannot modify server configuration, implement rate limiting in PHP. Create a simple rate limiter that uses PrestaShop's database or file system:
// Simple file-based rate limiter for PrestaShop
// Add to a custom module's hook on actionFrontControllerInitBefore
function rateLimitCheck($maxRequests = 60, $timeWindow = 60) {
$ip = Tools::getRemoteAddr();
$cacheDir = _PS_CACHE_DIR_ . 'ratelimit/';
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0755, true);
}
$file = $cacheDir . md5($ip) . '.json';
$now = time();
if (file_exists($file)) {
$data = json_decode(file_get_contents($file), true);
// Clean old entries
$data['requests'] = array_filter(
$data['requests'],
function($timestamp) use ($now, $timeWindow) {
return ($now - $timestamp) < $timeWindow;
}
);
if (count($data['requests']) >= $maxRequests) {
header('HTTP/1.1 429 Too Many Requests');
header('Retry-After: ' . $timeWindow);
die('Rate limit exceeded. Please wait and try again.');
}
} else {
$data = ['requests' => []];
}
$data['requests'][] = $now;
file_put_contents($file, json_encode($data));
}Method 5 - robots.txt and Crawl Control
While robots.txt does not stop malicious bots (they ignore it), it reduces the load from well-behaved crawlers:
# robots.txt for PrestaShop
User-agent: *
Disallow: /modules/
Disallow: /classes/
Disallow: /controllers/
Disallow: /translations/
Disallow: /var/
Disallow: /*?order=
Disallow: /*?orderby=
Disallow: /*?orderway=
Disallow: /*?tag=
Disallow: /*?id_currency=
Disallow: /*?search_query=
Disallow: /*?back=
Disallow: /*?n=
Disallow: /en/login
Disallow: /en/my-account
Disallow: /en/cart
Disallow: /en/order
# Limit crawl rate for aggressive bots
User-agent: SemrushBot
Crawl-delay: 10
User-agent: AhrefsBot
Crawl-delay: 10
User-agent: Googlebot
Allow: /
Sitemap: https://yourstore.com/1_index_sitemap.xmlMethod 6 - CAPTCHA on Critical Forms
Add Google reCAPTCHA or hCaptcha to your most targeted pages:
- Login page - Prevents credential stuffing attacks
- Registration page - Prevents fake account creation
- Contact form - Prevents spam submissions
- Newsletter signup - Prevents list pollution
PrestaShop has official reCAPTCHA modules available. For PrestaShop 8.x+, look for modules compatible with reCAPTCHA v3 (invisible) for the best user experience.
Method 7 - Cloudflare Free Tier
Even without Cloudflare Pro (which includes WAF), the free tier provides significant bot protection:
- Browser Integrity Check - Challenges requests with suspicious HTTP headers
- Bot Fight Mode - Automatically detects and challenges bots (available on free tier)
- Rate limiting - 1 free rule with 10,000 requests/month
- Under Attack Mode - JavaScript challenge for all visitors during active attacks
Monitoring and Detection
To know if bots are attacking your store, monitor your access logs:
# Find the top 20 IP addresses by request count
awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20
# Find IPs hitting login page excessively
grep "login" /var/log/apache2/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
# Find suspicious user agents
awk -F'"' '{print $6}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -30If you see a single IP making thousands of requests, or a user agent you do not recognize making hundreds of requests per minute, you have a bot problem.
Summary of Protection Layers
| Method | Protects Against | Difficulty | Cost |
|---|---|---|---|
| .htaccess user agent blocking | Known scrapers | Easy | Free |
| fail2ban | Brute force, credential stuffing | Medium | Free |
| Nginx rate limiting | All excessive requests | Medium | Free |
| PHP rate limiter | Targeted page abuse | Medium | Free |
| CAPTCHA | Form spam, fake accounts | Easy | Free |
| Cloudflare free tier | General bot traffic, DDoS | Easy | Free |
| robots.txt crawl-delay | Well-behaved crawlers | Easy | Free |
Further reading: Visitor Control: Blocking Bad Bots and Unwanted Traffic and reCAPTCHA for PrestaShop: Protecting Your Store from Spam and Bots.
PrestaShop .htaccess Redirects: Writing Rules Without Breaking Your Store
The .htaccess file is one of the most powerful and dangerous files in your PrestaShop installation. A single misplaced character can take your entire store offline. But mastering .htaccess redirects is essential for SEO - you need them when changing URLs, migrating from another platform, removing old products, or restructuring your category tree. This guide teaches you how to write safe, effective redirect rules specifically for PrestaShop.
How PrestaShop Uses .htaccess
PrestaShop automatically generates and manages the .htaccess file. When you enable Friendly URLs in SEO & URLs settings, or click "Generate .htaccess file," PrestaShop writes rewrite rules between two marker comments:
# ~~start~~ Do not remove this comment, Prestashop will keep this comment block
# -- Your PrestaShop rules here --
# ~~end~~ Do not remove this comment, Prestashop will keep this comment blockCritical rule - Never add your custom redirects inside this block. PrestaShop will overwrite them the next time it regenerates the file. Place your custom rules BEFORE the PrestaShop block.
Understanding Redirect Types
301 - Permanent Redirect
Use when a page has permanently moved to a new URL. Search engines transfer the old page's SEO value (link juice) to the new URL. This is the most common redirect for e-commerce.
302 - Temporary Redirect
Use when a page is temporarily unavailable and will return to the original URL. Search engines keep the old URL indexed. Use this for seasonal pages, A/B tests, or maintenance.
410 - Gone
Use when a page has been permanently removed and there is no replacement. This tells search engines to remove the URL from their index. Useful for discontinued products with no alternative.
Basic Redirect Syntax
Simple One-to-One Redirects
# Redirect a single URL to a new location
Redirect 301 /old-page.html https://yourstore.com/new-page.html
# Redirect an old product URL
Redirect 301 /old-product-name.html https://yourstore.com/en/new-product-name.html
# Redirect an old category
Redirect 301 /old-category/ https://yourstore.com/en/new-category/Important - The first path (after 301) is relative to your domain root and must start with /. The second URL must be the full absolute URL including https://.
Pattern-Based Redirects with RewriteRule
For more complex redirects, use mod_rewrite with RewriteRule:
RewriteEngine On
# Redirect all pages from old domain structure
RewriteRule ^old-folder/(.*)$ https://yourstore.com/new-folder/$1 [R=301,L]
# Redirect product IDs to friendly URLs
RewriteRule ^product\.php\?id_product=([0-9]+)$ https://yourstore.com/en/product-$1.html [R=301,L]
# Redirect all .htm pages to .html
RewriteRule ^(.+)\.htm$ https://yourstore.com/$1.html [R=301,L]Common PrestaShop Redirect Scenarios
Scenario 1 - Migrating from Another Platform
When migrating from WooCommerce, Magento, or Shopify, your old URL structure will not match PrestaShop's. You need to redirect every old URL to its new PrestaShop equivalent.
# WooCommerce to PrestaShop - typical product URL migration
RewriteRule ^product/old-product-slug/?$ https://yourstore.com/en/new-prestashop-url.html [R=301,L]
# WooCommerce category to PrestaShop category
RewriteRule ^product-category/old-category/?$ https://yourstore.com/en/2-new-category.html [R=301,L]
# Magento to PrestaShop
RewriteRule ^catalog/product/view/id/([0-9]+)/?$ https://yourstore.com/en/product-$1.html [R=301,L]Scenario 2 - Removing a Language or Changing URL Structure
# Redirect old non-language URLs to new language-prefixed URLs
RewriteRule ^product-name\.html$ https://yourstore.com/en/product-name.html [R=301,L]
# Redirect old language prefix to new one
RewriteRule ^gb/(.*)$ https://yourstore.com/en/$1 [R=301,L]Scenario 3 - Forcing HTTPS and WWW
# Force HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Force www
RewriteCond %{HTTP_HOST} ^yourstore\.com$ [NC]
RewriteRule ^(.*)$ https://www.yourstore.com/$1 [R=301,L]
# Force non-www
RewriteCond %{HTTP_HOST} ^www\.yourstore\.com$ [NC]
RewriteRule ^(.*)$ https://yourstore.com/$1 [R=301,L]Scenario 4 - Removing Trailing Slashes
# Remove trailing slash (except for directories)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ https://yourstore.com/$1 [R=301,L]Scenario 5 - Bulk Product Redirects
When you have hundreds of old URLs to redirect, use a RewriteMap or include a separate file:
# Create a file called redirects.conf with your mappings
# Then include it (if your hosting allows)
# Or list them individually
Redirect 301 /old-product-1.html https://yourstore.com/en/new-product-1.html
Redirect 301 /old-product-2.html https://yourstore.com/en/new-product-2.html
Redirect 301 /old-product-3.html https://yourstore.com/en/new-product-3.htmlRules That Can Break PrestaShop
Infinite Redirect Loops
The most dangerous mistake. This happens when a rule redirects URL A to URL B, and another rule (or PrestaShop's own rules) redirects URL B back to URL A. The browser shows "Too many redirects" and the page never loads.
# DANGEROUS - can cause loops
RewriteRule ^(.*)$ https://yourstore.com/$1 [R=301,L]
# This redirects EVERYTHING, including the target URL itselfPrevention - always use conditions to prevent loops:
# SAFE - prevents loop by checking if already on correct host
RewriteCond %{HTTP_HOST} !^www\.yourstore\.com$ [NC]
RewriteRule ^(.*)$ https://www.yourstore.com/$1 [R=301,L]Breaking API and Back Office Access
Overly broad redirect rules can break the PrestaShop back office, webservice API, and module controllers:
# DANGEROUS - redirects everything including admin URLs
RewriteRule ^(.*)$ https://yourstore.com/en/$1 [R=301,L]
# SAFE - exclude admin directory and API
RewriteCond %{REQUEST_URI} !^/admin [NC]
RewriteCond %{REQUEST_URI} !^/api [NC]
RewriteCond %{REQUEST_URI} !^/modules [NC]
RewriteRule ^(.*)$ https://yourstore.com/en/$1 [R=301,L]Breaking Static Assets
Redirect rules that match CSS, JavaScript, and image files will break your store's appearance and functionality:
# DANGEROUS - redirects images and CSS
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]
# SAFE - exclude static files
RewriteCond %{REQUEST_URI} !\.(css|js|jpg|jpeg|png|gif|svg|webp|woff|woff2|ttf|eot|ico)$ [NC]
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]Testing Your Redirects Safely
Step 1 - Always Back Up First
cp .htaccess .htaccess.backupStep 2 - Test with 302 First
Use temporary (302) redirects during testing. If something goes wrong, search engines have not cached the permanent redirect. Switch to 301 only after confirming everything works.
Step 3 - Test with curl
# Check redirect chain
curl -I -L https://yourstore.com/old-page.html
# Check specific redirect
curl -I https://yourstore.com/old-page.html
# Look for: HTTP/1.1 301 Moved Permanently
# And: Location: https://yourstore.com/en/new-page.htmlStep 4 - Verify in Google Search Console
After implementing redirects, use the URL Inspection tool in Google Search Console to verify that Google can follow the redirects correctly.
Where to Place Custom Rules
# YOUR CUSTOM REDIRECTS GO HERE (before PrestaShop block)
Redirect 301 /old-page.html https://yourstore.com/new-page.html
Redirect 301 /old-category/ https://yourstore.com/en/new-category/
# ~~start~~ Do not remove this comment, Prestashop will keep this comment block
# ... PrestaShop auto-generated rules ...
# ~~end~~ Do not remove this comment, Prestashop will keep this comment blockWhen to Use a Module Instead
Consider using a redirect module instead of manual .htaccess editing when:
- You have non-technical staff who need to manage redirects
- You need to manage hundreds of redirects with a UI
- You want automatic 404 detection and redirect suggestions
- You need redirect analytics (how many times each redirect is hit)
- You want to import/export redirects in bulk via CSV
Redirect modules store the mappings in the database and use a single PHP-based catch-all rule instead of adding lines to .htaccess. This is often safer and more maintainable for large redirect sets.
Quick Reference Cheat Sheet
| Task | Rule |
|---|---|
| Single page redirect | Redirect 301 /old https://site.com/new |
| Pattern redirect | RewriteRule ^old/(.*)$ https://site.com/new/$1 [R=301,L] |
| Force HTTPS | RewriteCond %{HTTPS} off + RewriteRule |
| Exclude directory | RewriteCond %{REQUEST_URI} !^/admin |
| Exclude file types | RewriteCond %{REQUEST_URI} !\.(css|js|jpg)$ |
| Remove trailing slash | RewriteCond %{REQUEST_FILENAME} !-d |
For more details, read our guides: PrestaShop .htaccess: Security and Performance Rules You Need and What Are Friendly URLs and Why Every PrestaShop Store Needs Them.
PHP Version Compatibility Matrix for PrestaShop
Choosing the right PHP version for your PrestaShop store is one of the most critical infrastructure decisions you will make. Running an incompatible PHP version can cause white screens, broken checkout flows, module failures, and security vulnerabilities. This comprehensive guide covers every PrestaShop release from 1.6 through 9.x and maps each one to its supported PHP versions, recommended configurations, and upgrade considerations.
Why PHP Version Matters for PrestaShop
PHP is the server-side language that powers PrestaShop. Each major PHP release introduces performance improvements, new language features, and deprecates older functions. PrestaShop's codebase evolves alongside PHP, meaning that newer PrestaShop versions take advantage of modern PHP features while dropping support for outdated ones.
Running the wrong PHP version causes three categories of problems:
- Fatal errors - Functions removed in newer PHP versions (e.g.,
mysql_*functions removed in PHP 7.0,each()removed in PHP 8.0) cause immediate crashes. - Deprecation warnings - Deprecated functions generate warnings that can break AJAX responses, JSON output, and PDF generation when
display_errorsis enabled. - Security exposure - PHP versions that have reached end-of-life no longer receive security patches, leaving your store vulnerable.
Complete Compatibility Matrix
PrestaShop 1.6.x
| PrestaShop Version | PHP 5.4 | PHP 5.5 | PHP 5.6 | PHP 7.0 | PHP 7.1 | PHP 7.2+ |
|---|---|---|---|---|---|---|
| 1.6.0.x - 1.6.0.14 | Yes | Yes | Yes | No | No | No |
| 1.6.1.0 - 1.6.1.4 | Yes | Yes | Yes | Partial | No | No |
| 1.6.1.5 - 1.6.1.23 | Yes | Yes | Yes | Yes | Yes | No |
| 1.6.1.24+ | Yes | Yes | Yes | Yes | Yes | No |
Recommended PHP for 1.6.x - PHP 7.1. It offers the best balance of performance and compatibility. Running 1.6.x on PHP 7.2+ requires core file modifications that break the upgrade path and are not recommended.
PrestaShop 1.7.x
| PrestaShop Version | PHP 7.1 | PHP 7.2 | PHP 7.3 | PHP 7.4 | PHP 8.0+ |
|---|---|---|---|---|---|
| 1.7.0.x - 1.7.4.x | Yes (recommended) | No | No | No | No |
| 1.7.5.x | Yes | Yes (recommended) | No | No | No |
| 1.7.6.x | Yes | Yes (recommended) | Yes | No | No |
| 1.7.7.x | Yes | Yes | Yes (recommended) | Partial | No |
| 1.7.8.x | Yes | Yes | Yes | Yes (recommended) | No |
Critical warning - No version of PrestaShop 1.7 supports PHP 8.0 or later. If you run PS 1.7.6 on PHP 8, Smarty will crash immediately because the template engine uses functions that were removed in PHP 8.0. The each() function removal and changes to how array_key_exists() works with objects cause fatal errors.
PrestaShop 8.x
| PrestaShop Version | PHP 7.2 | PHP 7.3 | PHP 7.4 | PHP 8.0 | PHP 8.1 | PHP 8.2 | PHP 8.3 |
|---|---|---|---|---|---|---|---|
| 8.0.0 - 8.0.2 | Yes (min) | Yes | Yes | Yes | Partial | No | No |
| 8.0.3 - 8.0.5 | Yes (min) | Yes | Yes | Yes | Yes (recommended) | No | No |
| 8.1.0 - 8.1.2 | No | Yes (min) | Yes | Yes | Yes (recommended) | Partial | No |
| 8.1.3 - 8.1.7 | No | Yes (min) | Yes | Yes | Yes (recommended) | Yes | Partial |
Recommended PHP for 8.x - PHP 8.1. It is the sweet spot offering full compatibility, active security support, and excellent performance with JIT compilation. PHP 8.1 brings fibers, enums, readonly properties, and intersection types that PrestaShop 8 can leverage.
PrestaShop 9.x
| PrestaShop Version | PHP 8.1 | PHP 8.2 | PHP 8.3 | PHP 8.4 |
|---|---|---|---|---|
| 9.0.x | Yes (min) | Yes | Yes (recommended) | Yes |
Recommended PHP for 9.x - PHP 8.3 or 8.4. PrestaShop 9 runs on Symfony 6.4 LTS and requires PHP 8.1 as its minimum. PHP 8.4 brings property hooks and asymmetric visibility that future PrestaShop updates will leverage.
PHP End-of-Life Dates You Must Know
| PHP Version | Active Support Until | Security Fixes Until | Status (2026) |
|---|---|---|---|
| PHP 7.4 | Nov 2021 | Nov 2022 | EOL - Dangerous |
| PHP 8.0 | Nov 2022 | Nov 2023 | EOL - Dangerous |
| PHP 8.1 | Nov 2023 | Dec 2025 | EOL - Upgrade soon |
| PHP 8.2 | Dec 2024 | Dec 2026 | Security only |
| PHP 8.3 | Dec 2025 | Dec 2027 | Security only |
| PHP 8.4 | Dec 2026 | Dec 2028 | Active support |
If you are running PHP 7.4 or 8.0 in 2026, you are running on an unsupported version that no longer receives security patches. This is a critical risk for any e-commerce store handling payment data.
How to Check Your Current PHP Version
Method 1 - PrestaShop Back Office
Navigate to Advanced Parameters > Information. The Server Information section displays your PHP version, along with memory limit, max execution time, and other relevant settings.
Method 2 - PHP Info File
Create a file named phpinfo.php in your store's root directory with this content:
<?php phpinfo();Access it via your browser at https://yourstore.com/phpinfo.php. Delete this file immediately after checking - it exposes sensitive server configuration details.
Method 3 - Command Line
php -v
php -r "echo PHP_VERSION;"Note that the CLI PHP version may differ from the web server PHP version. Always verify through the web interface or phpinfo().
Common Issues When Running Wrong PHP Versions
White Screen of Death (WSOD)
The most common symptom of PHP incompatibility. Check your PHP error log (usually at /var/log/php-errors.log or accessible via your hosting panel). Typical errors include:
Fatal error: Uncaught Error: Call to undefined function mysql_connect()
Fatal error: Uncaught Error: Call to undefined function each()
Fatal error: Cannot use "parent" when current class scope has no parentDeprecation Warnings Breaking AJAX
When display_errors = On and you upgrade PHP, deprecation notices get prepended to AJAX responses. This breaks the JSON parsing in the back office, causing features like product search, customer lookup, and order creation to fail silently. The fix:
; php.ini
display_errors = Off
log_errors = On
error_log = /path/to/php-error.logModule Incompatibility
Third-party modules may not support your PHP version. Before upgrading PHP, check each installed module for compatibility. Common problem areas:
- Modules using
create_function()- removed in PHP 8.0 - Modules using
mysql_*functions - removed in PHP 7.0 - Modules using positional string access with curly braces
$str{0}- removed in PHP 8.0 - Modules not handling nullable return types - stricter in PHP 8.1+
How to Safely Upgrade PHP for PrestaShop
Step 1 - Audit Your Current Setup
Before changing anything, document your current environment:
php -v # Current PHP version
php -m # Loaded extensions
php -i | grep memory # Memory limit
php -i | grep max_exec # Execution time limitStep 2 - Check Module Compatibility
Review every installed module. Check the module developer's documentation for PHP version support. If a module has not been updated in over two years, it is likely incompatible with PHP 8.x.
Step 3 - Test on Staging First
Never upgrade PHP on your production server without testing. Create a staging copy of your store and test with the new PHP version. Check:
- Front office pages load correctly
- Product pages, category pages, CMS pages
- Cart and checkout process completes
- Payment modules process test transactions
- Back office functionality works (product editing, order management)
- All third-party modules function correctly
- Cron jobs execute without errors
Step 4 - Upgrade with Rollback Plan
Most hosting providers allow you to switch PHP versions from the control panel (cPanel, Plesk, DirectAdmin). Keep the previous PHP version available for quick rollback if issues arise.
Step 5 - Clear All Caches After Upgrade
After switching PHP versions, clear every cache layer:
# Clear PrestaShop cache
rm -rf var/cache/prod/* var/cache/dev/*
# Clear Smarty compiled templates
rm -rf var/cache/smarty/compile/* var/cache/smarty/cache/*
# If using OPcache, restart PHP-FPM
systemctl restart php8.3-fpm
# Clear any CDN cache (Cloudflare, etc.)PHP Configuration Best Practices for PrestaShop
Regardless of which PHP version you choose, these settings are essential for optimal PrestaShop performance:
; php.ini recommended settings
memory_limit = 512M
max_execution_time = 300
max_input_vars = 10000
post_max_size = 32M
upload_max_filesize = 32M
; OPcache settings (critical for performance)
opcache.enable = 1
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 32
opcache.max_accelerated_files = 16229
opcache.revalidate_freq = 60
opcache.fast_shutdown = 1
; Required extensions
extension = intl
extension = zip
extension = gd
extension = curl
extension = mbstring
extension = openssl
extension = pdo_mysql
extension = fileinfoModule Developer Considerations
If you develop PrestaShop modules, you need to consider PHP compatibility carefully:
- Minimum PHP version - Target PHP 7.2 as minimum for modules that should work on PrestaShop 8.0+, or PHP 8.1 for PrestaShop 9-only modules.
- Use PHPStan or Psalm - Static analysis tools catch PHP version incompatibilities before your users do.
- Avoid version-specific syntax - Features like match expressions (PHP 8.0), enums (PHP 8.1), and readonly properties (PHP 8.1) limit your module to those PHP versions and above.
- Test on multiple versions - Use Docker containers with different PHP versions to test your module across the compatibility range.
Frequently Asked Questions
Can I run PrestaShop 1.7 on PHP 8?
No. No version of PrestaShop 1.7 officially supports PHP 8.0 or later. While some users have applied patches to make it partially work, this is unsupported and will break with updates. The correct path is to upgrade to PrestaShop 8.x.
Should I use PHP 8.4 with PrestaShop 8.1?
Not recommended. PrestaShop 8.1 was developed and tested primarily with PHP 8.1. While PHP 8.2 has partial support in later 8.1.x releases, PHP 8.4 introduces changes that may cause issues with older Symfony components. Stick with PHP 8.1 for PrestaShop 8.x.
How much faster is PHP 8.x compared to 7.x?
Benchmarks show PHP 8.1 is approximately 20-30% faster than PHP 7.4 for typical PrestaShop workloads. The JIT compiler provides the most benefit for computational tasks. For I/O-bound operations (database queries, file reads), the improvement is smaller but still measurable.
Does upgrading PHP require upgrading PrestaShop?
Not necessarily, but they go hand in hand. You can upgrade PHP within the supported range for your PrestaShop version without upgrading PrestaShop itself. However, if you want to run a modern PHP version (8.3+), you will need PrestaShop 8.1 or 9.x.
For more details, read our guides: PrestaShop 1.7 vs 8 vs 9: Which Version Should You Be Running? and What PrestaShop 9 Changed and Why Module Compatibility Matters.
What Content Security Policy Is and Why It Matters
Content Security Policy (CSP) is a security mechanism implemented through HTTP headers that tells the browser exactly which resources are allowed to load on your pages. It prevents cross-site scripting (XSS) attacks, data injection attacks, and other code injection vulnerabilities by giving you granular control over where JavaScript, CSS, images, fonts, frames, and other resources can originate from.
Without CSP, a browser will execute any JavaScript it encounters on your page, regardless of where it came from. If an attacker manages to inject a malicious script (through a vulnerable module, a compromised third-party library, or a stored XSS vulnerability), the browser happily executes it with full access to the page content, including customer data, form inputs, and session cookies.
With CSP, you declare a whitelist of trusted sources. If the browser encounters a resource that does not match the policy, it blocks it and logs a violation. This means that even if an attacker finds a way to inject code into your page, the browser refuses to execute it because it does not come from an approved source.
For PrestaShop stores that handle customer personal information, payment data, and authentication credentials, CSP is a critical security layer. It is not a replacement for fixing vulnerabilities in your code, but it is an effective defense-in-depth measure that limits the damage when a vulnerability exists.
CSP Directives Explained
A Content Security Policy consists of one or more directives, each controlling a specific type of resource. The most important directives for PrestaShop are:
default-src: The fallback directive. If a more specific directive is not set, the browser uses default-src. Setting default-src 'self' means that by default, only resources from your own domain are allowed.
script-src: Controls where JavaScript can be loaded from. This is the most critical directive for XSS prevention. Common values include 'self' (your own domain), specific CDN domains, and analytics domains.
style-src: Controls where CSS can be loaded from. PrestaShop themes and modules frequently use inline styles, which means you may need 'unsafe-inline' unless you implement a nonce-based approach.
img-src: Controls where images can be loaded from. PrestaShop stores often load images from their own domain, CDN domains, and third-party services like Google (for user avatars or Maps).
font-src: Controls where fonts can be loaded from. Google Fonts, Font Awesome CDN, and your own domain are common sources.
connect-src: Controls which URLs can be contacted via JavaScript (AJAX requests, WebSocket connections, EventSource). Payment gateways, analytics endpoints, and your own API endpoints need to be listed here.
frame-src: Controls which domains can be embedded in iframes. Payment gateways like PayPal, Stripe, and Klarna use iframes for their payment forms. YouTube and Vimeo embeds also require frame-src entries.
frame-ancestors: Controls which domains can embed your page in an iframe. Setting frame-ancestors 'self' prevents clickjacking attacks by ensuring your store cannot be embedded in another site's iframe.
object-src: Controls plugin content like Flash. Set this to 'none' because Flash is obsolete and no PrestaShop functionality requires it.
base-uri: Controls which URLs can be used in the <base> element. Set to 'self' to prevent base URI manipulation attacks.
form-action: Controls which URLs forms can submit to. This should include your own domain and any external payment processing endpoints.
Starting with Report-Only Mode
Deploying CSP on a PrestaShop store requires careful preparation because an overly restrictive policy will break functionality. The right approach is to start with report-only mode, which tells the browser to report violations without actually blocking anything.
Instead of using the Content-Security-Policy header, use Content-Security-Policy-Report-Only. This header accepts the exact same directives but only generates reports without enforcing the policy. Your store continues to function normally while you collect data about what would be blocked.
Setting Up Violation Reporting
Add a report-uri directive to your policy that points to an endpoint that collects violation reports. You can use a free service like Report URI (report-uri.com), which provides a dashboard for viewing and analyzing CSP violations, or you can set up your own endpoint.
The browser sends violation reports as JSON POST requests. Each report includes the blocked URI, the directive that was violated, the page where the violation occurred, and other useful debugging information. Collecting these reports for a week or two on a live store gives you a comprehensive picture of all the resources your store loads and where they come from.
Building Your Initial Policy
Using the violation reports from report-only mode, build a whitelist of all legitimate resource sources. Group them by directive type. Your initial policy will likely include:
Your own domain for all resource types. CDN domains (like cdnjs.cloudflare.com, fonts.googleapis.com, fonts.gstatic.com) for scripts, styles, and fonts. Analytics domains (like google-analytics.com, googletagmanager.com, connect.facebook.net) for tracking. Payment gateway domains for scripts, frames, and connections. Chat widget domains if you use live chat. Social media domains for embedded content or share buttons.
Building a CSP for PrestaShop
PrestaShop presents specific challenges for CSP implementation because of its architecture and the modules ecosystem.
Handling Inline Styles and Scripts
PrestaShop core, themes, and many modules use inline styles and inline JavaScript extensively. Inline code is blocked by default in CSP because an attacker who injects content into your page would be injecting inline code. There are three approaches to handling this:
Using 'unsafe-inline': The simplest but least secure approach. Adding 'unsafe-inline' to script-src and style-src allows all inline code, which significantly weakens CSP's XSS protection. For style-src, this is generally acceptable because inline styles pose a much lower security risk than inline scripts. For script-src, avoid 'unsafe-inline' if at all possible.
Using nonces: The recommended approach. A nonce is a random, single-use token generated on each request. You add the nonce to your CSP header (script-src 'nonce-abc123') and to each legitimate inline script tag (<script nonce="abc123">). The browser only executes inline scripts that have the correct nonce. Since the nonce changes on every request and an attacker cannot predict it, injected scripts without the nonce are blocked.
Implementing nonces in PrestaShop requires modifying the theme to add nonce attributes to all inline script tags and creating a mechanism (typically a module or a custom hook) that generates the nonce, adds it to the CSP header, and makes it available to templates. This is a significant implementation effort but provides strong XSS protection.
Using hashes: You can whitelist specific inline scripts by their SHA-256 hash. The browser computes the hash of each inline script it encounters and checks it against the hashes listed in the CSP. This approach works for inline scripts that do not change between requests (static inline scripts), but it is impractical for PrestaShop because many inline scripts include dynamic content like product IDs, prices, and user-specific data that change the hash.
Handling eval and Dynamic Code
Some JavaScript libraries use eval() or new Function() to dynamically create and execute code. CSP blocks these by default. If a module or library requires eval, you must add 'unsafe-eval' to script-src. Common culprits include older versions of jQuery templates, some analytics scripts, and certain payment gateway libraries.
Check your violation reports for entries with eval or inline as the blocked URI. These indicate code that uses dynamic evaluation. Where possible, replace the library with a version that does not use eval. When that is not possible (such as with a third-party payment gateway library you cannot modify), 'unsafe-eval' is the only option.
Third-Party Services
Most PrestaShop stores rely on multiple third-party services, each of which needs to be whitelisted in your CSP. Here are the most common ones and the directives they require:
Google Analytics and Google Tag Manager: These require entries in script-src for www.google-analytics.com, www.googletagmanager.com, and tagmanager.google.com. They also need connect-src entries for www.google-analytics.com and analytics.google.com (for sending tracking data), and img-src entries for www.google-analytics.com (for the tracking pixel). Google Tag Manager is particularly challenging because it dynamically loads scripts from domains you may not know in advance, as the scripts loaded depend on the tags configured in GTM.
PayPal: Requires script-src and frame-src entries for *.paypal.com and *.paypalobjects.com. The exact domains depend on whether you use PayPal Standard, PayPal Express, or the newer PayPal Commerce Platform integration.
Stripe: Requires script-src for js.stripe.com, frame-src for js.stripe.com and hooks.stripe.com, and connect-src for api.stripe.com.
Google Fonts: Requires style-src for fonts.googleapis.com and font-src for fonts.gstatic.com.
YouTube embeds: Require frame-src for www.youtube.com and www.youtube-nocookie.com.
Facebook Pixel and social plugins: Require script-src and connect-src for connect.facebook.net and www.facebook.com, plus img-src for www.facebook.com and *.fbcdn.net.
Live chat widgets (Tidio, Crisp, Intercom, etc.): Each has its own set of domains for scripts, styles, WebSocket connections, and images. Check your violation reports or the provider's documentation for the exact domains required.
A Complete CSP Example for PrestaShop
Here is a realistic CSP header for a PrestaShop store that uses Google Analytics, Google Fonts, PayPal, YouTube embeds, and has inline styles:
Content-Security-Policy: default-src 'self'; script-src 'self' www.google-analytics.com www.googletagmanager.com js.stripe.com 'unsafe-inline' 'unsafe-eval'; style-src 'self' fonts.googleapis.com 'unsafe-inline'; img-src 'self' data: www.google-analytics.com *.paypal.com; font-src 'self' fonts.gstatic.com; connect-src 'self' www.google-analytics.com analytics.google.com api.stripe.com; frame-src 'self' www.youtube.com www.youtube-nocookie.com js.stripe.com *.paypal.com; frame-ancestors 'self'; object-src 'none'; base-uri 'self'; form-action 'self' *.paypal.com;
This policy includes 'unsafe-inline' and 'unsafe-eval' for scripts, which weakens XSS protection but is necessary for most PrestaShop installations that have not been modified to support nonces. For img-src, the data: source is included because PrestaShop and many modules use data URIs for small images and icons.
Implementing CSP in PrestaShop
Via .htaccess (Apache)
For Apache servers, add the CSP header in your .htaccess file. Place it near the top of the file, before the PrestaShop rewrite rules:
Header set Content-Security-Policy "default-src 'self'; script-src 'self' ..."
This requires the mod_headers module to be enabled. You can verify by checking if your server returns the header using browser DevTools (Network tab, click on the main document request, check the Response Headers).
Via Nginx Configuration
For Nginx, add the header in your server block:
add_header Content-Security-Policy "default-src 'self'; script-src 'self' ..." always;
The always parameter ensures the header is sent even for error responses, which is important because error pages can also be targets for XSS attacks.
Via a PrestaShop Module
Implementing CSP through a module gives you the ability to manage the policy from the back office. The module hooks into the actionOutputHTMLBefore or uses PHP's header() function in a front controller hook to add the CSP header to every response. A module-based approach is easier to maintain because you can update the policy without editing server configuration files and without restarting the web server.
Testing Your CSP with Browser DevTools
After implementing your CSP (in report-only mode initially), use browser DevTools to monitor for violations. Open the Console tab and look for messages that start with "[Report Only]" (in report-only mode) or "Refused to" (in enforcement mode). Each message tells you exactly what was blocked and which directive was responsible.
Test every page type on your store: the home page, category pages, product pages, the cart, the checkout process (including each step and each payment method), the customer account pages, and CMS pages. Each page type may load different resources, and you need to ensure your policy covers all of them.
Pay special attention to the checkout process. A blocked payment gateway script or iframe during checkout directly prevents customers from completing purchases. Test every payment method you offer, including the 3D Secure verification flow if applicable, because these often load additional resources from domains that are not obvious.
Common Testing Pitfalls
Testing in a development environment may not reveal all violations because your development setup may not include all the third-party services that run on production (analytics, advertising pixels, live chat, A/B testing tools). Always deploy CSP in report-only mode on production first and collect reports for at least one to two weeks before switching to enforcement.
Some violations only occur under specific conditions. For example, a payment gateway might load additional verification scripts only when a customer's card requires 3D Secure authentication. Social sharing buttons might load scripts only when a visitor clicks them. Dynamic content loaded via AJAX may reference resources that are not present on the initial page load. Run through every possible user flow during testing.
Gradual Enforcement Strategy
The recommended deployment strategy for CSP on PrestaShop follows these steps:
Phase 1: Discovery. Deploy a permissive Content-Security-Policy-Report-Only header with default-src * 'unsafe-inline' 'unsafe-eval' data: blob:; and a report-uri. This logs all resources without blocking anything, giving you a complete inventory of what your store loads.
Phase 2: Draft policy. Based on the violation reports, build a whitelist policy that covers all legitimate resources. Deploy it in report-only mode and monitor for violations that indicate you missed a resource.
Phase 3: Refine. Over one to two weeks, check violation reports daily and add any legitimate sources you missed. Pay attention to reports that come from specific page types or user flows you might not have tested manually.
Phase 4: Enforce. Switch from Content-Security-Policy-Report-Only to Content-Security-Policy. Keep the report-uri directive so you continue receiving violation reports. Monitor closely for the first week after enforcement to catch any legitimate resources that are being blocked.
Phase 5: Tighten. Once enforcement is stable, look for opportunities to tighten the policy. Can you replace 'unsafe-inline' in script-src with nonces? Can you narrow wildcard domains to specific subdomains? Can you remove sources that are no longer used? Each tightening step improves your security posture.
Maintaining Your CSP
A CSP is not a set-and-forget configuration. Every time you install a new module, add a third-party service, change payment gateways, or update your theme, you may need to update your CSP to include new resource sources. Make CSP review part of your module installation and update process.
Keep your report-uri active even after enforcement so you receive alerts about new violations. A sudden increase in violation reports might indicate that a module update introduced new resource requirements, or it might indicate an actual XSS attack attempt that your CSP is successfully blocking. Either way, you want to know about it.
Document your CSP and the reason for each entry. Over time, policies accumulate entries for services you no longer use. Periodic reviews to remove unnecessary entries keep the policy clean and reduce the attack surface. A CSP with fewer allowed sources is inherently more secure than one with many.
For more details, read our guides: PrestaShop Security Hardening: The Complete Checklist and PrestaShop .htaccess: Security and Performance Rules You Need.
How PrestaShop Handles Product Images
Every image uploaded to PrestaShop goes through a processing pipeline. When you add a product image, the system stores the original file and then generates multiple resized versions called thumbnails. Each thumbnail corresponds to an image type defined in the back office under Design > Image Settings. These image types specify exact pixel dimensions and are tied to specific contexts: product listings, product pages, cart previews, category headers, manufacturer logos, and more.
PrestaShop stores images in the /img/ directory. In PrestaShop 1.7 and 8.x, product images are organized using a directory structure based on the image ID. For example, an image with ID 1234 is stored at /img/p/1/2/3/4/. Inside that directory, you will find the original image (named by ID, like 1234.jpg) and all generated thumbnails (like 1234-home_default.jpg, 1234-large_default.jpg, 1234-small_default.jpg).
The naming convention follows the pattern: {image_id}-{image_type_name}.{extension}. This means every image type you define creates an additional file for every product image in your catalog. A store with 5,000 product images and 8 image types will have approximately 45,000 image files (5,000 originals plus 5,000 times 8 thumbnails). This scale matters when you need to regenerate them.
Understanding Image Types
Image types are defined in the database table ps_image_type and managed through the back office. Each image type has a name, width, height, and flags indicating which entity types it applies to (products, categories, manufacturers, suppliers, stores). The default PrestaShop installation includes several image types:
cart_default is typically 125x125 pixels, used in the shopping cart and mini cart. small_default is around 98x98 pixels, used in product listings on some themes. medium_default is around 452x452 pixels, used for product thumbnails on the product page. home_default is around 250x250 pixels, used on the homepage and category listings. large_default is around 800x800 pixels, used as the main product image on the product page.
Themes can define their own image type requirements. When you install a new theme, it typically registers its preferred image types during installation. The critical point is that the actual image files on disk must match what the theme expects. If the theme requests home_default at 340x340 but your image files were generated at 250x250 because you used a different theme previously, every product listing will display incorrectly sized images.
When Image Regeneration Is Necessary
Several situations require a full or partial thumbnail regeneration. Understanding when it is truly necessary saves you from running a process that can take hours on large catalogs.
Theme Change
This is the most common reason. Different themes require different image dimensions. When you switch from one theme to another, the new theme's templates reference image types with specific dimensions. If those dimensions do not match the existing thumbnail files, images appear stretched, cropped incorrectly, or blurry. After installing a new theme, always check its image type requirements and regenerate thumbnails to match.
Image Type Dimension Changes
If you modify the width or height of an existing image type through Design > Image Settings, the change only affects the database definition. All existing thumbnail files on disk retain their old dimensions. You must regenerate thumbnails for the modified image type to apply the new dimensions to existing images.
Adding a New Image Type
When you create a new image type, no thumbnail files exist for it yet. If a template references this new image type, it will display broken image links until you regenerate. The regeneration process creates the missing thumbnail files for every existing image.
Image Quality Issues
If you change the JPEG compression quality setting in PrestaShop (found in Performance > Image Settings or the image configuration section depending on your version), existing thumbnails were generated with the old quality setting. Regeneration applies the new quality level to all thumbnails.
After a Migration or Server Move
Sometimes during migration, thumbnail files get lost or corrupted while original images survive. If product images appear broken but originals exist in the expected directories, regeneration recreates all thumbnails from the originals.
Enabling WebP Format
PrestaShop 8.x introduced WebP support for product images. When you enable WebP generation, existing images do not automatically get WebP variants. You must regenerate thumbnails to create the .webp versions alongside the existing JPEG or PNG files.
Regeneration Through the Admin Panel
PrestaShop provides a built-in regeneration tool in the back office under Design > Image Settings (or Preferences > Images in older versions). At the bottom of the page, you will find the regeneration section.
Options Available
You can choose to erase previous images before regenerating. When enabled, PrestaShop deletes all existing thumbnails before creating new ones. This is useful when you want to remove thumbnails for image types that no longer exist, but it means all images will be unavailable during the regeneration process. When disabled, PrestaShop overwrites existing thumbnails and creates missing ones without deleting anything first.
You can select which entity types to regenerate: products, categories, manufacturers, suppliers, or stores. If you only changed product image dimensions, there is no need to regenerate category or manufacturer images.
Limitations of the Admin Panel Approach
The admin panel regeneration runs as a web request. This creates several problems for large catalogs. Web servers have execution time limits, typically 30 to 300 seconds depending on your configuration. A store with 10,000 product images and 8 image types needs to generate 80,000 thumbnail files. Even at a generous 10 images per second, that takes over two hours. Most web servers will terminate the process long before it finishes.
Memory limits also apply. Each image must be loaded into memory, resized using GD or ImageMagick, and saved. High-resolution original images can consume 20 to 50 MB of memory each during processing. PHP's default memory limit of 128 MB or 256 MB can be exhausted quickly, especially when processing images in sequence without proper memory cleanup.
If the process is interrupted by a timeout or memory error, you end up with a partially regenerated catalog. Some products have new thumbnails, others have old ones, and some might have none at all. This inconsistent state is worse than the original problem.
CLI Regeneration for Large Catalogs
For stores with more than a few hundred products, command-line regeneration is strongly recommended. It bypasses web server timeout limits and can be configured with higher memory limits.
Using the PrestaShop Console
PrestaShop 1.7.5 and later include a Symfony console. You can regenerate thumbnails using:
php bin/console prestashop:image:regenerate
This command accepts several options. To regenerate only specific image types, use the --image-type flag followed by the image type name. To process only products, categories, or other specific entity types, use the --entity flag. The --format flag lets you specify which output formats to generate (jpg, png, webp).
Run the command from your PrestaShop root directory. If you are using Docker, execute it inside the container:
docker exec -u www-data your-container php bin/console prestashop:image:regenerate
The -u www-data flag ensures generated files are owned by the web server user. Running as root creates files that the web server cannot serve or modify later.
Memory and Time Configuration
For CLI execution, you can increase PHP limits directly in the command:
php -d memory_limit=512M -d max_execution_time=0 bin/console prestashop:image:regenerate
Setting max_execution_time=0 removes the time limit entirely, and 512 MB of memory is sufficient for most catalogs. For stores with extremely high-resolution originals (4000x4000 pixels or larger), you may need 1 GB or more.
Custom Regeneration Approach
For very large catalogs (50,000 or more images), even the console command can be slow or problematic. A custom PHP approach lets you process images in batches with progress tracking, error handling, and the ability to resume after interruption.
The approach involves querying the database for all image records, iterating through them in batches of 100 or 200, generating thumbnails for each image, and logging progress. If the process is interrupted, you can resume from where it stopped by checking which thumbnails already exist.
A batch approach also allows you to spread the regeneration across multiple runs during off-peak hours, avoiding performance impact on the live store.
WebP Generation During Regeneration
WebP is a modern image format that provides significantly smaller file sizes than JPEG at comparable quality. PrestaShop 8.x can generate WebP versions of thumbnails during the regeneration process.
Enabling WebP Support
Before regenerating, enable WebP in your PrestaShop configuration. In PrestaShop 8.x, this option is in the image settings. When enabled, the regeneration process creates both the traditional JPEG/PNG thumbnail and a .webp version for each image type.
Server Requirements
WebP generation requires either the GD extension compiled with WebP support (--with-webp) or the ImageMagick extension with WebP delegates. You can check GD support with phpinfo() or gd_info(). Look for WebP Support in the output. If WebP support is missing, the regeneration process silently skips WebP creation without producing errors.
Disk Space Considerations
WebP files are typically 25 to 35 percent smaller than equivalent JPEG files, but you are storing both formats. A store with 40,000 JPEG thumbnails taking 2 GB of disk space will need approximately 3.4 GB total after WebP generation (the original 2 GB plus roughly 1.4 GB of WebP files). Plan your disk space accordingly before starting a full regeneration.
Serving WebP to Browsers
Generating WebP files is only half the solution. Your theme and server must be configured to serve WebP to browsers that support it while falling back to JPEG/PNG for browsers that do not. This is typically handled through <picture> elements in the theme templates or through server-side content negotiation using the Accept header.
In Apache, you can add rewrite rules that check for WebP support and serve the WebP version when available. In Nginx, the try_files directive can check for a .webp version of the requested image and serve it if the browser's Accept header includes image/webp.
Performance Impact and Mitigation
Image regeneration is CPU-intensive and I/O-heavy. On a live store, it can degrade performance significantly if not managed carefully.
CPU Impact
Each image resize operation requires loading the original into memory, performing the resize algorithm, applying any quality/compression settings, and writing the result to disk. The resize operation itself is computationally expensive, especially for large images being scaled down to small thumbnails. On a shared hosting environment, this can saturate the CPU and slow down the entire store.
I/O Impact
Regeneration reads every original image and writes multiple thumbnail files. On traditional hard drives, this creates significant I/O load. On SSD storage, the impact is much lower but still noticeable at scale. The I/O pattern is particularly unfriendly to spinning disks because it involves random reads (originals scattered across directories) combined with sequential writes (thumbnails in the same directories).
Running Regeneration During Off-Peak Hours
Schedule regeneration for your lowest-traffic period. For European stores, this is typically between 2 AM and 6 AM. For stores with global traffic, there may not be a true off-peak, but you can identify relative low points from your analytics data.
Using Nice and Ionice
On Linux servers, you can reduce the priority of the regeneration process so it does not starve other processes of resources. The nice command lowers CPU priority, and ionice lowers I/O priority:
nice -n 19 ionice -c 3 php bin/console prestashop:image:regenerate
A nice value of 19 is the lowest priority. Ionice class 3 is the idle class, meaning the process only gets I/O time when nothing else needs it. This dramatically reduces the impact on the live store but makes the regeneration take longer.
Temporary Scaling
If you are on a cloud server, consider temporarily scaling up your server (more CPU cores, more RAM, faster storage) for the duration of the regeneration, then scaling back down. The extra cost for a few hours of higher-tier resources is usually minimal compared to the impact of a slow, multi-day regeneration on your store's performance.
Avoiding Timeouts During Regeneration
Timeouts are the most common problem with image regeneration. Here are the specific settings and configurations that prevent them.
PHP Configuration
The max_execution_time directive limits how long a PHP process can run. For CLI execution, this is typically already set to 0 (unlimited), but verify by checking php -i | grep max_execution_time. For web-based regeneration through the admin panel, increase this value in your php.ini or .htaccess:
php_value max_execution_time 7200
Also increase max_input_time if you are using the admin panel, as the form submission timeout is separate from execution timeout:
php_value max_input_time 7200
Web Server Timeout
Apache's Timeout directive and Nginx's proxy_read_timeout / fastcgi_read_timeout can terminate long-running requests even if PHP itself has not timed out. For Apache: Timeout 7200. For Nginx, add to your server block: fastcgi_read_timeout 7200; or proxy_read_timeout 7200;.
PHP-FPM Configuration
If you use PHP-FPM (which most modern setups do), the request_terminate_timeout in your pool configuration can also kill long-running processes. Set it to 0 to disable the timeout, or match it to your desired maximum runtime:
request_terminate_timeout = 7200
Cloudflare and CDN Timeouts
If your store is behind Cloudflare or another CDN, the CDN has its own request timeout (Cloudflare's free plan has a 100-second timeout). This makes admin panel regeneration effectively impossible behind a CDN. You must either use CLI regeneration, bypass the CDN for admin access, or use a solution that processes images asynchronously.
Incremental Regeneration Strategies
Full regeneration processes every image in the catalog. For stores with tens of thousands of images, this can take many hours. Incremental approaches process only the images that actually need new thumbnails.
Selective Image Type Regeneration
If you only added or modified one image type, you do not need to regenerate all image types. Use the --image-type option in the console command to target only the specific image type that changed. This reduces the work to one-eighth (or whatever fraction of your total image types) of a full regeneration.
Date-Based Processing
If you need to regenerate thumbnails for recently added products only (for example, after fixing an image processing issue), you can query the database for images added after a specific date and process only those. The ps_image table does not have a date column by default, but the associated ps_product table has date_add and date_upd fields that can be used to identify recently modified products.
Missing Thumbnail Detection
Instead of regenerating everything, scan the image directories to find images that are missing specific thumbnails and only regenerate those. This is the fastest approach when you have added a new image type or when a partial regeneration was interrupted.
The logic is straightforward: for each image ID in the database, check if the expected thumbnail file exists on disk. If it does not, regenerate just that thumbnail. This turns a multi-hour full regeneration into a targeted process that might take minutes.
Parallel Processing
For very large catalogs, you can split the image ID range into chunks and process them in parallel using multiple PHP processes. For example, one process handles image IDs 1 through 10000, another handles 10001 through 20000, and so on. Each process runs independently, and the combined throughput is roughly proportional to the number of parallel processes (limited by CPU cores and I/O bandwidth).
Be careful with parallel processing and disk I/O. Running too many processes simultaneously on a traditional hard drive will cause I/O contention and actually slow things down. On SSD storage, 4 to 8 parallel processes typically work well.
Image Format Considerations
PrestaShop supports JPEG, PNG, and GIF as source formats, and can generate thumbnails in these formats plus WebP. The source format affects regeneration behavior.
JPEG Images
JPEG is the most common format for product photos. It supports lossy compression, which means each time a JPEG is saved, some quality is lost. This is why regenerating thumbnails from original uploads produces better results than regenerating from previously resized thumbnails. Always ensure you are working from the original uploaded image, not a previously generated thumbnail.
PNG Images
PNG supports transparency and lossless compression. If your product images use transparent backgrounds, PNG thumbnails preserve that transparency. However, PNG files are typically much larger than JPEG files. Consider whether you actually need transparency. If not, converting PNG product images to JPEG during regeneration can significantly reduce disk space and improve page load times.
GIF Handling
PrestaShop can accept GIF uploads, but generated thumbnails from GIF sources are static (no animation preserved). If you have animated GIF product images, be aware that regeneration produces static thumbnails from the first frame.
Post-Regeneration Verification
After regeneration completes, verify the results before assuming everything is correct.
Spot-Check Image Quality
Open several product pages and inspect the images visually. Check that thumbnails are sharp, correctly proportioned, and not stretched or pixelated. Pay special attention to images that were originally small (close to or smaller than the thumbnail dimensions), as these are most likely to show quality issues when upscaled.
File Count Verification
Compare the number of generated thumbnails against expectations. If you have 5,000 product images and 8 image types, you should have approximately 40,000 thumbnail files (plus the originals and potentially WebP variants). A significantly lower count indicates that the regeneration process was interrupted or encountered errors on some images.
File Permission Check
Verify that regenerated files are owned by the web server user (typically www-data on Debian/Ubuntu or apache on CentOS). If you ran the regeneration as root, the files may not be readable by the web server, causing broken images on the frontend. Fix with: chown -R www-data:www-data img/p/.
Cache Clearing
After regeneration, clear all caches. This includes PrestaShop's internal cache (Advanced Parameters > Performance), any opcode cache (OPcache), and any CDN or reverse proxy cache. Old cached pages may still reference old image URLs or dimensions. If you use a module that generates CSS sprites or inline images, regenerate those as well.
If your store is behind Cloudflare, purge the cache for the /img/ path or do a full cache purge. Cloudflare caches images aggressively, and visitors may see old thumbnails until the CDN cache expires or is purged.
Troubleshooting Common Regeneration Problems
Black or Corrupted Thumbnails
This usually indicates a GD library issue. The GD extension may not support the source format (for example, GD compiled without JPEG support). Verify GD capabilities with gd_info(). Another cause is insufficient memory: if PHP cannot allocate enough memory to load the original image, GD may produce a black image instead of throwing an error.
Wrong Dimensions in Generated Thumbnails
If thumbnails have unexpected dimensions, check the image type definitions in the database. The admin panel may show one value while the database contains another (this can happen after a failed import or manual database modification). Query directly: SELECT * FROM ps_image_type WHERE name = 'home_default';
Regeneration Hangs Without Progress
A hung regeneration process usually means it encountered a very large image that exhausted available memory. Check the PHP error log for memory allocation failures. The solution is to increase the memory limit or pre-process the problematic source images to reduce their resolution before regeneration.
Permission Denied Errors
If regeneration reports permission errors, the PHP process cannot write to the image directories. This commonly happens in Docker environments where bind-mounted volumes have different ownership inside and outside the container. Ensure the user running the regeneration command has write access to the entire /img/ directory tree.
Summary
Image regeneration is a maintenance task that every PrestaShop store owner encounters, usually during a theme change or when optimizing image settings. For small catalogs (under 500 products), the admin panel tool works adequately. For anything larger, CLI regeneration is the only reliable approach. The key principles are: always work from original images, match your image type definitions to your theme's requirements, manage server resources and timeouts proactively, use incremental approaches when possible, and verify results after the process completes. With WebP becoming the standard for web images, regeneration also serves as the mechanism to create modern format variants of your entire product catalog, delivering smaller file sizes and faster page loads to your customers.
For more details, read our guides: Image Optimization for PrestaShop: Faster Loading Without Losing Quality and PrestaShop Image Optimization: Alt Tags, Lazy Loading and Page Speed.
What Varnish Is and Why It Matters for PrestaShop
Varnish Cache is an HTTP reverse proxy that sits between your web server and the internet, serving cached copies of pages without ever touching PHP or MySQL. When a visitor requests a page that Varnish has cached, the response comes directly from memory in microseconds. PHP never executes. MySQL never receives a query. The web server barely notices the request happened.
This is fundamentally different from how PHP-based full page cache (FPC) modules work in PrestaShop. An FPC module still runs within PHP. The request hits Apache or Nginx, PHP boots, PrestaShop initializes (loading configuration, establishing database connections, parsing routes), and then the FPC module intercepts the request before the full controller logic runs, serving a cached HTML file. While this is significantly faster than rendering the page from scratch, it still involves starting PHP and loading the PrestaShop framework. That overhead, typically 50-200 milliseconds even for a cache hit, adds up under load.
Varnish eliminates that overhead entirely. A Varnish cache hit is served in 1-5 milliseconds. Under heavy traffic, the difference is dramatic. A PrestaShop store that struggles to handle 100 concurrent users with an FPC module can serve thousands of concurrent users with Varnish, because the vast majority of requests never reach the PHP backend at all.
When PHP Full Page Cache Modules Are Sufficient
Before investing in Varnish, it is worth understanding when a PHP-based FPC module is good enough. For many PrestaShop stores, it is.
If your store receives fewer than 50,000 daily page views, a well-configured FPC module will handle the load without problems. The additional complexity of Varnish is not justified when your server has spare capacity. If your server response times with FPC are consistently under 200 milliseconds, your visitors are already getting fast page loads. The bottleneck at that point is likely frontend rendering (CSS, JavaScript, images) rather than server response time.
FPC modules also handle some PrestaShop-specific scenarios more gracefully than Varnish because they run inside the application. They can check whether a user is logged in, whether the cart has items, and whether certain dynamic content needs to be personalized, all within the same PHP process. With Varnish, these checks must be handled through cookie inspection and cache variation rules, which adds configuration complexity.
Consider Varnish when your store regularly handles traffic spikes (flash sales, marketing campaigns, seasonal peaks) that overwhelm your PHP capacity, when you need sub-10ms response times for SEO or user experience reasons, when your hosting budget is limited and you need to serve more traffic from the same hardware, or when your store serves a high ratio of anonymous browsing traffic (category pages, product pages) relative to cart and checkout activity.
How Varnish Works: The Request Flow
Understanding the request flow through Varnish is essential for configuring it correctly with PrestaShop.
Request Arrives
When a visitor requests a page, the request hits Varnish first (Varnish listens on port 80 or 443 if terminated by a frontend proxy). Varnish examines the request: the URL, the HTTP method, the cookies, and the headers.
Cache Lookup
Varnish checks its cache for a stored response matching this request. The cache key is typically based on the URL and selected headers. If a matching response exists and has not expired, Varnish serves it directly. This is a cache hit. The response is sent to the visitor and the backend server is never contacted.
Cache Miss
If no matching cached response exists, Varnish forwards the request to the backend server (Apache or Nginx running PrestaShop). PrestaShop processes the request normally, generates the HTML response, and sends it back to Varnish. Varnish stores the response in its cache (if the response is cacheable) and forwards it to the visitor. Subsequent requests for the same page will be served from cache.
Cache Invalidation
When product data changes, prices update, or content is modified, the cached version becomes stale. Varnish needs to be told to discard the old cached version so it fetches a fresh one from the backend. This is cache invalidation, and it is the hardest part of any caching system to get right.
VCL Configuration for PrestaShop
Varnish Configuration Language (VCL) is a domain-specific language that controls how Varnish handles requests. A proper VCL configuration for PrestaShop must handle several PrestaShop-specific behaviors.
Backend Definition
The backend definition tells Varnish where to forward cache misses. For a typical PrestaShop setup where Apache or Nginx runs on the same server on port 8080:
backend default {
.host = "127.0.0.1";
.port = "8080";
.connect_timeout = 5s;
.first_byte_timeout = 60s;
.between_bytes_timeout = 10s;
}
The timeouts are important. PrestaShop pages can take several seconds to generate on a cold cache, especially category pages with many products. Setting first_byte_timeout too low causes Varnish to return a 503 error before PrestaShop finishes generating the page.
Handling Cookies and Sessions
Cookies are the biggest challenge when caching PrestaShop with Varnish. PrestaShop sets several cookies by default, and Varnish treats any request with cookies as uncacheable unless instructed otherwise. If you do not handle cookies in your VCL, Varnish will cache almost nothing.
PrestaShop sets these cookies on most requests: the session cookie (typically named PrestaShop-xxxx), the cart-related cookies, Google Analytics cookies (_ga, _gid, _gat), and various tracking cookies from marketing tools. Of these, only the PrestaShop session cookie matters for cache behavior. Analytics and tracking cookies should be stripped from the request before the cache lookup so they do not prevent caching.
In your VCL vcl_recv subroutine, strip non-essential cookies:
sub vcl_recv {
# Remove Google Analytics and other tracking cookies
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_ga|_gid|_gat|__utm[a-z]+|_fbp|_gcl_[a-z]+)=[^;]*", "");
# Remove empty cookie header
if (req.http.Cookie ~ "^\s*$") {
unset req.http.Cookie;
}
}
Deciding What to Cache
Not every PrestaShop page should be cached. The VCL must distinguish between cacheable and non-cacheable requests.
Always cache: Product pages for anonymous visitors, category listing pages, CMS pages (about, terms, contact), the homepage, manufacturer and supplier pages, sitemap pages.
Never cache: The shopping cart page, checkout pages (all steps), the customer account area (orders, addresses, personal info), the login and registration pages, any page for a logged-in customer, POST requests, AJAX requests that modify state (add to cart, update quantity).
The VCL logic for this typically checks the URL path and the presence of session cookies:
sub vcl_recv {
# Do not cache POST requests
if (req.method == "POST") {
return (pass);
}
# Do not cache admin area
if (req.url ~ "^/admin") {
return (pass);
}
# Do not cache checkout and cart
if (req.url ~ "(cart|order|login|my-account|module/)" ) {
return (pass);
}
# Do not cache if customer has items in cart
if (req.http.Cookie ~ "PrestaShop-") {
return (pass);
}
return (hash);
}
Setting Cache Duration
In the vcl_backend_response subroutine, you control how long Varnish caches each response. PrestaShop sends Cache-Control headers that typically say no-cache or private because it assumes every response might contain personalized content. You need to override these for pages you know are safe to cache:
sub vcl_backend_response {
# Cache product and category pages for 1 hour
if (bereq.url ~ "^/([0-9]+-|[a-z]+-[0-9]+)") {
set beresp.ttl = 1h;
unset beresp.http.Set-Cookie;
}
# Cache static assets for 1 day
if (bereq.url ~ "\.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf)$") {
set beresp.ttl = 1d;
unset beresp.http.Set-Cookie;
}
}
Stripping Set-Cookie from cached responses is critical. If a cached response includes a Set-Cookie header, Varnish will not cache it by default, and even if forced to cache it, it would set the same session cookie for every visitor, causing session hijacking.
Cache Invalidation with PURGE Requests
When a product price changes, a new product is added, or content is updated, the cached version must be invalidated. Varnish supports PURGE requests: a special HTTP method that tells Varnish to remove a specific URL from its cache.
Configuring PURGE Support
Add PURGE handling to your VCL:
acl purge {
"127.0.0.1";
"localhost";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return (synth(405, "Not allowed."));
}
return (purge);
}
}
The ACL restricts PURGE requests to localhost, preventing external users from flushing your cache.
Triggering Purges from PrestaShop
PrestaShop does not send PURGE requests natively. You need a module or custom hook that detects when cacheable content changes and sends a PURGE request to Varnish. The module hooks into PrestaShop events like actionProductUpdate, actionCategoryUpdate, and actionCMSPageUpdate. When these events fire, the module sends an HTTP PURGE request to the corresponding URL on the Varnish server.
For a product update, the module would purge the product URL, the category URLs the product belongs to (because category listing pages show product prices and availability), and potentially the homepage if it displays featured products. This cascade of purges is necessary to prevent stale data from appearing anywhere on the site.
Ban-Based Invalidation
For scenarios where many URLs need to be purged at once (a site-wide price update, a design change, a new promotion banner), individual PURGE requests are impractical. Varnish supports bans, which are pattern-based invalidation rules. A ban tells Varnish to discard any cached object matching a pattern:
sub vcl_recv {
if (req.method == "BAN") {
if (!client.ip ~ purge) {
return (synth(405, "Not allowed."));
}
ban("req.url ~ " + req.http.X-Ban-Pattern);
return (synth(200, "Banned."));
}
}
Sending a BAN request with the header X-Ban-Pattern: /category/ would invalidate all cached category pages in one operation.
Edge Side Includes (ESI) for Dynamic Blocks
Many PrestaShop pages contain a mix of static and dynamic content. The product listing on a category page is the same for every visitor, but the header showing the cart count is personalized. Without ESI, you cannot cache the page at all because the dynamic header makes the whole response visitor-specific.
Edge Side Includes solve this by allowing you to mark sections of the page as separately fetched fragments. Varnish assembles the final page from cached and uncached fragments.
How ESI Works
In your Smarty template, instead of rendering the cart widget directly, you include an ESI tag:
<esi:include src="/module/cartwidget/ajax" />
When Varnish processes the cached page, it encounters the ESI tag and makes a separate backend request for that fragment. The main page body is served from cache, while the cart widget is fetched fresh from PrestaShop. The assembled response includes both the cached body and the fresh cart widget.
Enable ESI processing in your VCL:
sub vcl_backend_response {
set beresp.do_esi = true;
}
ESI Considerations for PrestaShop
Implementing ESI requires modifying your PrestaShop templates to separate dynamic content into ESI-compatible fragments. Each fragment needs its own URL endpoint that returns just the HTML for that block. The fragments that are typically dynamic and need ESI treatment include the cart summary widget (item count, total), the customer greeting ("Hello, John"), any personalized product recommendations, the login/logout link, and recently viewed products.
The effort required to implement ESI properly is significant. Each dynamic fragment needs a dedicated controller, the templates need restructuring, and the caching rules for each fragment need individual tuning. This is one of the reasons Varnish is considered an advanced optimization, it works best when the application is designed with it in mind.
Backend Health Checks
Varnish can monitor the health of your backend server and take action when it becomes unavailable. This is configured in the backend definition:
backend default {
.host = "127.0.0.1";
.port = "8080";
.probe = {
.url = "/ping.php";
.timeout = 2s;
.interval = 5s;
.window = 5;
.threshold = 3;
}
}
Varnish sends a request to /ping.php every 5 seconds. If 3 out of the last 5 checks fail, Varnish marks the backend as sick. While the backend is sick, Varnish can serve stale cached content (grace mode) instead of returning errors to visitors. This means your store remains partially available even when the PHP backend crashes or restarts.
The grace mode configuration determines how long Varnish will serve stale content:
sub vcl_backend_response {
set beresp.grace = 6h;
}
With a 6-hour grace, if your backend goes down, visitors will see cached pages (even if they are up to 6 hours old) rather than error pages. Product prices might be slightly outdated, but the store remains functional while you fix the backend issue.
Performance Benchmarks
The performance difference between no cache, PHP FPC, and Varnish is substantial and measurable.
No cache (bare PrestaShop): A typical PrestaShop product page takes 200-800 milliseconds to generate, depending on server hardware, number of modules loaded, and database query count. Under load, response times increase because PHP workers are saturated. A single server might handle 20-50 concurrent users before response times become unacceptable.
PHP FPC module: Cache hits serve in 30-100 milliseconds because PHP still boots and the framework partially initializes. Under load, performance is much better because cached responses require minimal PHP processing time. A single server can handle 200-500 concurrent users depending on configuration. Cache misses still take the full rendering time.
Varnish: Cache hits serve in 1-5 milliseconds. Under load, Varnish itself can handle thousands of concurrent connections because it is written in C and designed specifically for this workload. The backend server only handles cache misses, which are a small fraction of total traffic on a properly configured system. The same hardware that struggles with 50 concurrent users without caching can handle 5,000 or more with Varnish.
These numbers illustrate why Varnish is worth the configuration complexity for high-traffic stores. The performance improvement is not incremental, it is an order of magnitude.
Hosting Requirements
Varnish has specific hosting requirements that not every PrestaShop hosting environment can accommodate.
Server Access
You need root access to install and configure Varnish. Shared hosting plans do not support Varnish because it requires its own process listening on a port and intercepting all HTTP traffic. You need a VPS, dedicated server, or cloud instance where you control the full server stack.
Memory
Varnish stores its cache in RAM. The amount of RAM you need depends on the number of unique pages in your catalog and the size of each cached response. A rough formula: number of cacheable pages multiplied by average page size gives you the minimum cache size. A store with 5,000 products, 200 categories, and an average page size of 50KB needs approximately 260MB of cache RAM. Add overhead for Varnish itself and you should allocate at least 512MB. For larger catalogs, 1-2GB is common.
Port Configuration
In a standard setup, Varnish listens on port 80 (the default HTTP port) and forwards cache misses to the web server on a different port (commonly 8080). This means you need to reconfigure Apache or Nginx to listen on port 8080 instead of 80. If you are using HTTPS (and you should be), you typically put Nginx in front of Varnish to handle SSL termination: Nginx on port 443 terminates SSL and forwards to Varnish on port 80, which forwards cache misses to Apache or PHP-FPM on port 8080.
Docker Setup Example
Running Varnish in Docker alongside a PrestaShop container is a clean way to add Varnish to an existing setup without modifying the host system.
Docker Compose Configuration
A basic Docker Compose setup with Varnish, Nginx for SSL, and PrestaShop:
services:
varnish:
image: varnish:7.4
ports:
- "80:80"
volumes:
- ./varnish/default.vcl:/etc/varnish/default.vcl:ro
environment:
- VARNISH_SIZE=512m
depends_on:
- prestashop
prestashop:
image: prestashop/prestashop:8
expose:
- "80"
environment:
- DB_SERVER=db
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=secretpassword
- MYSQL_DATABASE=prestashop
In this setup, Varnish is the entry point on port 80. The PrestaShop container does not expose its port to the host, only to the Docker network. The VCL backend host would be prestashop (the Docker service name) on port 80.
VCL for Docker
The VCL backend definition for Docker uses the service name instead of localhost:
backend default {
.host = "prestashop";
.port = "80";
}
Docker's internal DNS resolves the service name to the container IP. The rest of the VCL configuration remains the same as a non-Docker setup.
Cache Storage in Docker
By default, the Varnish Docker image uses in-memory storage (malloc), which is ideal for performance. The VARNISH_SIZE environment variable controls how much memory Varnish allocates for its cache. Set this to a value that fits within your container's memory limits while leaving room for the Varnish process itself.
For persistent cache that survives container restarts, you can use file-based storage by mounting a volume, but this is rarely necessary. The cache warms up quickly (within minutes of receiving traffic) and file-based storage is slower than memory-based storage.
Monitoring Varnish Performance
Varnish provides built-in tools for monitoring cache performance.
The varnishstat command shows real-time statistics including cache hit rate, backend connections, and memory usage. The most important metric is the hit rate, which should be 85% or higher for a well-configured setup. If your hit rate is below 70%, review your VCL rules because too many requests are passing through to the backend.
The varnishlog command shows detailed per-request logs, which are invaluable for debugging why specific requests are not being cached. You can filter by URL pattern, response code, or cache hit/miss status.
The varnishtop command shows a ranked list of the most frequent log entries, helping you identify patterns in cache misses or errors.
Common Pitfalls
Forgetting to Strip Cookies
The single most common Varnish misconfiguration with PrestaShop is not stripping analytics and tracking cookies. These cookies are present on virtually every request and make every request unique from Varnish's perspective, resulting in a 0% hit rate. Always strip cookies you do not need for cache variation.
Caching Personalized Content
If your VCL is too aggressive, it will cache pages that contain personalized content (logged-in user greeting, cart contents) and serve them to other visitors. This causes serious usability issues and potential privacy problems. Always pass requests that contain session cookies to the backend.
Not Invalidating on Content Changes
Without a proper purging mechanism, content changes in the back office will not be visible until cached pages expire naturally. For a store with active inventory changes, this means visitors might see out-of-stock products, wrong prices, or outdated descriptions. Implement PURGE or BAN support and integrate it with PrestaShop's update hooks.
Ignoring HTTPS
Varnish does not handle SSL natively. You must put an SSL-terminating proxy (Nginx, HAProxy, or a cloud load balancer) in front of Varnish. Failing to plan for this in your architecture leads to mixed content issues, redirect loops, or an inability to serve HTTPS traffic at all.
Is Varnish Right for Your Store
Varnish is a powerful tool, but it is not the right choice for every PrestaShop store. It adds operational complexity: another service to monitor, another configuration language to learn, another layer in your debugging process. The benefits are clear and measurable for stores that need them, but they come at a cost in setup time, maintenance, and troubleshooting difficulty.
If your store serves fewer than 50,000 page views per day and your server handles the load comfortably with an FPC module, Varnish is unnecessary complexity. If your store regularly faces traffic spikes that overwhelm your server, serves a high volume of anonymous browsing traffic, or needs the fastest possible response times for SEO or user experience, Varnish provides a level of performance that no PHP-based caching solution can match.
Start with proper PrestaShop optimization (query optimization, module audit, PHP OPcache, image optimization) and an FPC module. If those optimizations are not enough, Varnish is the next step in the performance scaling ladder.
For more details, read our guides: PrestaShop Cache: Full Page Cache Modules Explained and Redis Cache for PrestaShop: Setup and Performance Gains.
Ask a question
What customers say about us
Great work and support
Z-index configuration to control stacking order with other floating elements
ImplementedLINE Official Account deep link support for one-tap mobile chat initiation
ImplementedCustom pre-message text to pre-fill the LINE chat compose box
ImplementedAnimated bounce effect on the LINE chat button to draw visitor attention
ImplementedSuggest a Feature
No known issues
There are currently no open or resolved issues registered for this module.
- Addedadmin menu management via MenuInstaller for streamlined module setup
- AddedLicense management tab with key management and renewal options
- Addedself-healing integrity checks for automatic diagnostics and repair
- Addedcomplete FR/DE/ES/IT/PL translations
- Addedfull compatibility with PrestaShop 9.x and Hummingbird theme
- AddedLINE Official Account deep link support for one-tap mobile chat initiation
- Improvedbutton positioning with configurable corner (bottom-left/right) and offset
- Fixedbutton not rendering when front-office cache was enabled without module asset exclusion
- Addedcustom pre-message text to pre-fill the LINE chat compose box
- Addedanimated bounce effect on the LINE chat button to draw visitor attention
- Improvedmobile UX: button scales appropriately for touch targets
- FixedLINE button overlapping with other chat widgets when multiple integrations active
- Addedz-index configuration to control stacking order with other floating elements
- Initialrelease: LINE Chat floating button integration for PrestaShop
- InitialLINE ID or LINE Official Account URL configuration
- InitialConfigurable button label, icon, and background colour
- InitialPage-level display rules: show only on product pages, or sitewide
Easy return - no questions asked
Install, set up and take profit
Priority Help & Satisfaction Over Sales
No reviews yet. Be the first to leave a review!
Write a Review