PS PrestaShop Intermediate

DataFirefly Push Pro — Complete Guide

Install, configure and operate DataFirefly Push Pro for PrestaShop 8 and 9: native Web Push VAPID, smart opt-in, 9 automations, campaign builder, segmentation, A/B testing, revenue attribution, topics, inbox and HMAC-signed webhooks.

Updated Module version 1.2.0

DataFirefly Push Pro brings native web push notifications to PrestaShop 8 and 9 without any third-party service like OneSignal or monthly subscription. This guide covers installation, initial setup, the nine automations, the campaign builder, segmentation, A/B testing, revenue attribution, topics, the inbox, webhooks and troubleshooting.

1. Overview and use cases

The module natively implements the Web Push VAPID protocol (RFC 8292) with aes128gcm encryption on the server side. Subscriptions are stored in your PrestaShop database, sends go directly from your hosting, no data goes through a third-party service.

Typical use cases:

  • Abandoned cart recovery: three spaced reminders (1 h, 24 h, 72 h) without depending on the visitor’s email.
  • Product alerts: back in stock, price drop, opt-in directly on the product page.
  • Transactional: order confirmation, shipping, review request after delivery.
  • Re-engagement: birthday, inactive customers, new products digest.
  • One-off campaigns: sales, launches, Black Friday, with segmentation and A/B testing.

2. Requirements

  • PrestaShop 8.0 to 9.x
  • PHP 7.4 minimum, 8.x recommended
  • MySQL 5.7 minimum or MariaDB 10.3
  • HTTPS mandatory: browsers’ Web Push API only works on a secure origin. Only localhost is an exception for development testing.
  • An external cron capable of calling an HTTP URL every 5 minutes (Linux cron, host scheduled tasks, native PrestaShop cron, etc.)
  • OpenSSL enabled in PHP (used for VAPID key generation and aes128gcm encryption)

Why HTTPS? All browsers (Chrome, Firefox, Safari, Edge) refuse to register a service worker or grant notification permission on an HTTP page. This is a browser limitation, not a module one.

3. Installation

  1. Download the ZIP dfpushnotifications-v1.2.0-phase3.zip from your DataFirefly customer area.
  2. PrestaShop back office → Modules → Module Manager → Upload a module → select the ZIP.
  3. Click Install. The installation creates 14 tables under the ps_dfpush_* prefix, generates a unique cron token and registers the BO tabs.
  4. A new menu appears: Improve → DataFirefly Push with 8 tabs (Dashboard, Campaigns, Automations, Queue, Subscribers, Topics, Webhooks, Settings).

4. VAPID key generation

VAPID keys identify your server to the browser push services (FCM, Mozilla autopush, Apple push). They are generated once and must never change after going live (otherwise all subscribers become unreachable).

  1. Go to DataFirefly Push → Opt-in & Settings.
  2. Click Generate VAPID keys. The module creates an ECDSA P-256 key pair stored in the PrestaShop configuration.
  3. Enter a VAPID subject: a mailto: URL with your technical contact address (e.g. mailto:admin@yourshop.com). It’s the identifier push services can reach in case of abuse.
  4. Enable the module via the Push notifications enabled toggle.

Back up your keys. If you regenerate the VAPID keys after launch, all your existing subscribers will be rejected by push services with a 410 Gone code. Keep a backup of the PrestaShop database before any key manipulation.

5. Opt-in configuration

The Opt-in & Settings tab controls the display of the permission request. Three styles are available:

  • Bell: a floating bell at the bottom right. The user clicks, then the browser shows its native request. The least intrusive.
  • Banner: a persistent banner at the top or bottom of the page with two buttons (allow / decline).
  • Modal: a centered modal window, more visible but also more aggressive.

Triggers

To avoid showing the request from the very first second (high refusal rate), pick a trigger:

  • Delay: show after X seconds (default 15 s)
  • Scroll: show after X % of page scroll (default 40 %)
  • Pages: show after X pages viewed in the session (default 2)

