# DataFirefly Native Live Shopping — Documentation

> Overview DataFirefly Native Live Shopping turns your WooCommerce store into a self-hosted live shopping platform, with no dependency on third-party services like Bambuser or CommentSold. Broadcasting uses WebRTC peer-to-peer mesh…

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

## Overview

DataFirefly Native Live Shopping turns your WooCommerce store into a self-hosted live shopping platform, with no dependency on third-party services like Bambuser or CommentSold. Broadcasting uses **WebRTC peer-to-peer mesh** from the host's browser to each viewer, signaling goes through the WordPress REST API, and replay recording is done client-side via the MediaRecorder API then stored as WordPress attachments.

The plugin provides:

- A `dfnls_live_show` CPT to create and schedule your live shows
- A host console embedded in the WordPress admin (camera preview, controls, products, chat)
- A turnkey viewer experience with clickable products in overlay and chat
- A WooCommerce cart bridge (add to the official cart without leaving the live)
- Automatic replay synchronized with live events (spotlights, coupons, messages)
- A dedicated Gutenberg block and the `[dfnls_live]` shortcode

**Architecture** — The WebRTC mesh topology is ideal up to ~25 simultaneous viewers per host. Beyond that, plan an external TURN server or consider an SFU. The host's upload bandwidth should be around 500 kbps per connected viewer.

## Requirements

- **WordPress** 6.3 or higher
- **WooCommerce** 8.0 or higher (HPOS compatible)
- **PHP** 8.1 or higher (tested up to 8.3)
- **HTTPS required** — `getUserMedia()` and `getDisplayMedia()` refuse to work over non-secure HTTP
- Supported browsers on the viewer side: Chrome 80+, Firefox 75+, Edge 80+, Safari 14+, Opera 67+
- A recent browser on the host side with accessible camera and microphone

