Form-funnel drop-off analytics

Lead tracking tells you who converted. Form-funnel analytics tells you who started, who dropped off, and on which field. Beaconry records three signals per form (form_start, form_abandon, lead submit), aggregates them into a per-form drop-off table, and keeps the behavioural signals strictly analytics-only so they never leak to an ad platform.

Reading time: ~6 minLast updated: 2026-06-08

The problem it solves

A lead conversion is a single number: someone submitted. It cannot tell you that forty percent of the people who started your quote form gave up at the phone field, or that your three-step application form bleeds visitors at step two. That insight lives in the gap between "started typing" and "submitted", and the only way to see it on GA4 normally is to instrument form_start events yourself, define a funnel exploration by hand, name each step, and keep that funnel in sync every time you edit the form.

Form-funnel analytics does that part for you. You flip one toggle, and Beaconry maintains a per-form table of starts, leads, abandons, a conversion rate and the fields people abandon on, computed from data it already sees passing through the pipeline. No GA4 exploration to build, no event schema to design, no funnel definition to maintain.

The three signals

Each form is summarised from three independent events, all keyed to the same form so they line up into one funnel row.

  • form_start, fired by the browser engine on the first focus into a form input. One start per form per visit, recorded as a counter.
  • form_abandon, fired by the browser engine on page-leave (pagehide / visibilitychange) when a form was started, has at least one filled field, and was not submitted. It carries only the NAME of the last-touched field plus filled-and-total counts. Never a field value.
  • lead submit, fired server-side when the form is actually submitted, the same lead event the rest of Beaconry already sends. It is keyed on the form's stable key so it counts as the "converted" leg of the same funnel.

Starts, abandons and submits are stored as per-form, per-day buckets in a single non-autoloaded option, pruned on write with a 90-day daily-cron cleanup behind it. There is no extra database table and no per-event row, the funnel store is a small rolling aggregate.

Lining the three signals up onto one form

For the funnel to read correctly, all three events have to agree on which form they belong to. Beaconry does that with a stable composite form key.

The browser engine derives a key from the form in the page and the server derives the same key from the submission. For Fluent Forms and Kadence Advanced Form the two match exactly (fluent_<id> / kadence_adv_<post_id> on both sides), so those two plugins get the full picture: starts, abandons and leads all collapse onto one row. For the other form plugins the browser start and abandon land under the form's DOM id while the lead submit lands under the server key, so you still get a complete lead count for every plugin, and the start/abandon drop-off detail is fullest on Fluent and Kadence Advanced where the keys align.

This is why the abandon-detail half of the feature is at its best on Fluent and Kadence Advanced. It is a consequence of those plugins exposing an id the browser can read before submit, not a tiering decision.

The per-form drop-off table

The Forms tab renders a table built from a 30-day snapshot of the store. Forms with zero activity in the window are omitted, and rows are ordered by volume (starts plus submits) so your busiest forms sit at the top. Each row carries:

ColumnMeaning
FormThe form's human label (falls back to its stable key if no label is known yet).
StartsHow many visitors focused into the form in the window.
LeadsHow many actually submitted (the same lead events your channels received).
AbandonsHow many started, filled at least one field, then left without submitting.
Conversion rateLeads divided by the funnel base, as a whole-number percent. The base is starts when starts were recorded, otherwise leads plus abandons (so a form whose start signal never aligned still gets a meaningful rate).
Top drop-off fieldsThe field names where abandons concentrated, highest first, capped at the top three. Names only, no values.

The "top drop-off fields" column is the actionable part. If a quote form shows most of its abandons on phone, that field is your friction. Make it optional, move it later, or explain why you need it, then watch the column the next week. The table also exposes an abandon rate (abandons over starts) and a "Clear list" control to reset the store when you want a clean baseline after a redesign.

Analytics-only by construction

This is the part that matters for clean ad reporting. form_start and form_abandon are behavioural signals, not conversions, and Beaconry guarantees by code that they never reach an ad vendor. Two independent gates enforce it.

  1. The opt-in gate runs first, inside the funnel observer. It always records the event into the in-plugin store, and then for form_abandon it cancels the dispatch outright unless you have explicitly turned on forwarding abandons to GA4. So by default an abandon only ever touches Beaconry's own funnel store and goes nowhere on the wire.
  2. The central routing gate runs in the dispatcher, right after the pre-dispatch filters. It matches the event name against a single analytics-only list and, on a match, routes the event to GA4 only and hard-stops before any ad-vendor channel. One check covers Meta, TikTok, LinkedIn, Google Ads, Microsoft Ads, Pinterest, X Ads, Snapchat and Reddit at once, and any ad channel added in future inherits the rule automatically with no per-channel exception to remember.

