Sending Custom Events to Leaky Paywall Insights
This article walks through when custom events make sense, how to send one, and a few common examples.
What Insights already tracks automatically
Before you add anything custom, Insights already receives these events for every subscriber:
- Checkout Started — subscriber reached the payment step of checkout
- Registration — subscriber account created
- Subscription Started — first paid subscription
- Subscription Renewed — recurring renewal
- Subscription Cancelled
- Level Changed — subscriber changed tiers
- Status Changed — status transition (active, past_due, etc.)
- Payment Succeeded / Payment Failed
- Login
- Content Viewed — logged-in subscriber loaded a paywalled article
- Paywall Displayed
If your use case is covered above, you do not need custom events.
When to use a custom event
Add a custom event when you want to track something Insights does not know about. Common cases:
- Submissions from a custom signup form (not the built-in LP form)
- In-app actions — bookmarking, commenting, completing a video, downloading a PDF
- Subscriber milestones — reaching a reading streak, hitting a plan limit
- External integrations — email opens from Mailchimp, form completions from a survey tool
- Manual admin actions — flagging a subscriber for follow-up
- Anything else you want to slice, filter, or trend in Insights
Requirements
- Leaky Paywall 5.0 or later
- Insights configured in Leaky Paywall → Settings → Insights (with a valid API key)
- Ability to add a small PHP file to your WordPress installation (either a mu-plugin or a code-snippets plugin like WPCode)
The function
Leaky Paywall provides one helper function for sending events.
leaky_paywall_track_event( $event_name, $user, $properties );
| Argument | Type | Required | Description |
|---|---|---|---|
$event_name |
string | Yes | Any name you choose. Shown in Insights as-is. |
$user |
int or WP_User |
Yes | WordPress user ID or a WP_User object. |
$properties |
array | No | Key-value pairs of extra data. Values must be simple scalars (strings, numbers, booleans). |
Returns: true if the event was queued for sending, false if Insights isn't configured or the user can't be resolved. The actual send is non-blocking, so this call adds essentially zero latency.
What Insights adds to every event automatically
You do not need to pass any of these — they attach to every event by default:
emailwp_user_iddisplay_namelevel_namestatus(active / trial / etc.)customer_ip(when detectable)occurred_at(server timestamp)
Your properties are merged in alongside these. Use properties for the extra context specific to your event.
Example: Custom event on a form submission
Fire an event when someone submits your custom signup form (using the LP REST API to create the subscriber):
Naming your events
A few guidelines that keep Insights clean and easy to filter:
- Use short, human-readable names — "Newsletter Signup", not "nl_sgnp_v2"
- Reuse names across similar events instead of variants like "Signup Home", "Signup Footer", "Signup Sidebar" — put the variant in a
sourceproperty instead - Prefer past tense for consistency with the built-in events — "Article Bookmarked", not "Bookmark Article"
Testing
- Add the code (mu-plugin or code snippet).
- Trigger the action in your site — submit the form, click the button, whatever fires it.
- Check Leaky Paywall → Insights for the event to appear on the subscriber's activity timeline.
- If nothing shows up, check Leaky Paywall → Tools → Debug Log for entries mentioning
Insights. Most failures are silent by design (Insights sends are non-blocking) but errors that are caught get logged there.
Common issues
The event isn't showing up in Insights.
- Confirm Insights is enabled at Leaky Paywall → Settings → Insights and shows a valid API key
- Confirm the user has an LP subscriber record (level_id in user meta); the tracker skips users without one, unless you pass a WP_User object explicitly
Properties aren't appearing on the event.
- Property values must be simple scalars — strings, numbers, booleans. Arrays and objects will be dropped.
- Empty strings and
nullvalues are filtered out. - Property names should be lowercase with underscores (
source_form, notsourceForm).