Conversion tracking for a Webflow form

The client's problem

Fix GA4 + Google Ads tracking on our Webflow site.
We can't measure enquiries.
Our tracking is broken and I want it fixed properly.

What's there now

  • Webflow site
  • GA4 installed directly on the page, no Google Tag Manager
  • a native Webflow enquiry form
  • no conversion event for enquiries at all

What I need:

  • Set up Google Tag Manager, move GA4 and Google Ads into it
  • Create a generate_lead event when someone submits the enquiry form
  • Make that the primary conversion in Google Ads, demote form_submit to secondary

In your reply, tell me

How would you detect a successful submission on a native Webflow form? Be specific.

My solution

1

Native Webflow forms are submitted asynchronously via jQuery → ajaxComplete will notify a handler of the submission.

2

Of all the §1 notifications, the handler must process only those that correspond to the submission of a native Webflow form; the handler can identify them via its 3rd argument — ajaxOptions:

ajaxOptions.url?.includes('/api/v1/form/')

The specification of ajaxOptions is identical to the specification of settings for jQuery.ajax (because they are the same object).

3

The form could have been submitted by a spammer or contained errors that the client-side validation missed → the handler must verify that the form has passed Webflow's server-side validation.

The handler can do this via its 2nd argument — jqXHR.

jqXHR «is a superset of the browser's native XMLHttpRequest object» → it has the status property.

The check:

200 === jqXHR.status

4

Other forms might be present on the website → the handler must determine whether the submitted form is «the enquiry form».

4.1. The handler can do this via the form's name set in the Webflow Designer.

4.2. By default, Webflow assigns the name «Email Form» to all new forms → it is necessary to assign a unique name to «the enquiry form».

4.3. The handler can retrieve the form's name via its 3rd argument — ajaxOptions (as in §2).

4.4. The data property of ajaxOptions contains all the form data in the application/x-www-form-urlencoded format.

4.5. The code to identify the form by its name:

new URLSearchParams(ajaxOptions.data).getAll('name').includes('<Form Name>')

4.6. Webflow allows naming a form field namenew URLSearchParams(ajaxOptions.data) could contain multiple parameters named name → it is correct to use the syntax above instead of the naive check '<Form Name>' === new URLSearchParams(ajaxOptions.data).get('name').

5

The handler can push the corresponding custom event to the Google Tag Manager dataLayer in the standard way (without any Webflow specifics):

window.dataLayer = window.dataLayer || [];
window.dataLayer.push({'event': 'generate_lead'});