email-gate

npm: @playerstack/plugin-email-gate

Pause the video and show an email form before the visitor can keep watching. Lead capture for course previews, lead magnets, and pre-roll qualifying.

Secure-by-default: if you set webhookUrl, you must also set challengeUrl. The plugin refuses to render otherwise — this prevents accidentally exposing an unauthenticated lead-capture endpoint that any bot can scrape from DevTools and flood. See Email lead capture security for the full server protocol with examples for Next.js, Hono, and Cloudflare Workers.

Quickstart — open mode (event bus only)

For local dev, internal tools, or when you handle the lead inside the page:

<player-stack
  src="https://files.example.com/lesson.mp4"
  data-config='{
    "emailGate": {
      "enabled": true,
      "at": "before",
      "title": "Drop your email to watch the full lesson",
      "buttonLabel": "Unlock video →"
    }
  }'
></player-stack>

The form pauses the video and emits email-gate:submit on the event bus. Nothing is POSTed anywhere — your code listens via a custom plugin if needed.

<player-stack
  src="https://files.example.com/lesson.mp4"
  data-config='{
    "emailGate": {
      "enabled": true,
      "at": "before",
      "webhookUrl":   "https://your-api.com/api/leads",
      "challengeUrl": "https://your-api.com/api/leads/challenge"
    }
  }'
></player-stack>

Both URLs required. Server protocol + full code examples: Email lead capture security.

Config

FieldTypeDefaultDescription
enabledbooleanfalsePlugin is a no-op unless true
at"before" | number"before"Show on init, or after N seconds of playback
atPercentnumberAlternative trigger at N% of duration
webhookUrlstringWhere to POST LeadsSubmission. Requires challengeUrl.
challengeUrlstringWhere to GET LeadsChallenge. Server issues Altcha challenge + single-use nonce.
titlestring"Watch the rest"Heading text
buttonLabelstring"Continue watching →"Submit button label
storageKeystring"playerstack:email-gate"localStorage key prefix

Events

NamePayloadWhen
email-gate:submit{ email: string }Server accepted the submission (or open-mode form was filled, honeypot not tripped)

Built-in client-side protections

Use cases