FluentCRM: event tracking
SkillCommunicationTrack and consume FluentCRM 3.x contact events from companion plugins. Covers the experimental event_tracking flag, the track method of FluentCrmApi('event_tracker'), fc_event_tracking, repeatable counter semantics, subscriber resolution by subscriber/email/user/current contact, fluent_crm/event_tracked, the fluent_crm/track_event_activity action bridge, event_tracking advanced contact filters, event_tracking_keys option source, and FluentCampaign Pro's Tracking Event Recorded trigger / Add Event Tracking action. Use when a plugin records user activity, builds event-based automations, filters contacts by tracked events, or audits code touching EventTracker, Tracker, fluent_crm/event_tracked, or fc_event_tracking.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the FluentCRM: event tracking skill
What this skill tells your AI
The instructions your AI receives, as published by lonsdale201/wp-agent-skills in fluentcrm/fluentcrm-event-tracking/SKILL.md and read by ahel’s review.
Use this skill when a plugin wants to record product usage, LMS actions, purchase milestones, profile events, or any other contact activity into FluentCRM's event timeline and Pro automation conditions.
Guard the feature
Event tracking is core FluentCRM code, but it is disabled by default behind the experimental setting:
use FluentCrm\App\Services\Helper;
if (!function_exists('FluentCrmApi') || !Helper::isExperimentalEnabled('event_tracking')) {
return;
}
FluentCrmApi('event_tracker')->track() returns WP_Error('not_enabled', ...) when the flag is off. Always handle WP_Error.
Track an event
The API key is event_tracker:
$event = FluentCrmApi('event_tracker')->track([
'subscriber_id' => (int) $contactId, // preferred when known
'provider' => 'my-plugin',
'event_key' => 'course_completed',
'title' => 'Course completed',
'value' => (string) $courseId,
], true);
if (is_wp_error($event)) {
return;
}
Subscriber resolution order in Tracker::track():
subscriberobject, when suppliedsubscriber_idemailuser_idconverted to the WP user's email- current contact cookie / current user through
fluentcrm_get_current_contact()
Required fields are event_key and title. Both are truncated to 192 characters and sanitized. provider defaults to custom; value is sanitized as textarea text.
Repeatable vs append-only
Second argument controls storage behavior:
FluentCrmApi('event_tracker')->track($data, true); // repeatable/default
FluentCrmApi('event_tracker')->track($data, false); // append a new row every time
With $repeatable = true, FluentCRM looks up an existing row by (subscriber_id, event_key, title), updates value, increments counter, saves, and fires fluent_crm/event_tracked.
With $repeatable = false, it creates a new fc_event_tracking row every time and fires the same action.
There is no unique DB key for the repeatable lookup in 3.1.13; the counter is application-level, not an atomic financial counter. Use it for automation/activity state, not exact billing/accounting.
Action bridge
EventTrackingHandler also registers:
do_action('fluent_crm/track_event_activity', $data, $repeatable);
That delegates to FluentCrmApi('event_tracker')->track(), but do_action() discards the return value. Use the API method directly when you need the created EventTracker or WP_Error.
Event hook
Every successful track fires:
add_action('fluent_crm/event_tracked', function ($event, $subscriber) {
// $event is FluentCrm\App\Models\EventTracker
// $subscriber is FluentCrm\App\Models\Subscriber
}, 10, 2);
FluentCampaign Pro's "Tracking Event Recorded" trigger listens to this exact hook with actionArgNum = 2.
Pro automation trigger and action
Pro trigger: FluentCampaign\App\Services\Funnel\Triggers\TrackingEventRecordedTrigger
triggerName = fluent_crm/event_tracked- requires event tracking to be enabled
- only runs for contacts with
status = subscribed - checks configured
event_key - checks
minimum_event_countagainstEventTracker.counter - supports Pro condition groups through
fluent_crm/event_tracking_condition_groups - uses
source_trigger_name = fluent_crm/event_trackedandsource_ref_id = $event->id
Pro action: FluentCampaign\App\Services\Funnel\Actions\AddEventTrackerAction
- action name
add_contact_event_tracker - parses SmartCodes in title/value with
fluent_crm/parse_campaign_email_text - calls
FluentCrmApi('event_tracker')->track($eventAtts, is_unique === yes)
If you build a custom trigger/action around event tracking, still follow fluentcrm-funnel-trigger and fluentcrm-funnel-action for lifecycle and status rules.
Contact filters and option source
EventTrackingHandler registers the advanced contact filter provider:
fluentcrm_contacts_filter_event_tracking
Supported filter properties in 3.1.13:
event_tracking_keyevent_tracking_titleevent_tracking_valueevent_tracking_key_count
The built-in option key for selectors is event_tracking_keys. It returns unique event_key values from fc_event_tracking as [{id, title}].
Do not register your own fluentcrm_ajax_options_event_tracking_keys filter unless you intentionally override/extend the built-in source. The core handler registers it with one accepted argument, while custom option filters usually use the 3-argument pattern described in fluentcrm-rest-options.
Privacy and safety
Event values are visible in the contact timeline widget and can feed automation conditions. Do not store access tokens, personal secrets, raw request bodies, or unbounded JSON blobs in value.
Good event shape:
[
'provider' => 'lw-lms',
'event_key' => 'lesson_completed',
'title' => 'Lesson completed',
'value' => (string) $lessonId,
]
Bad event shape:
[
'event_key' => 'webhook_payload',
'title' => 'Webhook payload',
'value' => wp_json_encode($_POST), // too large, may contain secrets
]
Common mistakes
- Ignoring the experimental flag and treating
WP_Error('not_enabled')as a model. - Passing a WP user ID as
subscriber_id. Useuser_idfor WP users, or resolve the FluentCRM contact first. - Assuming repeatable tracking is DB-unique or atomic. It is a lookup/update convenience.
- Using a different hook for Pro automation. The trigger listens to
fluent_crm/event_tracked, notfluentcrm_event_tracked. - Storing translated labels as
event_key. Keepevent_keystable ASCII-like machine keys; put human text intitle.
Cross-references
- Use
fluentcrm-funnel-triggerfor custom event-driven automation triggers. - Use
fluentcrm-funnel-actionfor custom automation actions that write tracked events. - Use
fluentcrm-smartcodes-segmentswhen event values appear in SmartCodes or Pro dynamic segments.
References
- Official documentation: https://developers.fluentcrm.com/database/orm/
- Verified source paths:
fluent-crm/app/Api/config.phpfluent-crm/app/Api/Classes/Tracker.phpfluent-crm/app/Models/EventTracker.phpfluent-crm/app/Models/Subscriber.phpfluent-crm/app/Hooks/Handlers/EventTrackingHandler.phpfluent-crm/app/Hooks/Handlers/Integrations.phpfluent-crm/app/Services/Helper.phpfluent-crm/database/migrations/SubscriberEventTracking.phpfluentcampaign-pro/app/Services/Funnel/Triggers/TrackingEventRecordedTrigger.phpfluentcampaign-pro/app/Services/Funnel/Actions/AddEventTrackerAction.phpfluentcampaign-pro/app/Services/Funnel/Conditions/FunnelConditionHelper.php
Signals
- GitHub stars
- 22
- Forks
- 2
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
fluentcrm-event-tracking- Source
- github.com/lonsdale201/wp-agent-skills