Cooldown

If the visitor closes or refuses the request, a cooldown prevents showing it again for N days (default 7). It avoids the “popup harassment” effect that pushes users to permanently block the domain.

Daily cap and quiet hours

  • Max per day: maximum number of notifications sent to the same subscriber per day (default 3). Beyond that, the send queue silently rejects excess messages.
  • Quiet hours: time range during which no notification is delivered. Messages queued during this range are rescheduled to the morning of the first non-silent window.

6. Cron: setup and token

The cron drives all deferred operations: automations, send queue, webhook draining, cleanup. It must be called every 5 minutes via a token-secured HTTP URL.

Token

A unique token is generated at installation. To retrieve it: DataFirefly Push → Automations, the blue banner at the top shows the full URL to copy-paste into your cron.

Linux cron example

*/5 * * * * curl -s "https://yourshop.com/module/dfpushnotifications/cron?token=YOUR_TOKEN" > /dev/null

Tasks executed at each tick

  1. Reset of daily counters (once a day, at midnight crossing)
  2. Execution of mature-delay automations (abandoned carts 1 h / 24 h / 72 h, birthday, inactivity, new products, scheduled review requests)
  3. Triggering of scheduled campaigns whose date has arrived
  4. Draining of the send queue (up to 50 notifications per batch by default, configurable)
  5. Draining of the webhook queue (up to 100 per batch)
  6. Cleanup of old entries (sent > 60 days, webhook log > 30 days)

The cron response is a JSON detailing each step:

{
  "success": true,
  "tasks": {
    "reset_counters": "ok",
    "triggers": { "abandoned_1h": 12, "abandoned_24h": 4, "birthday": 2, "inactivity": 38 },
    "scheduled_campaigns": 1,
    "queue": { "processed": 50, "sent": 47, "failed": 2, "expired": 1 },
    "webhooks": { "processed": 8, "sent": 8, "failed": 0, "dropped": 0 },
    "cleanup": "ok"
  },
  "duration_ms": 1842
}

If your host doesn’t provide a cron, set up a free third-party service (cron-job.org, EasyCron, cronless) pointing to the same URL every 5 minutes.

7. Automations: the 9 triggers

Disabled by default, enable them one by one from DataFirefly Push → Automations. Each card shows the title, body and stats. Click Edit to customize the wording and options.

Available variables

Depending on the trigger, you can insert in the title and body:

  • {first_name}: customer’s first name (empty for anonymous visitors)
  • {cart_total}: abandoned cart amount, formatted with currency
  • {order_reference}: order reference
  • {order_total}: total order amount
  • {product_name}: product name (back in stock, price drop)
  • {product_price}: current product price
  • {products_count}: number of new products (digest)

Abandoned cart (3 reminders)

Three independent triggers: abandoned_cart_1h, abandoned_cart_24h, abandoned_cart_72h. The module records each cart change in ps_dfpush_cart_watch and marks the cart as converted as soon as an order is validated. The cron sends each reminder at maturity, unless the cart was converted in the meantime.

Back in stock

On the product page, a Notify me when back in stock button appears automatically when the product is out of stock. The subscriber clicks, the push opt-in is requested if needed, then the module records a watcher in ps_dfpush_product_watch. As soon as a stock change brings the available quantity above 0, the watcher is notified and marked as processed.

Price drop

Same principle with the Notify me on price drop button. The watcher stores the reference price at the time of opt-in. The notification is sent as soon as a product update brings the price below 99 % of the reference price (a threshold that avoids parasitic triggers on rounding).

Order confirmation

Triggered by the actionValidateOrder hook. Sent immediately, without quiet-hours respect (transactional). Direct link to the order detail page.

Shipping

Triggered by actionOrderStatusUpdate as soon as the status moves to a state marked as shipped in PrestaShop. Link to the order details (which contains the tracking if you use a tracking module).

Review request

