# DataFirefly Push — Complete guide

> Overview and requirements DataFirefly Push turns your WooCommerce store into a native Web Push notifications platform. No SDK, no third-party tracking: every piece of cryptography (VAPID and RFC 8291 encryption)…

- Page: <https://www.datafirefly.com/en/documentation/datafirefly-push/>
- Language: en
- Last updated: 2026-06-27
- Other languages: [fr](https://www.datafirefly.com/documentation/datafirefly-push/index.md), [es](https://www.datafirefly.com/es/documentation/datafirefly-push/index.md), [de](https://www.datafirefly.com/de/documentation/datafirefly-push/index.md), [it](https://www.datafirefly.com/it/documentation/datafirefly-push/index.md), [pl](https://www.datafirefly.com/pl/documentation/datafirefly-push/index.md), [nl](https://www.datafirefly.com/nl/documentation/datafirefly-push/index.md), [pt](https://www.datafirefly.com/pt/documentation/datafirefly-push/index.md)
- Index: <https://www.datafirefly.com/en/documentation/llms.txt>

## Overview and requirements

DataFirefly Push turns your WooCommerce store into a native Web Push notifications platform. No SDK, no third-party tracking: every piece of cryptography (VAPID and RFC 8291 encryption) runs on your own server in pure PHP through OpenSSL. The plugin covers a multi-style smart opt-in, ten automatic triggers, manual campaigns with visual builder and segmentation, a complete analytics dashboard, a dedicated My Account page for your customers, and native GDPR compliance.

- WordPress 6.2 and above.
- WooCommerce 7.0 and above, tested up to 9.6, HPOS and Cart/Checkout Blocks compatible.
- PHP 8.1 and above.
- Multilingual (FR/EN/ES/DE/IT), compatible with Polylang and WPML.
- Compatible with LiteSpeed Cache, WP Rocket and other cache plugins: the Service Worker is served as standalone PHP.

No third-party service to plug in, no Composer library to maintain. VAPID keys are generated automatically on activation, subscriptions and events stay in your own database.

## Installation

1. Download the `df-push.zip` archive from your customer account.
2. In the WordPress admin, go to **Plugins > Add New > Upload Plugin** and drop the archive.
3. Click **Activate**.
4. The **DF Push** menu appears in the admin sidebar with seven sub-menus: Dashboard, Campaigns, Subscribers, Triggers, Opt-in, Settings, Webhooks & API.

On activation, the plugin creates eight dedicated tables prefixed `dfpush_`, generates your VAPID keys, schedules the daily cron `df_push_daily_lifecycle` and registers the My Account endpoint. No manual step is needed.

## First-time setup: VAPID keys and opt-in

Once activated, the plugin is immediately functional with its default settings: the floating bell appears bottom-right after five seconds, the pre-prompt is enabled, automatic triggers are ready. Just check two things in **DF Push > Settings** before announcing the service:

- **VAPID public key**: the block shows your automatically generated public key (the application server key used by the browser). You can regenerate it but that invalidates every existing subscription.
- **PWA manifest** and **default icon**: add your icon (192×192 minimum) if `site_icon` isn't set on the site.

No external service to register, no Firebase / OneSignal developer account to create. The VAPID keys the plugin generates are enough: they authenticate your application server with the FCM, Mozilla Push and WNS push services.

## Opt-in tab — prompt, styles and triggers

This tab drives the subscription request. Five available styles, each positionable and themeable:

- **Floating bell** (default): discreet pill bottom-right or bottom-left.
- **Banner** at the top or bottom of the page.
- **Modal** centered with overlay.
- **Slide-in** from the side.
- **Sticky bar** pinned at the top.

The **soft-ask pre-prompt** (recommended) shows your custom message before the browser's native request. This mechanism preserves your opt-in quota: on Chrome, declining the pre-prompt doesn't burn the native-request budget (×3 vs 1 without a pre-prompt).

Five configurable, stackable triggers:

- **Delay** (in seconds) after page load.
- **Scroll** as a percentage of the page (0 = disabled).
- **Exit-intent** on mouse-leave motion (desktop only).
- **X pages viewed** in the session.
- **Add to cart** (captures the WooCommerce `added_to_cart` event).

Enable the **prompt A/B test** with a variant B title and message, and a configurable split. Assignment is persisted in localStorage to ensure per-visitor consistency across sessions.

Once the browser permission is denied, it can't be re-requested by script. Polish your pre-prompt and don't chain a request on the first scroll: that pattern shows 70 % refusal versus 20-30 % with a pre-prompt fired at the right moment.

## Triggers tab — the automatics

Ten automatic triggers, each individually toggleable from the **Triggers** tab. Each relies on Action Scheduler for deferred sends, with a synchronous fallback if Action Scheduler isn't available.

### Abandoned cart

Three configurable reminders, by default at 1 hour, 24 hours and 72 hours after abandonment. Detection captures the `added_to_cart` event for Push-subscribed users and schedules three `df_push_abandoned_cart` actions at decreasing intervals. Reminders are automatically cancelled if the order is placed meanwhile.

### Back-in-stock

On the product page, your subscribed visitors can join a per-product waitlist. When WooCommerce fires `woocommerce_product_set_stock_status` with a return to _instock_, the plugin sends a notification to the product's waitlist, then empties it.

### Price drop

The plugin keeps a `_df_push_last_price` meta per product. On every product update, it compares the old and new price. If the drop exceeds the configured **minimum percentage threshold**, a notification is sent to the _Promotions_ topic.

### Confirmation, shipping, review

- **Order confirmation**: immediate send on `woocommerce_thankyou` to the subscriber if the user ID matches.
- **Shipping**: detects the tracking number on the order by reading in order the meta `_tracking_number`, `_wc_shipment_tracking_items` (WooCommerce Shipment Tracking) and `_aftership_tracking_number` (AfterShip). If a number is found, the notification includes it in its message.
- **Review request**: scheduled X days after the order moves to the _completed_ status (configurable delay).

### Birthday, re-engagement, new product

- **Birthday**: the daily cron `df_push_daily_lifecycle` reads the WooCommerce `billing_birthday` field and sends a notification to subscribers whose birthday it is.
- **Re-engagement**: sends to subscribers inactive for 30, 60 and 90 days (windows configurable as CSV: `30,60,90`).
- **New product**: on product publish, a notification is sent to the _New arrivals_ topic.

Every trigger accepts a templated payload: `{firstname}`, `{product_name}`, `{product_price}`, `{old_price}`, `{order_number}`, `{tracking_number}`, `{category}`, `{discount_code}`. Variables are resolved at send time, not at scheduling time.

## Campaigns tab — visual builder, segmentation, A/B test

Build a manual campaign in **DF Push > Campaigns > New campaign**. The builder offers a live preview of the notification as it will appear on the subscriber's device.

- **Content**: title, message, destination URL, hero image, up to two action buttons with their own label and URL.
- **Persistent notification** (_requireInteraction_ option): the notification stays visible until interaction.
- **Segmentation** by language, country, device, topic, and by RFM behaviour: minimum orders, minimum AOV, days inactive, purchased category. Behavioural segments are computed via `wc_get_orders` at launch.
- **A/B test**: enable a variant B (title and message), the split is configurable in percent. Assignment is random per subscriber, deterministic by ID for analytics consistency.
- **Scheduling**: pick a date and time, or send immediately.
- **Test mode**: send the campaign to admins only, from the builder, before going live.

The send engine automatically chunks the segment, respects per-subscriber timezone quiet hours, applies the configured frequency cap, and purges on the fly any endpoint returning 404 or 410 (browser-side unsubscribe).

## Dashboard and analytics

The **DF Push > Dashboard** screen aggregates your 30-day KPIs. Chart.js is bundled locally (no external CDN dependency).

- **KPIs**: active subscribers, opt-in rate, sends, click-through rate (CTR), conversions, attributed revenue.
- **30-day time series**: sends vs clicks, one line per day.
- **7 × 24 heatmap**: best send slots based on clicks, crossing day of week and hour of day.
- **Per-campaign funnel**: sent > delivered > clicked > converted.
- **Attributed revenue**: a configurable attribution window (72 hours by default) links each click to the first purchase made within the window by that subscriber.
- **CSV export** of every event for GDPR audit or BI integration.

## Customer page: My Account → Notifications

A dedicated **My Account → Notifications** page is automatically added to the WooCommerce dashboard. The customer gets four blocks:

- **This device**: current status (active, disabled, blocked by browser, unsupported), with Enable or Disable on this device button.
- **All your devices**: list of subscribed devices (type, browser, language, last activity), with per-device unsubscribe or unsubscribe-all in one click.
- **My preferences**: checkboxes for the native topics (New arrivals, Promotions, Back in stock). Saved via REST with confirmation.
- **Notification history**: the last 30 notifications received, with title, body, icon, link and date.

The URL is `/my-account/df-push-notifications/` in English. The rewrite endpoint is registered with the `EP_ROOT | EP_PAGES` mask, with a self-heal on `init:999` that detects a missing rule (concurrent permalink flush case) and re-flushes automatically.

Customer-side actions (unsubscribe, preferences) go through REST routes under `df-push/v1/account/*`, authenticated by cookie + `wp_rest` nonce. No action can be performed on another account, even if the device identifier is tampered with in the request.

## GDPR and consent register

GDPR compliance is handled natively, not as a cosmetic add-on. Every opt-in and unsubscribe is recorded in the `dfpush_consent_log` table with:

- Subscriber ID.
- Action: _subscribe_ or _unsubscribe_.
- SHA-256 hashed IP (the cleartext IP is never persisted).
- User-agent.
- UTC timestamp.

The native WordPress Privacy Exporters and Erasers are wired in: a customer can request export or deletion of their personal data from **Tools → Export Personal Data** or **Tools → Erase Personal Data**. The plugin then includes their subscriptions, topics, inbox and consent register in the response — or removes them as requested.

## Settings tab — anti-spam and attribution

This tab centralizes subscriber-respect parameters and the attribution window:

- **Quiet hours**: interval during which no notification is sent. Timezone-aware (read on the subscriber's device at opt-in time via `Intl.DateTimeFormat().resolvedOptions().timeZone`). 22h-8h local by default.
- **Frequency cap**: maximum number of notifications per day per subscriber. 0 = unlimited.
- **Smart send time**: optimises send time per subscriber based on their historical click slots.
- **Attribution window**: duration in hours between a click and an order for the order to be attributed to the notification. 72 hours by default.
- **In-site inbox**: enables or disables the floating bell with notification history on the front-end.
- **PWA manifest**: enables manifest generation to make the site installable on mobile.

## Webhooks and REST API tab

The **Webhooks & API** tab covers two integration mechanisms.

### Outbound webhooks

Configure one or more HTTP endpoints per event. Three formats are available:

- **Slack**: `{ text }` payload compatible with Slack Incoming Webhooks.
- **Discord**: `{ content }` payload compatible with Discord Webhooks.
- **Generic**: full JSON payload with event, timestamp, data — Zapier, n8n, Make-compatible.

Available events: `subscriber.created`, `campaign.launched`, `notification.clicked`, `order.attributed`. Requests are non-blocking (`wp_remote_post` with `blocking=false`) so they never slow down the main send.

### REST API

Under the `df-push/v1` namespace, the plugin exposes a tokenised public send route: `POST /wp-json/df-push/v1/send` with the `X-DF-Push-Token` header. The token is regeneratable in one click from the admin.

```
curl -X POST https://your-site.com/wp-json/df-push/v1/send
  -H "Content-Type: application/json"
  -H "X-DF-Push-Token: YOUR_TOKEN"
  -d '{
    "title": "Flash promo",
    "body": "20 % off the whole catalogue until midnight",
    "url": "https://your-site.com/promotions",
    "segment": { "lang": "en", "topic": "promos" }
  }'
```

Treat this token like a password. Anyone who has it can send notifications to your subscribers. Regenerate it immediately if you suspect a leak.

## In-site inbox, PWA and multilingual

Three complementary features cover cases where the user hasn't allowed Push.

- **In-site inbox**: a floating bell (front-end configurable) opens a list of the latest notifications received by the user, read or unread, even if they've never allowed Push. Particularly useful for iOS Safari before 16.4 and PWA users.
- **PWA manifest**: dynamically generated at `/df-push-manifest.json` from `site_icon` or a custom icon. `df_push_manifest` filter available to adjust theme color, display, scope, start_url.
- **Multilingual**: Polylang and WPML compatible. Notifications are sent in the subscriber's language (detected at opt-in), with fallback on the site's default language. `.po` and `.mo` files in FR, EN, ES, DE, IT are included.

## Service Worker and technical architecture

The Service Worker is served by a standalone PHP file at `/wp-content/plugins/df-push/sw.php`. This approach completely sidesteps WordPress routing: no chance of interference with a cache plugin, a canonical redirect or another `template_redirect` handler.

The `Service-Worker-Allowed: /` header is sent in response to allow registration with root scope (`scope: '/'`) even though the script lives under `/wp-content/`.

On the database side, eight tables prefixed `dfpush_`:

- `dfpush_subscribers`: subscribers and their Push endpoint.
- `dfpush_topic_subs`: topic ↔ subscriber assignments.
- `dfpush_campaigns`: manual campaigns with payload, segment and scheduling.
- `dfpush_notifications`: log of individual sent notifications.
- `dfpush_events`: raw events (opt-in, sent, delivered, clicked, converted) for analytics.
- `dfpush_inbox`: persistent copy of notifications for the in-site inbox.
- `dfpush_stock_waitlist`: back-in-stock waitlists.
- `dfpush_consent_log`: GDPR register.

**Uninstall** (full delete from Plugins) drops these eight tables and purges every option. Simple deactivation, on the other hand, keeps the data for later re-activation.

## Developer hooks

The plugin exposes actions and filters at key points to extend its behaviour without touching the core.

- `df_push_booted` (action): fires after plugin boot, useful to register custom extensions.
- `df_push_payload_build` (filter): alter the JSON payload sent to the push service before encryption.
- `df_push_should_send` (filter): short-circuit the send on custom conditions (return _false_ to skip).
- `df_push_segment_query` (filter): enrich behavioural segmentation criteria.
- `df_push_webhook_payload` (filter): adjust outbound webhook payloads.
- `df_push_manifest` (filter): alter the generated PWA manifest.
- Registered Action Scheduler actions: `df_push_send_one`, `df_push_fan_out`, `df_push_abandoned_cart`, `df_push_review_request`, `df_push_dispatch_campaign`.

## FAQ and troubleshooting

### The opt-in prompt doesn't show up

Three possible causes: browser permission is already denied (check your browser settings), permission is already granted (the prompt isn't needed anymore), or a trigger hasn't fired yet (delay not elapsed, insufficient scroll). In the JavaScript console, run `window.DFPush.isSubscribed()` to check current state.

### The Subscribers admin is empty even though an opt-in succeeded

Check in the network console that the `POST /wp-json/df-push/v1/subscribe` request returns a 200 code. From version 1.0.1, the plugin automatically re-syncs any existing `PushSubscription` with the server on every page load, and logs any DB insertion error to `error_log`.

### The Service Worker fails to register

If the browser error is "The script resource is behind a redirect" or "Unexpected token '<'", test directly the URL `https://your-site.com/wp-content/plugins/df-push/sw.php`. You should see the Service Worker JavaScript code with `Content-Type: application/javascript` and the `Service-Worker-Allowed: /` header. If you see HTML 403, check the htaccess rules that may block direct PHP execution under `wp-content/plugins/`.

### Notifications aren't received on iOS

Safari on iOS only supports Push notifications from version 16.4 and only for sites installed as a PWA via the **Add to Home Screen** button. The PWA manifest generated by the plugin makes that installation easy. If you don't specifically target iOS, this isn't an issue: other browsers receive notifications normally.

### How to migrate from OneSignal or Pusher

Existing subscribers on those third-party services aren't portable: Push cryptography ties each subscription to a unique pair (server VAPID key, browser endpoint). Your visitors will have to re-subscribe after your switch to DataFirefly Push. You can prepare the transition by disabling the old SDK a few days in advance and communicating via a pre-announcement banner about the new experience.

### What happens on uninstall?

Simple **deactivation** keeps every table and option: you can reactivate the plugin and pick up where you left off. **Full delete** from Plugins runs `uninstall.php` which drops the eight `dfpush_` tables, purges every plugin option (including VAPID keys and the API token), and unschedules the crons. Permalinks are automatically flushed on the next request.
