Analytics Dashboard
Core Forms includes a built-in analytics system that tracks form performance without external dependencies. It provides funnel metrics, field-level drop-off analysis, attribution data, spam trends, and actionable recommendations.
Architecture
The analytics system has three components:
- Tracker -- Records raw events to the
wp_cf_analyticstable - Dashboard -- Aggregates events into funnel metrics and insights
- REST API -- Exposes analytics data for admin UI and external consumption
Event Types
The Tracker records six event types:
| Event | Source | Description |
|---|---|---|
view |
Client-side (AJAX) | Form appeared in the viewport |
start |
Client-side (AJAX) | User interacted with the first field |
submit |
Server-side (hook) | Form submitted successfully |
abandon |
Client-side (AJAX) | User left the page after starting |
field_interaction |
Client-side (AJAX) | User focused/changed a specific field |
spam |
Server-side (hook) | Submission flagged as spam |
Data Storage
Events are stored in the wp_cf_analytics table:
| Column | Type | Description |
|---|---|---|
id |
INT | Primary key |
form_id |
INT | Form post ID |
event_type |
VARCHAR(30) | Event type constant |
page_url |
TEXT | URL where the event occurred |
utm_source |
VARCHAR(100) | UTM source parameter |
utm_medium |
VARCHAR(100) | UTM medium parameter |
utm_campaign |
VARCHAR(100) | UTM campaign parameter |
field_name |
VARCHAR(100) | Field name (for field_interaction events) |
meta |
TEXT | JSON metadata |
ip_hash |
VARCHAR(64) | Privacy-safe hashed IP (daily salt) |
created_at |
TIMESTAMP | Event timestamp |
Privacy
IP addresses are never stored in plain text. The Tracker hashes them with a daily-rotating salt derived from the WordPress AUTH_SALT constant:
$ip_hash = hash( 'sha256', $ip . AUTH_SALT . gmdate( 'Y-m-d' ) );
This allows unique visitor counting within a single day without storing identifiable data.
Rate Limiting
Client-side tracking is rate-limited to 30 events per IP per form per minute. This prevents abuse and keeps the analytics table manageable:
$throttle = 'cf_track_' . md5( $ip . '_' . $form_id );
$count = (int) get_transient( $throttle );
if ( $count >= 30 ) {
wp_send_json_error( null, 429 );
}
set_transient( $throttle, $count + 1, MINUTE_IN_SECONDS );
REST API Endpoints
All endpoints require the edit_forms capability.
| Endpoint | Description |
|---|---|
GET /cf/v1/analytics/{id}/funnel |
Funnel metrics with derived rates |
GET /cf/v1/analytics/{id}/daily |
Daily event counts for charting |
GET /cf/v1/analytics/{id}/field-dropoff |
Field interaction analysis |
GET /cf/v1/analytics/{id}/attribution |
UTM and referrer data |
GET /cf/v1/analytics/{id}/spam-trends |
Daily spam counts |
GET /cf/v1/analytics/{id}/recommendations |
Auto-generated tips |
GET /cf/v1/analytics/overview |
Summary across all forms |
Overview Endpoint
The global overview returns a summary for up to 50 forms:
GET /wp-json/cf/v1/analytics/overview
[
{
"form_id": 123,
"title": "Contact Form",
"slug": "contact",
"views": 1500,
"submissions": 75,
"completion_rate": 42.5,
"spam_rate": 3.2
}
]