Scheduled X days after the order moves to a delivery state (default 7 days, configurable in the trigger config JSON). The notification is queued with a future scheduled_at, the cron delivers it when the time comes.

Birthday

The cron reads the PrestaShop customer’s birthday field and sends the notification on the day at the configured hour. A deduplicator avoids multiple sends in the same year.

Inactivity

Identifies subscribers whose last_visit is more than N days old (default 30). To avoid harassment, a same subscriber is notified at most once every 30 days via this trigger.

New products

Daily digest sent at a configurable hour (default 10 a.m.). The module aggregates products created in the last 24 hours and sends a notification mentioning the name of the first and the total count. Ideal for a store that regularly adds catalog.

8. Campaign builder

For one-off operations: DataFirefly Push → Campaigns → New campaign. The form is divided into five sections.

Content

  • Campaign name: internal name (never shown to subscribers)
  • Notification title: 80 chars max
  • Body: 250 chars max
  • Click URL: where the click redirects
  • Icon URL: small logo (defaults to your shop logo)
  • Large image URL: hero image, 1024 × 512 recommended (Chrome only)
  • Badge URL: monochrome 72 × 72 PNG (Android)

Action buttons

Up to two buttons with their label and URL. They appear below the notification on Chrome desktop and Android. Ideal to offer multiple CTAs (View the offer / Ignore).

Audience

See the Segmentation section below.

Schedule & delivery

  • Send at: send date / time. Empty = immediate (at the next cron drain).
  • Urgency: very-low, low, normal, high. Influences priority on the push service side.
  • TTL: time to live in seconds (default 86400 = 24 h). If the subscriber’s browser is offline longer, the notification expires.
  • Require interaction: persistent notification until clicked or manually closed (Chrome only).

9. Segmentation

Combinable with logical AND. All criteria empty = no restriction.

Criterion Effect
Languages The subscriber speaks at least one of these languages (checked boxes)
Countries Country detected at subscription (based on language / IP / geo)
Devices mobile / desktop / tablet (detected at subscription)
Browsers Chrome, Firefox, Safari, Edge, Opera, Samsung Internet
Customer groups The subscriber is linked to a PrestaShop customer in at least one of the groups
Purchase history Any (default), Has bought, Never bought
Active within N days Last visit less than N days ago (based on ps_dfpush_customer_activity)

The Preview audience size button computes via AJAX the exact number of matching subscribers. Useful to check that targeting isn’t too restrictive before sending.

10. A/B testing

On each campaign, the % of audience for variant B field defines the share of the audience that receives variant B (from 0 to 50). The split is deterministic: for a given id_subscriber, the subscriber always receives the same variant (based on id_subscriber % 100 < split).

Variant B overrides only the fields you fill in. You can for example change only the title, or only test an image. Statistics are stored separately:

  • stats_delivered / stats_clicked / stats_revenue: variant A
  • stats_b_delivered / stats_b_clicked / stats_b_revenue: variant B

The columns appear in the campaign list with an A/B badge next to the name.

11. Revenue attribution

Key mechanism of the module: linking orders to the notifications that triggered them.

Flow

  1. The module sends a notification with a unique track_token (32 hex chars) in the payload.
  2. The service worker intercepts the click and redirects to /module/dfpushnotifications/track?t=TOKEN&click=1&u=URL.
  3. The track controller sets a dfpush_attr=TOKEN cookie (30 days, SameSite=Lax) and redirects to the final URL.
  4. The customer browses, adds to cart, validates the order.
  5. At the actionValidateOrder hook, the AttributionService reads the cookie, finds the notification in ps_dfpush_notifications, writes id_order + revenue + currency on the row.
  6. The service increments stats_revenue (or stats_b_revenue depending on variant) on the campaign or trigger, fires the order.attributed webhook, then clears the cookie.