**Important** — Without a valid HTTPS certificate (Let's Encrypt is enough), the host console cannot access camera or microphone. Test on `localhost` or on a domain with a TLS certificate.

## Installation

1. Download the `df-native-live-shopping.zip` archive from your DataFirefly account.
2. In WordPress, go to _Plugins → Add New_ → _Upload Plugin_.
3. Select the ZIP file and click _Install Now_.
4. Once installed, click _Activate Plugin_.
5. A new **Live Shopping** menu appears in the admin sidebar.

On activation, the plugin:

- Creates 5 custom tables (`wp_dfnls_signaling`, `_sessions`, `_events`, `_replay_parts`, `_chat`)
- Adds the `manage_dfnls_lives` and `host_dfnls_lives` capabilities to the `administrator` and `shop_manager` roles
- Schedules two crons: daily purge of old replays, hourly purge of stale signaling messages
- Registers default options (Google STUN servers, 90-day retention, 25 viewers max, etc.)

## First live in 5 minutes

The shortest path to launch your first live show:

1. **Live Shopping → New live** menu
2. Enter a title (e.g. "Spring flash sale")
3. In the _Products_ metabox, search and select the WooCommerce products you want to showcase (drag and drop to reorder)
4. Optional: in _Scheduling_, set a start date and time (a countdown will display on the viewer side)
5. Publish the live
6. Go to **Live Shopping → Host console** and select your live
7. Click _Start broadcast_, allow camera and microphone access
8. Share the public URL of the live (`/live/your-slug/`) with your audience

## Host console

The host console is the dashboard from which you moderate your live. It's accessible via _Live Shopping → Host console_. Features:

### Video preview and controls

- **Camera**: toggles camera activation/deactivation
- **Microphone**: toggles microphone activation/deactivation
- **Screen share**: replaces the camera stream with a screen share (useful for demos)
- **Start / Stop**: main live control buttons

### Product spotlighting

The list of products linked to the live displays on the right. Each product has a _Spotlight_ button. Clicking it:

- Immediately shows the product overlay to all viewers
- Records a timestamped `product.spotlight` event for replay sync
- A second click on the same button removes the overlay

### Coupon broadcasting

Enter a promo code (e.g. `LIVE20`) and optionally a description, then click _Broadcast_. An animated flash appears on the viewers' screen with a "Copy" button to grab the code in one click.

### Host messages

A free-text input lets you send a message that displays as a temporary banner on the viewer side (8 seconds by default).

### Live chat

Host/viewer chat is integrated into the console. Host messages are visually distinguished (badge and red border) in all views.

### Activity log

A log at the bottom of the console displays in real time connections/disconnections, broadcast events, replay chunk uploads, and any errors.

## Viewer experience

What the audience sees on the public URL of the live:

- **Before the live** — If the live is scheduled, a waiting screen displays with a countdown until the planned time. Auto-poll of the status every 5 seconds to detect the start.
- **During the live** — Live video with a pulsing "LIVE" pill and viewer counter. Sidebar with two tabs: _Products_ (clickable list of live products) and _Chat_.
- **Product overlay** — When the host spotlights a product, a card slides in (default: bottom right) with photo, name, price and _Add to cart_ button.
- **Add to cart** — One click on the button adds the product to the official WooCommerce cart. A FAB (floating button) appears at the bottom right with the cart item counter.
- **Coupon flash** — Broadcast by the host, displays at the top with animation and copy button.
- **After the live** — If replay is enabled, a "Watch replay" button lets you replay the live with full event synchronization.

## Global settings

**Live Shopping → Settings** menu. Main sections:

### STUN servers

By default, Google's public STUN servers are used:

```
stun:stun.l.google.com:19302
stun:stun1.l.google.com:19302
```

You can add your own STUN servers (one per line).

### TURN servers

Optional but recommended for viewers behind symmetric NAT (some 4G carriers, corporate VPNs). Format:

```
turn:turn.example.com:3478
turns:turn.example.com:5349
```

Enter the associated _TURN username_ and _TURN credential_.

### Recording and replay

- **Recording enabled**: global yes / no
- **Chunk duration** (ms): 5000 by default. Shorter = more crash resilience but more requests; longer = fewer requests but more loss on crash
- **Replay retention** (days): 90 by default. Beyond that, the daily cron automatically deletes WebM files and related entries

### Capacity and overlay

- **Max viewers per host**: 25 by default. Adjust to your upload bandwidth
- **Overlay position**: right, left or bottom

### Per-live defaults

- Chat enabled by default
- Replay enabled by default
- Login required by default

## STUN and TURN servers — when to configure a TURN

STUN is a simple public IP discovery server, free and sufficient in ~85% of cases. TURN, on the other hand, actually relays media traffic: it consumes bandwidth, but allows connecting two clients that cannot directly reach each other.

Configure a TURN if:

- Your viewers regularly complain about not seeing the video (WebRTC connection state stuck at "connecting")
- Your audience contains many 4G/5G mobile users with symmetric NAT carriers (Free Mobile in France notably)
- Your host or viewers are behind a strict corporate VPN

**Recommended solution** — Deploying a self-hosted [coturn](https://github.com/coturn/coturn) on a small VPS (€5-10 / month) is enough for 30-40 concurrent viewers. Paid alternatives: Xirsys, Twilio Network Traversal Service.

## Recording and replay

### How recording works

Recording happens entirely **on the host's browser side** via the MediaRecorder API:

1. At live start, MediaRecorder is instantiated with automatic detection of the best available codec (VP9 > VP8 > H.264, opus for audio, ~1.5 Mbps video + 96 kbps audio)
2. Every 5 seconds (configurable), a WebM chunk is triggered and uploaded via `POST /wp-json/df-nls/v1/shows/{id}/replay/chunk`
3. The chunk is stored as a WordPress attachment, named `dfnls-show-{id}-part-{NNNNN}.webm`, with `post_parent` pointing to the live
4. The `wp_dfnls_replay_parts` table keeps the order and duration of each chunk

### How replay works

On page load in replay mode:

1. The viewer calls `GET /wp-json/df-nls/v1/shows/{id}/replay` which returns the ordered list of segments and the events timeline
2. Segments are loaded sequentially via the `ended` event of the `` element (native fallback)
3. A MediaSource variant enables transparent concatenation if the browser supports it
4. The playback position (cumulative time) is compared to each event's `offset_ms` — when the point is crossed, the viewer locally triggers the same behavior as in live (show overlay, coupon flash, message)

### Storage and disk space

Order of magnitude: a one-hour live at 1.5 Mbps video + 96 kbps audio produces about **720 MB** of WebM files. With 90-day retention and 4 lives per month, count ~10 GB of disk space dedicated to replays.

**MIME and upload** — The plugin adds an `upload_mimes` filter to allow `video/webm` and `video/mp4` from the media library. Check that your server doesn't have overly strict `LimitRequestBody` or `upload_max_filesize` rules (target 20 MB minimum per chunk).

## Integration: shortcode, block, direct URL

### Direct public URL

Each published live has its own automatically generated URL:

```
https://your-site.com/live/your-slug/
```

This is the simplest way: share this link with your audience.

### Shortcode

To insert a live into an existing page or post:

```
[dfnls_live id="42"]
[dfnls_live id="42" mode="live"]
[dfnls_live id="42" mode="replay"]
[dfnls_live id="42" mode="auto"]
```

Available modes:

- `auto` (default): detects the live status and displays live / waiting / replay accordingly
- `live`: forces live broadcast display (useful for testing)
- `replay`: forces replay mode even if the live is still in progress

### Gutenberg block

In the block editor, search for _"Live Shopping"_. The block supports `wide` and `full` alignments, exposes a selector to choose the live and a mode selector in the inspector sidebar.

### Custom PHP template

The CPT uses `templates/single-live-show.php`. To override, copy this file into your theme under `your-theme/df-native-live-shopping/single-live-show.php`.

## Multilingual with Polylang

The plugin declares the `dfnls_live_show` CPT as translatable with Polylang. On activation, if Polylang is already installed:

- Each live can have an FR, EN, ES, DE, IT version, etc.
- Critical metadata (`_dfnls_product_ids`, `_dfnls_scheduled_at`, live options) is copied automatically between translations
- The 5 integrated languages (FR, EN, ES, DE, IT) are loaded automatically according to the WordPress locale

**Polylang Pro tip** — If you use Polylang Pro and your WooCommerce products are themselves translated, each live translation must be associated with the corresponding language version of the products. The plugin does not perform automatic cross-language mapping on product IDs.

## HPOS and compatibilities

The plugin officially declares compatibility with WooCommerce's high-performance order storage (HPOS) via `FeaturesUtil`. You can enable HPOS on your installation without risk of the cart bridge malfunctioning.

Also compatible with:

- WordPress Multisite (per-site install, no network mode)
- Shared hosting (o2switch, OVH, Infomaniak, PlanetHoster) — signaling uses REST polling, no WebSocket
- Cache plugins (WP Rocket, WP Super Cache) — plugin REST endpoints are automatically excluded

## Security and capabilities

The plugin adds two dedicated capabilities:

- `manage_dfnls_lives` — create, edit, delete lives; access to settings
- `host_dfnls_lives` — access to the host console, start / stop a live

Both capabilities are assigned by default to the `administrator` and `shop_manager` roles. To grant a user only the right to host without being able to create lives:

```
$user = get_user_by('login', 'presenter');
$user->add_cap('host_dfnls_lives');
```

### REST nonces

All action routes (POST) are protected by `wp_rest` nonce. The viewer and host receive their respective nonce via `wp_localize_script` at page load.

### Upload MIME validation

Replay chunk uploads are strictly validated via `wp_check_filetype_and_ext` to accept only `video/webm` and `video/mp4`. Files are renamed server-side (`dfnls-show-{id}-part-{NNNNN}.webm`).

## Cron and maintenance

Two WordPress crons are scheduled on activation:

- `dfnls_cleanup_expired_replays` — **daily**. Deletes replays of lives ended more than N days ago (configurable retention). Uses `wp_delete_attachment(..., true)` to also remove the physical file.
- `dfnls_cleanup_stale_signaling` — **hourly**. Purges signaling messages older than 24h and sessions inactive for more than 90 seconds.

**WP-Cron disabled** — If you've disabled WP-Cron in favor of a system cron, make sure to call `wp-cron.php` at least once per hour so purges execute.

## For developers — REST API

All routes are under the `df-nls/v1` namespace.

### Show

- `GET /shows/{id}` — fetches a live (status, products, options)
- `POST /shows/{id}/join` — joins as viewer or host (body: `peer_id`, `role`)
- `POST /shows/{id}/leave` — cleanly leaves
- `POST /shows/{id}/heartbeat` — keeps the session open (auto every 15s on viewer side)
- `POST /shows/{id}/start` — starts the live (host only)
- `POST /shows/{id}/end` — ends the live (host only)
- `GET /shows/{id}/viewers` — active viewer counter

### WebRTC Signaling

- `POST /signal/send` — sends an SDP/ICE message to a remote peer
- `GET /signal/pull?peer={id}` — retrieves pending messages and performs an implicit heartbeat

### Events

- `POST /shows/{id}/event` — records an event (spotlight, message, coupon)
- `GET /shows/{id}/events?since={id}` — pull events since a given ID

### Chat

- `GET /shows/{id}/chat?since={id}` — pull messages since an ID
- `POST /shows/{id}/chat` — send a message

### Cart bridge

- `POST /cart/add` — adds a product to the cart with source tracking (`show_id`, `product_id`, `quantity`)
- `GET /cart/summary` — current cart counter and total

### Recording and replay

- `POST /shows/{id}/replay/chunk` — multipart upload of a WebM chunk
- `GET /shows/{id}/replay` — segments + timeline events for playback

## Plugin structure (PSR-4)

```
df-native-live-shopping/
├── df-native-live-shopping.php        # Bootstrap
├── uninstall.php
├── readme.txt
├── assets/
│   ├── js/    (host.js, viewer.js, admin.js, block-editor.js)
│   └── css/   (host.css, viewer.css, admin.css)
├── languages/                          # 5 .po/.mo + .pot
├── templates/                          # single-live-show.php, viewer-container.php, ...
└── src/
    ├── Plugin.php
    ├── Activator.php   Deactivator.php
    ├── PostType/       (LiveShow.php)
    ├── Database/       (Schema + 5 Repository.php)
    ├── Admin/          (AdminPages, MetaBoxes, SettingsPage)
    ├── Api/            (RestController, SignalingController, CartController)
    ├── Recording/      (RecordingHandler)
    ├── Replay/         (ReplayHandler)
    ├── Frontend/       (Renderer, Shortcode, Block)
    └── Compat/         (PolylangCompat)
```

Root namespace: `DataFirefly / NativeLiveShopping`, manual PSR-4 autoloader declared in `df-native-live-shopping.php`.

## Troubleshooting

### Viewers don't see the video

- Verify the site is on HTTPS (mandatory for WebRTC)
- Open the browser console on the viewer side, look for `ICE failed` or `connection state failed` errors
- Configure a TURN server if the audience contains many 4G mobiles
- Verify that the host's upload bandwidth is sufficient (fast.com utility on the host side)

### The host console doesn't detect the camera

- Verify the browser has granted permission (padlock icon in the URL bar)
- On macOS, check system permissions: _Preferences → Security → Camera_
- Close other applications using the camera (Zoom, Teams, OBS...)

### Replay chunks are not uploading

- Check `upload_max_filesize` and `post_max_size` in php.ini (target 20 MB minimum)
- Check `LimitRequestBody` on Apache side if applicable
- Look at the host console activity log to identify the exact error
- Check the `wp-content/uploads` folder permissions

### Cart doesn't retain additions

- Verify no cache plugin caches the `/wp-json/df-nls/v1/*` endpoints
- Verify WooCommerce cookies (`woocommerce_cart_hash`, `wp_woocommerce_session_*`) are properly emitted
- On strict HTTPS, verify cookies have the `Secure` flag

### Replays take too much space

- Reduce retention (e.g. from 90 to 30 days) in settings
- Disable recording for lives where it's not necessary ("Allow replay" checkbox in _Options_ metabox)
- Reduce bitrate by modifying `host.js` (variable `videoBitsPerSecond`)

## Uninstallation

On simple deactivation, data is preserved and crons are unscheduled. On **full deletion** of the plugin from _Plugins_, `uninstall.php` performs:

- Removal of the 5 custom tables
- Removal of all `dfnls_*` options
- Removal of capabilities from roles
- Unscheduling of crons
- Optional: removal of CPTs and all replay attachments if the `dfnls_uninstall_delete_data` option was enabled before uninstallation

**Warning** — By default, lives and their replays are NOT deleted on uninstallation. To delete everything, enable the _Delete all data on uninstall_ option in settings before uninstalling.

## Support and roadmap

Technical support included for 12 months via the DataFirefly customer area. Plugin updates are available from your account, with email notification for major versions.

Roadmap ideas:

- Automatic SFU switching beyond a viewer threshold
- Live polls (poll.open / poll.close already reserved in the event protocol)
- Native analytics (average watch time, conversion rate per live)
- Multi-host support (two concurrent presenters)
