WP Manifestindependent plugin directory
manifest / analytics / video-lead-tracker

Video Lead Tracker

Gates an HTML5 video behind a lead form, tracks watch ranges, and provides analytics inside WordPress admin.

★ 1stars

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/mkarim1378/video-lead-tracker/archive/refs/heads/main.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

Gate your video content behind a lead form — then know exactly who watched, how much, and where they dropped off.

Video Lead Tracker is a self-hosted WordPress plugin that turns any HTML5 video into a lead-capture and analytics engine. Visitors submit their name and mobile number before the video unlocks. Every second of playback is recorded, aggregated, and surfaced in a built-in admin dashboard — with no third-party analytics services and no data leaving your server.


Why Video Lead Tracker

Most lead-capture tools stop at the form. You collect a name and number, but you have no idea whether the person who submitted actually watched your content — or for how long. Video Lead Tracker closes that gap.

  • A lead who watched 80% of your product demo behaves differently from one who watched 5 seconds and left. Now you can tell them apart.
  • All data lives in your WordPress database. No external SaaS, no tracking pixels, no GDPR headaches from third parties.
  • Built for the Iranian market: native support for all local mobile number formats and direct integration with Kavenegar and SMS.ir for OTP verification.

Features

Lead Capture & Identity

  • Overlay form collects name + mobile number before the video plays
  • Mobile number is normalized from any Iranian format (09xxxxxxxxx, +98xxxxxxxxxx, etc.) to a canonical 98xxxxxxxxxx form
  • Returning visitors are recognized automatically via a secure identity token stored in localStorage and a cookie — they skip the form on repeat visits
  • Anonymous viewing data (ranges, events, page visits) is retroactively linked to the lead record the moment the form is submitted
  • Optional OTP verification via SMS confirms mobile ownership before video access

OTP Verification

  • 6-digit cryptographically random code, SHA-256 hashed before storage
  • Configurable code expiry and resend cooldown
  • Built-in integrations: Kavenegar and SMS.ir
  • Brute-force safe: attempt counter increments before code comparison
  • Clean, in-page OTP UI with masked mobile display and resend countdown

Video Analytics

Event tracking — every meaningful player action is recorded:

Event Description
video_loaded Metadata loaded; video duration stored
play / pause Playback started or stopped
seek_start / seek_end User scrubbed the timeline
heartbeat Periodic progress ping (default every 10 s)
ended Video played to the end
rate_change Playback speed changed
error Player error with error code

Watch range tracking — continuous play segments are captured as [from_second, to_second] pairs:

  • Ranges are committed on pause, seek, heartbeat, and page close
  • Page-close commits use navigator.sendBeacon with a fetch keepalive fallback so no data is lost when the tab closes
  • Seeking mid-play correctly commits the pre-seek segment and starts a fresh one at the new position

Per-viewer summary — after each range commit, aggregated stats are updated in real time:

Metric How it's calculated
total_watch_seconds Sum of all raw range durations
unique_watch_seconds Sum of merged (deduplicated) ranges
unique_watch_percent unique / duration × 100, capped at 100%
max_video_time_seconds Furthest point reached in the video
reached_end ended event fired, OR max position ≥ duration − 2 s
sessions_count Distinct sessions in which the video was watched
first_play_at Timestamp of the viewer's first play event

Range deduplication uses a 0.25 s tolerance so scrubbing back a tiny amount doesn't inflate unique watch time.

Per-second heatmap — for each video, a heatmap table tracks how many viewers (total, unique leads, unique visitors) watched each second. Useful for spotting the exact moment engagement drops.

Page Visit Tracking

  • page_view, page_visible, page_hidden, page_unload, and heartbeat events
  • Visibility API for accurate focus/blur detection
  • sendBeacon on tab close so unload events are never lost

Admin Dashboard

  • Overview — plugin-wide totals: leads, sessions, videos, watch hours
  • Leads Report — sortable table of all leads with watch stats and verification status; click any row for the full lead detail view
  • Video Analytics — per-video funnel: viewers → starters → completers; average unique watch percent; timeline of activity
  • Heatmap UI — color-coded, per-second bar chart showing where viewers engage and where they drop
  • Export — download any report as CSV or XLSX