Attribution limits

  • Fixed 30-day window. Beyond that, attribution no longer applies.
  • One cookie per subscriber. If the user clicks a second notification before ordering, it’s the last one that’s credited (last click model).
  • Attribution requires the click and the order to happen on the same browser (the cookie is browser-bound).
  • An already-attributed order cannot be re-attributed (field id_order > 0 blocks double counting).

12. Topics

Topics are thematic subscription channels that customers enable from their account. Example: Promotions, New products, Stock alerts. A subscriber who only checks Promotions will only receive campaigns targeting that topic.

Create a topic

  1. DataFirefly Push → Topics → New topic
  2. Code: internal identifier without spaces (e.g. flash_deals)
  3. Display order: position in the list shown to the customer
  4. Active: visible to customers
  5. Default opt-in: pre-checked at subscription time
  6. Translations: a name and a description per installed language

Target a topic in a campaign

Segmentation includes a Topics criterion in the resolver. To enable it from the UI: currently only via custom JSON (the Topics checkbox arrives in a minor update). Subscribers without any subscribed topic receive everything (backward compatibility).

13. In-app inbox

The endpoint /module/dfpushnotifications/inbox returns the 20 latest notifications of the current subscriber as JSON. The frontend opens this inbox via the unified modal accessible from the customer account (the Push notifications tile).

The modal also shows the subscription status (with subscribe / unsubscribe button) and the topics list. To call it manually from your theme:

// Open the modal
window.dfpush.openManagePopup();

// Check subscription state
const isOn = window.dfpush.isSubscribed();

14. Webhooks

Webhooks send module events to Zapier, Make, n8n or your own backend. Each webhook is HMAC-SHA256 signed on the raw request body.

Create a webhook

  1. DataFirefly Push → Webhooks → New webhook
  2. URL: your endpoint (HTTPS recommended)
  3. Secret: auto-generated, copy it on the receiver side
  4. Events: check the events to deliver among the 8 available
  5. Click Send test ping to verify your endpoint replies 2xx

Available events

  • subscriber.subscribed: new opt-in
  • subscriber.unsubscribed: unsubscription
  • subscriber.expired: push service returned 410 Gone
  • notification.sent: notification successfully delivered
  • notification.clicked: click recorded
  • notification.failed: final failure after 3 attempts
  • campaign.sent: campaign finished
  • order.attributed: order linked to a notification

Payload format

{
  "event": "notification.clicked",
  "timestamp": "2026-05-28T14:32:18+00:00",
  "shop": 1,
  "data": {
    "id_subscriber": 482,
    "id_campaign": 12,
    "id_trigger": 0,
    "id_notification": 9182,
    "track_token": "abc123...",
    "url": "https://yourshop.com/promotions",
    "ab_variant": "A"
  }
}

HTTP headers sent

  • Content-Type: application/json
  • X-DfPush-Event: notification.clicked
  • X-DfPush-Signature: sha256=<hex>
  • X-DfPush-Timestamp: 1748443938
  • User-Agent: DataFireflyPush/1.2

Verify the signature on the receiver side

PHP example:

$body     = file_get_contents('php://input');
$expected = hash_hmac('sha256', $body, $YOUR_SECRET);
$received = explode('=', $_SERVER['HTTP_X_DFPUSH_SIGNATURE'])[1] ?? '';
if (!hash_equals($expected, $received)) {
    http_response_code(401);
    exit;
}
// Valid signature, process payload
$payload = json_decode($body, true);

Retry and drop

If your endpoint replies anything other than 2xx, the module retries with exponential backoff up to 5 attempts. After that, the log is marked dropped and the event is lost. Sent and dropped logs are purged after 30 days.

15. Multi-store and multilingual

All subscribers, campaigns, automations, topics and webhooks are tied to an id_shop. In multi-store:

  • Select the target store in the back-office selector before creating a campaign or automation
  • The cron is unique but filters automatically by store
  • VAPID keys are shared across stores (a single pair for all)

On the language side: the module ships in FR, EN, ES, DE and IT. The subscriber’s language is detected at subscription and stored. You can segment by language in campaigns.