The net effect, in every toggle combination:

  • An abandon reaches GA4 only, and only when you have switched on GA4 forwarding for the funnel. Otherwise it stays entirely in the plugin store.
  • An abandon reaches an ad channel never.
  • A form_start reaches GA4 only (if GA4 is connected), never an ad channel.

That second gate is the single source of truth for the "internal signal versus ad-vendor conversion" split. It exists because relying on per-channel skip lists alone is fragile: add a channel, forget the skip entry, and a behavioural event quietly starts inflating that channel's conversion count. The central gate makes that class of regression impossible.

What is and is not forwarded to GA4

Even when you do opt in to GA4 forwarding, what travels is deliberately thin. form_abandon carries the last-touched field NAME and the filled-and-total counts. There is no field value, no email, no phone, nothing a visitor typed. The whole feature is PII-safe by construction (field names and counts only), which is why it needs no special GDPR handling, the funnel store can never contain personal data because the events that feed it never carry any.

Commerce checkouts are excluded on purpose

WooCommerce (classic and block), Easy Digital Downloads and SureCart checkouts are explicitly kept out of the form funnel. They are not lead forms, and they already have their own view, begin_checkout, purchase funnel. Worse, their order submit is invisible to a form funnel (Store-API or AJAX, with no native form submit the browser can see), so a completed purchase would look like an abandon and mis-fire one on every successful order.

Two layers keep them out:

  • A render-agnostic exclude flag, set from the platform APIs themselves (is_checkout(), is_cart(), edd_is_checkout()). This switches the whole funnel off on a commerce checkout or cart page, including markup like EDD's own block checkout that a CSS selector could not reliably match.
  • A CSS-class backstop in the browser engine that recognises the WooCommerce, EDD and SureCart checkout and cart component classes, in case the page-level signal was missed.

Checkout-step abandonment is still measurable, it is just the commerce funnel's job: a begin_checkout without a matching purchase. See Server-side tracking for the commerce funnel.

How to enable

wp-admin, Beaconry, Forms tab, Form-Funnel card. Two toggles:

  1. Enable form-funnel analytics turns on the start and abandon recording in the browser engine and starts filling the per-form table. This is all you need for the drop-off table. The signals stay in the plugin store. Default is off.
  2. Forward abandons to GA4 additionally lets form_abandon through to GA4 (and only GA4, see above) so you can build your own GA4 explorations on top. Leave it off and abandons never leave the plugin. Default is off.

The Forms tab only appears in the Beaconry menu when at least one supported form plugin is active, and the funnel card lives there alongside the per-form field-mapping covered in Forms setup. Turning the feature on requires nothing in the form markup itself.

Versus a hand-built GA4 funnel

You can build a comparable funnel in GA4 directly, and if you already have a GA4 funnel exploration you like, keep it. The difference is in the operating cost and the guarantees.

Hand-built GA4 funnelBeaconry form-funnel
SetupInstrument form_start yourself, define a funnel exploration, name and order each step.One toggle. The table builds itself from data already in the pipeline.
Drop-off fieldNot available unless you also send a custom per-field event and chart it.Built in: the top drop-off field names per form, no extra events.
MaintenanceRe-check the funnel definition whenever you edit the form.The form key tracks the form, so the row follows it across edits.
Where it livesIn GA4, behind the usual reporting latency.In wp-admin, on the Forms tab, next to the form settings.
Ad-channel safetyYour responsibility to keep behavioural events out of conversion imports.Guaranteed by the central gate: starts and abandons never reach an ad channel.

They are not mutually exclusive. The "Forward abandons to GA4" toggle exists precisely so you can have both: the quick built-in table for day-to-day, and the raw form_abandon stream in GA4 for a custom exploration, with the ad channels still protected from the behavioural noise either way.

Troubleshooting

  • "A form shows leads but zero starts or abandons": that form's plugin does not expose an id the browser can read before submit, so its start and abandon land under a different key than its server-side lead. Lead counts are still accurate. The full start-to-abandon detail is fullest on Fluent Forms and Kadence Advanced Form, where the browser and server keys match.
  • "Abandons are not reaching GA4": enabling the funnel alone keeps abandons in the plugin store. You also need the second toggle, "Forward abandons to GA4". This is by design, the table works without sending anything to GA4.
  • "I see a form_abandon in GA4 but not in Meta or Google Ads": that is correct and not a bug. Behavioural signals are analytics-only and hard-stopped before every ad channel. There is no setting that forwards them to an ad vendor.
  • "A completed checkout looked like an abandon": it should not, commerce checkout and cart pages are excluded from the funnel at both the page-API level and the CSS-class level. If you renamed pages or use a non-standard checkout, confirm the page resolves through the platform API (is_checkout() and friends), which is how the exclude is detected, never by URL slug.
  • "The table is empty right after enabling": it fills as visitors interact. Starts and abandons need real form focus and page-leave to occur, and admins are excluded from front-end tracking by default, so test as a logged-out visitor.