Custom Events API
PersonalizeWP tracks visitor behaviour on your WordPress site to build detailed visitor profiles. By default, it automatically tracks page views, form submissions, and other standard interactions. The Custom Events API extends this capability, allowing you to track any custom user behaviour on your site - from button clicks and video plays to product interactions and scroll depth.
Why Track Custom Events?
Custom events give you deeper insight into how visitors interact with your content. This rich behavioural data allows you to:
- Build better visitor profiles - Understand not just what pages people visit, but what they click, watch, and interact with
- Create targeted segments - Group visitors based on specific actions, like "clicked pricing CTA" or "watched product demo video"
- Personalise content - Show different content to visitors based on their past interactions
- Measure engagement - Track which buttons, videos, or features drive the most engagement
- Analyse user journeys - See the complete path visitors take through your site, including micro-interactions
How It Works
The Custom Events API follows a three-step pattern:
- Track the event - Use JavaScript to capture user interactions and send them to PersonalizeWP
- Register the event type - Tell PersonalizeWP about your custom event so it can be validated and displayed
- Display the event data - Format how the event appears in the admin activity lists
Once configured, custom events appear alongside standard page view data in PersonalizeWP's admin interface and can be used for segmentation, reporting, and personalization rules.
Implementation Guide
Let's start with a common use case - tracking when visitors click important buttons on your site. This example tracks clicks on WordPress core button blocks.
Step 1: Track the Event with JavaScript
Add this code to track button clicks. The tracking JavaScript captures the button text and page context, then sends it to PersonalizeWP via the REST API:
// Add inline JS which records a Click Event on any core WP Button Block
add_action( 'wp_footer', function() {
?>
<script>
document.addEventListener( 'click', function( event ) {
let link = event.target.closest( 'a' );
if ( ! link || ! link.classList.contains( 'wp-block-button__link' ) ) {
return;
}
// Use JS optional chaining to check for object and method existence.
if ( window?.PersonalizeWP?.tracking?.trackEvent ) {
let clickArgs = {
'button-text': link.textContent,
};
// Add extra data so as to know what page the button is on.
if ( window.pwpTrack?.obj ) {
clickArgs.object = window.pwpTrack.obj;
}
// And what type of page it is.
if ( window.pwpTrack?.type) {
clickArgs['object-type'] = window.pwpTrack.type;
}
window.PersonalizeWP.tracking.trackEvent( 'click', clickArgs );
}
} );
</script>
<?php
} );
How this works:
The trackEvent() function merges your custom arguments with PersonalizeWP's default tracking data (visitor UUID, timestamp, current URL). All of this is sent to the /personalizewp/v1/activity REST API endpoint and stored in PersonalizeWP's custom database table.
Function signature:
window.PersonalizeWP.tracking.trackEvent( eventName, eventArgs )
eventName(string, required) - The event identifier, restricted to lowercase alphanumeric characters, dashes, and underscores (WordPresssanitize_keyformat). Examples:click,video-play,add-to-carteventArgs(object, required) - Key-value pairs of metadata about the event. Keys follow the same format restrictions as event names and should be under 150 characters. Values should follow WordPress Post Meta format conventions.
Implementation notes:
- DOM timing - Adding the inline JS to
wp_footerensures the DOM is fully available. Alternatively, wait for theDOMContentLoadedevent - Event delegation - Attaching the listener to the document and using event bubbling means dynamically added buttons are automatically tracked
- Safe access - The optional chaining (
?.) ensures PersonalizeWP is loaded before trying to track. For more robust timing control, see Example 3
Step 2: Register the event type
Tell PersonalizeWP about your custom event type so it can validate incoming data and display it correctly in the admin:
$personalizewp = personalizewp();
$personalizewp->register_event_type(
'click',
array(
'label' => 'Button click',
)
);
Parameters:
'click'- The event type name, must match the name used intrackEvent()in Step 1'label'- How the event appears in the admin interface. Defaults to the event type name if not provided
Important: Event type registrations should be hooked to the personalizewp_loaded action or later to ensure PersonalizeWP has fully loaded.
Step 3: Display Event Data in Admin
Format how your custom event data appears in the PersonalizeWP admin activity lists. This filter controls the "Event Value" column:
// Populate the 'Event Value' column cell for Click Events
add_filter( 'personalizewp_activity_table_event_value_click', function( $link_title, $link, $title, $item ) {
$button = PersonalizeWP\Model\Activity
::get_metadata( $item['ID'], 'button-text', true );
$obj_id = PersonalizeWP\Model\Activity
::get_metadata( $item['ID'], 'object', true );
if ( ! empty( $obj_id ) ) {
$title = get_the_title( $obj_id );
$link = get_edit_post_link( $obj_id );
return sprintf(
'Button `%1$s` clicked on <a href="%3$s" aria-label="%4$s">%2$s</a>',
esc_html( $button ),
esc_html( $title ),
esc_url( $link ),
esc_attr(
sprintf(
'Edit “%s”',
$title
)
)
);
}
return sprintf(
'Button `%1$s` clicked on `%2$s`',
esc_html( $button ),
esc_html( $item['url'] ),
);
}, 10, 4 );
What this displays:
- If the button click happened on a specific post/page: "Button
Get in Touchclicked on [Post Title]" (linked to edit screen) - If no post/page context: "Button
Get in Touchclicked onhttps://example.com/pricing"
Result:
With these three steps implemented, your custom events will:
- Be tracked automatically whenever buttons are clicked
- Appear in the Recent Events list with formatted, readable descriptions
- Be available for filtering and export
- Be associated with visitor profiles for segmentation and personalization