{
  "slug": "bw-lead-ai",
  "name": "BW Lead Attribution Intelligence",
  "version": "1.2.0",
  "download_url": "https://plugins.bowden.works/wp-content/uploads/plugin-updates/bw-lead-ai-1.2.0.zip",
  "download_hash": "sha256:dfb051c061c63f9594728f774c4703e6f74e2347092b62a6d24d258774859398",
  "download_size": 236968,
  "requires": "6.0",
  "tested": "",
  "requires_php": "7.4",
  "last_updated": "2026-07-26",
  "homepage": "https://plugins.bowden.works/bw-lead-ai/",
  "author": "Bowden Works",
  "description": "Capture traffic source, attribute it to every lead, and understand where your leads are coming from.",
  "changelog": "## [1.2.0] - 2026-07-26\n\n### Added\n- **Interaction tracking** — a new **Interactions** settings tab that records what\n  visitors did on the way to converting, and attaches it to the lead alongside the\n  traffic source. Nine interaction types, **every one off by default**:\n\n  | Type | What it records |\n  |---|---|\n  | Video plays | First play plus progress milestones, for HTML5 `<video>`, YouTube and Vimeo |\n  | File downloads | Clicks on links ending in a configured extension (pdf, doc, xls, zip…) |\n  | Phone clicks | `tel:` links |\n  | Email clicks | `mailto:` links |\n  | Social clicks | Links to configured social hostnames |\n  | Outbound clicks | Links to any other external site |\n  | Custom actions | Elements you name yourself by CSS selector |\n  | Scroll depth | How far down the page the visitor read |\n  | Form starts | First interaction with any form field |\n\n- **Interactions appear in `{bw:summary}`** — a count on the stats line, a\n  breakdown beneath it, and an `== Interactions ==` section listing what happened.\n  In `{bw:summary_detailed}` they are interleaved into the journey instead, so the\n  visit reads as one chronological story.\n- **New merge tags:** `{bw:events}` (total), `{bw:events_list}` (breakdown), and\n  `{bw:event.<type>}` for a single type's count, e.g. `{bw:event.video}`. These are\n  registered with Gravity Forms — and shown in the BW Lead Data field's dropdown\n  under an \"Interactions\" group — only once at least one type is enabled.\n- **Video milestones** (default 25/50/75/100%) make a real watch distinguishable\n  from an accidental click. Configurable, or empty to record plays only.\n- **Custom actions** let an admin define events without a plugin update, e.g.\n  `Pricing CTA : .pricing-cta, #get-quote`. A custom match wins over the generic\n  link classification, so clicking a selector that is also an outbound link records\n  one event, not two.\n\n### Fixed\n- **Saving one settings tab no longer resets settings owned by another tab.**\n  All tabs post to the same option and the sanitizer falls back to the *default*\n  for any key missing from the POST, so saving the Settings tab silently wiped the\n  Form Fields tab's legacy CSS-selector targets back to empty. Every tab now\n  round-trips the settings it doesn't render through hidden inputs, including the\n  nested `field_targets` values. This bug predates 1.2.0 and affected 1.0.x.\n\n### Notes\n- **Sites that enable nothing pay nothing.** With no interaction types ticked,\n  `events.js` is never enqueued, no listeners are attached, no third-party video\n  APIs are loaded, and the summary is byte-for-byte what it was before.\n- **YouTube tracking rewrites embed URLs.** The IFrame API only talks to players\n  that opted in with `enablejsapi=1`, so when video tracking is on, YouTube iframes\n  get that parameter appended — which reloads the embed once, on page load, before\n  the visitor can press play. Vimeo needs no such change (it uses postMessage).\n- Interaction records are capped in browser storage (first 5 + last 25) the same way\n  visits are, but the **counts are stored separately and never trimmed**, so totals\n  stay accurate over a long multi-visit journey even after old records age out.\n- Nothing is sent to the server and no new database tables are involved — same\n  client-side-only model as the rest of the plugin."
}
