For developers

Reference

For developers

This page documents the extension points SmartDingo Form Tracker exposes to code: filters, actions,
the admin-ajax.php endpoints, the leads database table, the lead-endpoint security model, the
front-end config global, and the selector-scan mode. Everything here is verified against the plugin
source.

Note There is no REST API. The plugin does not register any register_rest_route /
rest_api_init routes. All server communication goes through classic admin-ajax.php actions
(listed below). Do not build integrations against a REST namespace — none exists.


Filter: sdft_validate_lead_submission (Starter)

The most useful hook. It runs inside the lead-logging endpoint just before a lead is de-duplicated
and written to the database, after all built-in security checks have already passed. Use it to add
your own gate — a CAPTCHA/Turnstile check, a WAF or fraud-API lookup, or verification of a hidden
token rendered by your specific form plugin.

Signature: apply_filters( 'sdft_validate_lead_submission', true, $data, $_POST )

  • $data — the sanitized, decoded lead payload (keys include tracking, contact, visitor_id,
    form_name, form_page, capture_method).
  • $_POST — the raw POST array from the submission.

Return true (or the unchanged value) to accept the lead. Return a WP_Error to reject it;
its message is sent back to the browser and nothing is stored.

add_filter( 'sdft_validate_lead_submission', function ( $valid, $data, $post ) {
    // Example: require a hidden token your own form plugin renders server-side.
    if ( empty( $post['my_form_token'] ) || ! my_verify_token( $post['my_form_token'] ) ) {
        return new WP_Error( 'sdft_rejected', 'Lead failed token verification.' );
    }

    return $valid; // Accept.
}, 10, 3 );

Note This filter only ever fires when lead tracking is licensed and enabled, so it is a
Starter/Pro concern. It is the intended place to compensate for the endpoint’s inherent limitation:
a browser-only tracker cannot cryptographically prove that a real form actually submitted.


Actions

ActionWhen it firesTypical use
sdft_fs_loadedOnce, right after the Freemius SDK is initialized in the main plugin fileSafely run code that calls sdft_fs() (e.g. read the current plan)
sdft_leads_cleanup (Starter)Daily WP-Cron event; deletes leads older than the configured retentionForce retention cleanup manually

sdft_leads_cleanup is scheduled with wp_schedule_event( …, 'daily', … ) on activation and runs
SDFT_Leads_DB::run_cleanup(), which deletes rows older than sdft_lead_retention_months (a value
of 0 means “never delete”, so cleanup is a no-op). You can trigger it by hand:

wp cron event run sdft_leads_cleanup

…or in PHP with do_action( 'sdft_leads_cleanup' );.


admin-ajax endpoints

All endpoints are classic admin-ajax.php actions. Two are public (they register both
wp_ajax_ and wp_ajax_nopriv_); the rest are admin-only and require the manage_options
capability plus a nonce.

ActionAccessPurpose
sdft_log_lead (Starter)PublicReceive and store a lead from the front-end tracker
sdft_lead_token (Starter)PublicIssue a fresh nonce + one-time token (cache-proof credentials)
sdft_search_pagesAdminSearch pages/posts by title (page scanner picker)
sdft_export_settings (Starter)AdminExport plugin settings as JSON
sdft_import_settings (Starter)AdminImport settings from an uploaded JSON file
sdft_export_leads_csv (Starter)AdminStream the leads CSV download
sdft_save_dash_prefs (Starter)AdminSave the current user’s dashboard widget preferences

Warning The two public endpoints are the only unauthenticated surface. They are hardened as
described under Lead endpoint security model — do not remove or
weaken those checks in a fork.


The wp_sdft_leads table

Leads are stored in {$wpdb->prefix}sdft_leads. The table denormalizes the most-queried attributes
into their own columns (so filtering, sorting, and dashboard aggregation stay fast) and keeps the
full captured payload in two JSON blobs.