Privacy & Security

  • IP addresses can be stored raw, SHA-256 hashed, or not stored at all (configurable per site)
  • User-agent storage is opt-in
  • Identity tokens are never stored; only their SHA-256 hash (keyed with WP's secure_auth salt) is persisted
  • All write endpoints are rate-limited per IP using WordPress transients
  • No jQuery dependency — pure vanilla ES5 JavaScript

Requirements

Minimum
WordPress 5.8
PHP 7.4
MySQL 5.6 / MariaDB 10.1

Installation

  1. Upload the video-lead-tracker folder to /wp-content/plugins/
  2. Activate the plugin from Plugins → Installed Plugins
  3. Go to Video Tracker → Settings to configure OTP provider, tracking options, and privacy preferences
  4. Place the shortcode on any page or post:
[video_lead_tracker key="my-video" url="https://example.com/video.mp4"]

Shortcode Parameters

Parameter Default Description
key (required) Unique identifier for this video
url (required) Direct URL to the .mp4 (or any HTML5-compatible format)
title — Video title shown in admin reports
submit_text مشاهده ویدیو Label on the form submit button

Usage Guide

Step 1 — Initial Setup

After activating the plugin, go to Video Lead Tracker → Settings:

Setting Description
Enable Tracking Master switch — nothing is recorded until this is on
Tracking Page The page where your shortcode lives
Video Key A unique slug for this video (must match the key shortcode attribute)
Video Title Display name shown in admin reports
Video URL Direct URL to the MP4 file

Step 2 — Embed the Video

Place the shortcode inside any page or post:

[video_lead_tracker key="demo" url="https://yourdomain.com/video.mp4" title="Product Demo"]

When a visitor arrives at the page:

  1. An overlay form asks for their name and mobile number
  2. If OTP is enabled, they receive a verification code via SMS
  3. After the form is submitted the video unlocks and tracking begins
  4. On return visits the visitor is recognised automatically and sees the video directly — no form

Step 3 — Reading the Admin Dashboard

Overview

Once the first visits are recorded, the Overview page shows five KPIs:

  • Total Leads — number of unique people who submitted the form
  • Verified — leads whose mobile number was confirmed via OTP
  • Sessions — total page loads by all visitors
  • Videos — number of active videos
  • Watch Hours — total deduplicated watch time across all viewers

Below the KPIs you'll find the Recent Leads and Top Videos tables.

Overview data is cached for 5 minutes. The cache is automatically invalidated after each watch-range commit, so live data appears immediately after a viewer watches.

Leads Report

A sortable table of all leads. Columns:

  • Name / Mobile — name and masked mobile number
  • Verified — OTP confirmed?
  • Videos Watched — how many distinct videos this lead has watched
  • Avg Watch — progress bar showing their average unique watch percentage
  • Sessions — number of sessions

Click any lead's name to open the Lead Detail page:

  • Full identity info (unmasked mobile, verification status, first/last seen)
  • Video Watch History table (watch %, unique seconds, sessions, completed badge, first play)
  • Last 20 Sessions table (browser, device, OS, landing URL)

The Export CSV button at the top downloads all leads with their stats.

Video Analytics

A list of all active videos with aggregate stats. Click any video to open its detail page:

  • 5 KPI cards: Viewers, Avg %, Watch Hours, Completions, Sessions
  • Watch Distribution: how many viewers fell into each bucket — 0–25%, 25–50%, 50–75%, 75–100%
  • Top Viewers: ranked by unique watch percentage, each linked to their Lead Detail page

The Export CSV button downloads all video summary rows.

Heatmap

  1. Pick a video from the dropdown — the bar chart loads automatically
  2. Each bar represents a time bucket of the video (bucket size auto-scales so there are at most ~120 bars)
  3. Toggle between Total Views / Unique Visitors / Unique Leads using the buttons at the top
  4. Hover over any bar to see the exact time range and count

How to read it: a short bar means fewer viewers watched those seconds. Tall bars at the start and short bars toward the end = drop-off in the middle of the video. A sudden dip in the middle may indicate a boring segment or a technical issue.

The Export Heatmap CSV button downloads raw per-second data for further analysis in Excel or any BI tool.

Logs

If something goes wrong (OTP delivery failure, database error, aggregation issue), go to Logs:

  • Filter by level: Error / Warning / Info / Debug
  • Each entry shows the exact timestamp, context (which part of the plugin wrote it), message, and expandable metadata
  • The last 200 entries are shown, newest first

OTP Provider Setup

Kavenegar

  1. Log in to your Kavenegar panel and copy your API key
  2. Go to Video Tracker → Settings → OTP and select Kavenegar
  3. Paste your API key and set the sender line number

SMS.ir

  1. Go to Video Tracker → Settings → OTP and select SMS.ir
  2. Enter your API key
  3. Set the template ID for the OTP message pattern

Database Schema

The plugin creates 11 tables (prefixed with wp_vlt_):

Table Purpose
vlt_leads One row per unique mobile number
vlt_lead_names Full history of names submitted per lead
vlt_visitors One row per browser (anonymous identity)
vlt_sessions One row per page load
vlt_page_visits Page tracking events
vlt_videos One row per video_key
vlt_video_events Player events (play, pause, seek, …)
vlt_video_ranges Raw watch segments [from, to]
vlt_video_user_summary Aggregated per-viewer stats
vlt_video_heatmap Per-second view counts
vlt_logs Internal plugin logs

Optional tables created on demand:

Table Created when
vlt_otp_codes OTP feature is enabled
vlt_video_heatmap_uniques Heatmap deduplication is enabled

Schema upgrades are handled automatically via WordPress's dbDelta() on plugin update.


REST API

All endpoints live under /wp-json/vlt/v1/.

Method Endpoint Description
POST /session/init Initialize or restore a visitor session
POST /lead/submit Submit the lead form
POST /otp/send Send an OTP to the visitor's mobile
POST /otp/verify Verify the submitted OTP code
POST /track/page Record a page visit event
POST /track/video-event Record a player event
POST /track/video-range Commit a watched range segment

Localization

The plugin ships with a full Persian (fa_IR) translation. All user-facing strings in both PHP and JavaScript are wrapped with WordPress's standard __() / _e() functions and the video-lead-tracker text domain.

To add a new language, copy languages/video-lead-tracker.pot and use Poedit or Loco Translate to create a .po file, then compile it to .mo.


Architecture Notes

  • No jQuery. All frontend JavaScript is plain ES5, split across two IIFE modules:
    • vlt-frontend.js — session init, form, OTP, page tracking, shared state (window.vltState, window.vltApiFetch)
    • vlt-video-tracker.js — video event and range tracking; boots on the custom vlt:videoReady event
  • Static classes. All PHP classes use static methods and a singleton bootstrap (VLT_Plugin::get_instance()) — no instantiation required.
  • Manual autoloader. A spl_autoload_register map in the main plugin file replaces Composer autoload to keep the plugin self-contained with zero dependencies.
  • Aggregation on write. VLT_Aggregator::aggregate() runs synchronously after every range insert so the summary table is always up to date without background jobs.

License

GPLv2 or later — the same license as WordPress itself.


Author

Mohamad Karim — m-karim.ir