16. GDPR and best practices

  • Consent: subscription relies on the native browser opt-in, which is GDPR-compatible proof of consent.
  • Personal data: the module stores the Web Push endpoint, IP at subscription time, user-agent, language and country. No transmission to a third party.
  • Unsubscription: a click on the Unsubscribe button in the modal or disabling notifications in the browser sets the subscriber to revoked status.
  • Right to erasure: deleting a customer account in the BO also deletes their linked subscribers.
  • Quiet hours: default 10 p.m. – 8 a.m. Adapt to your audience (B2B = office hours, B2C = evening).
  • Daily cap: default 3/day. Beyond that, very high unsubscribe rate.

17. Troubleshooting

The opt-in doesn’t show

  • Check that your site is in HTTPS (not HTTP).
  • Check that VAPID keys are generated (Settings).
  • Check that the Push notifications enabled toggle is on.
  • Open the browser console (F12) and look for errors on dfpush-frontend.js.
  • If you’ve already refused or ignored the request, the cooldown blocks for N days. Clear the domain cookies to reset, or switch browsers to test.

The cron doesn’t run

  • Call the URL manually in your browser: you should see a JSON with success: true. If you see a 403 invalid_token, the token is mistyped.
  • Check the last execution in the dashboard (Dashboard, System block).
  • On some hosts, the cURL timeout for crons is 30 s. If the queue is very large, increase the cron frequency to every 1 or 2 minutes to process in smaller batches.

Notifications don’t go out

  • Queue tab: if rows are in pending, it means the cron hasn’t run since they were created.
  • If they’re failed, click on the row to see the HTTP code and the push service error message.
  • 410 Gone = the subscription is no longer valid (user unsubscribed or wiped their browser). The module automatically marks the subscriber as expired.
  • 429 Too Many Requests = rate limit on the push service side. The module automatically retries with backoff.

Orders aren’t attributed

  • Check that third-party cookies aren’t blocked by the customer’s browser (private mode, some anti-trackers).
  • The cookie expires at 30 days: an order placed 31 days after the click won’t be attributed.
  • If you see id_order = 0 in ps_dfpush_notifications while the order was placed, check that the actionValidateOrder hooks are registered (Modules → Hooks → actionValidateOrder).

SQL error with “LIMIT 1 LIMIT 1”

Internal bug fixed in 1.2.0 (Db::getValue and Db::getRow add their own LIMIT 1 automatically). If you still see this error, check that you have the latest module version installed.

18. FAQ

How many subscribers can the module handle?

The module has no coded limit. In practice, the limiting factor is cron execution time: on a standard shared host, count about 50 sends per minute (limited by push services). For 10,000 subscribers, plan a cron every 1 or 2 minutes when sending a large campaign.

Is Safari iOS really excluded?

Safari iOS supports Web Push since iOS 16.4 but only for sites installed as a PWA on the home screen. On a regular Safari, the Notification API returns undefined. This is an Apple limitation, not a module one.

Can I migrate my subscribers from OneSignal or Firebase?

No. Push endpoints are bound to the VAPID key pair used at subscription. If you change the pair, existing subscriptions become invalid. A migration would require users to re-subscribe.

Does the module work on PrestaShop 1.7?

No, only PrestaShop 8.0 to 9.x. Version 1.7 uses a different admin architecture that would require a dedicated fork.

Can I customize the service worker?

Yes, the views/js/sw-template.js file is rendered by the swjs.php controller and can be extended. Caution: any service worker modification requires a new register() on the client side. Existing visitors will keep the previous version until the browser detects the change (usually 24 h).

How to export subscribers?

Subscribers tab, Export CSV button. The file contains endpoint, browser, device, language, country, subscription date and send / click counters.

Support

For any question not covered by this guide, contact DataFirefly support. To report a bug, attach the details of your PrestaShop, PHP version and the content of the cron JSON response.

Was this page helpful?

Still stuck? Contact support