ColumnTypeIndexedNotes
idBIGINT UNSIGNEDPKAuto-increment
visitor_idVARCHAR(64)Anonymous per-visitor id
lead_emailVARCHAR(255) 
lead_nameVARCHAR(255) 
lead_phoneVARCHAR(50) 
utm_sourceVARCHAR(255) 
utm_mediumVARCHAR(255) 
utm_campaignVARCHAR(255) 
first_utm_sourceVARCHAR(255)First-touch
first_utm_mediumVARCHAR(255)First-touch
first_utm_campaignVARCHAR(255)First-touch
referrer_categoryVARCHAR(50) 
landing_pageVARCHAR(255) 
device_typeVARCHAR(50) 
form_nameVARCHAR(255)Form config name
form_pageVARCHAR(255)Path the form was submitted from
tracking_dataLONGTEXTJSON blob — full tracking payload
contact_dataLONGTEXTJSON blob — full contact payload
created_atDATETIMEDefaults to CURRENT_TIMESTAMP

The dedicated columns are copies pulled out of the two JSON blobs at insert time. tracking_data
also records a capture_method key (ajax for supported AJAX forms, beacon-best-effort for
best-effort captures) so you can tell reliable captures from best-effort ones.

Note The JSON blobs are not indexed. If you need to query on a value that lives only inside a
blob, extract it in application code rather than adding LIKE scans over LONGTEXT.


Lead endpoint security model

sdft_log_lead is a public route, so it applies layered checks. A submission must clear all of
them, in this order, before the sdft_validate_lead_submission filter even runs:

  1. Noncesdft_log_lead_nonce must verify.
  2. Plan + toggle — lead tracking must be licensed and switched on.
  3. Per-IP rate limit — max 5 submissions per minute and 20 per hour (transients keyed on
    a hash of the remote address).
  4. Origin / Referer — accepted if the Origin or Referer host matches the site host. If
    both headers are present but neither matches, the request is rejected. If both are absent (privacy
    tools), it is allowed because the nonce and token already prove same-site origin.
  5. Honeypot — the hidden sdft_hp_field must be empty.
  6. One-time HMAC token — a base64(json).hmac_sha256 token signed with wp_salt('nonce'). The
    signature is checked with hash_equals, the embedded timestamp must be within a 5-minute (300s)
    window, and an atomic INSERT IGNORE lock plus a consumed-token transient ensure each token is
    used exactly once.
  7. Payload size — rejected above 32 KB; tracking keys are whitelisted and values truncated.
  8. Deduplication — a repeat from the same visitor_id + form_page (+ form_name) within
    30 seconds is skipped as a no-op.

The sdft_lead_token endpoint exists specifically for full-page caches: an inline token baked into
cached HTML would already be expired by the time a visitor submits. The tracker instead fetches a
fresh nonce + token from sdft_lead_token (which sends nocache_headers()) immediately before
posting, so capture works without any per-host cache rules.


Front-end config global: sdftConfig

The tracker script reads a single localized global, window.sdftConfig. It is only printed when at
least one tracking field is enabled. Keys include: trackingFields, formConfigs, storageType,
debugEnabled, visitedPagesLimit, consentMode (plus consentCookieName / consentCookieValue
in manual mode), plan, and — when lead tracking is active — leadTracking, ajaxUrl,
leadNonce, and leadToken.

Note Treat sdftConfig as read-only output. It reflects server-side, plan-filtered settings;
overwriting it in the browser will not unlock gated features (the server re-checks the plan on
every request).


Selector-scan mode: ?sdft_scan=1

Appending ?sdft_scan=1 to any front-end URL loads the scanner script instead of the tracker.
It walks the page’s forms and reports usable CSS selectors, which powers the “Scan page” button in
the admin. Scan mode is admin-only — it does nothing unless the current user has manage_options
— so it is safe to leave the pattern in place; visitors can’t trigger it.


Next steps

Stop guessing where your leads come from

You’ve spent the budget. You’ve run the campaigns. You deserve to know what actually worked. SmartDingo gives you complete, accurate, first-party attribution for every WordPress form submission. Start today on the forms you already use.

Works with your existing forms. Setup in minutes. No credit card required.

SmartDingo is a WordPress lead tracking plugin built for online marketers and WordPress developers who need accurate, cookieless attribution. It captures UTM parameters, traffic sources, landing pages, and full visitor journeys for every form submission, working seamlessly with Fluent Forms, Gravity Forms, Ninja Forms, WPForms, and other major WordPress form plugins. Whether you’re tracking leads from Google Ads, Meta, LinkedIn, or organic search, SmartDingo connects every lead to the marketing campaign that generated it.

Copyright 2026 SmartDingo