A contact form is often a website's most important business action. Tracking it helps you understand which pages and campaigns bring enquiries. The useful event is the enquiry that Drupal accepts, not every click on the Submit button.
This guide describes a reliable pattern for a Drupal form or Webform integration. It keeps validation failures out of the lead count, reduces duplicate events, and avoids sending contact details to Google Analytics 4.
Define what a successful enquiry means
Choose the point at which your application considers the submission complete. That might be a completed Webform submission saved successfully, or an accepted submission passed to a configured handler. A draft, a validation error, or a spam rejection should not count.
For an email-only form, be precise about the result: acceptance by the application's mail transport is not proof that the recipient received the email. Keep delivery monitoring separate from the lead event. Our Drupal contact-form email guide explains those checkpoints.
Write this definition into the implementation notes. Otherwise a future theme update might move tracking to a button listener and change the meaning of the report without anyone noticing.
Use the recommended generate_lead event
Google defines generate_lead for a lead such as a submitted enquiry. Use a stable event name and a small set of controlled parameters. You can distinguish the contact form from a quotation form without including anything a visitor typed.
The event call can look like this:
gtag('event', 'generate_lead', {form_id: 'contact', form_name: 'Contact enquiry'});
This is the final event call, not a complete Drupal integration. It belongs in JavaScript reached only after confirmed success, with the Google tag initialized and the site's consent controls applied. Adding it directly to a Submit click handler would count invalid attempts. Google's event implementation guide covers the tag API.
Leave monetary value unset unless your business has an agreed valuation method. If you send a value, follow Google's event specification for the associated currency. An arbitrary value makes later revenue comparisons misleading.
Connect Drupal's success path to the browser
- Handle completion on the server. Use the form's successful submit flow or an appropriate Webform handler. Check that this is a newly completed enquiry, not a draft save or an edit to an existing submission.
- Create a short-lived receipt. Store an opaque random identifier and timestamp in the submitting visitor's session. Keep contact fields out of this receipt.
- Expose the receipt once. On the confirmation response, pass a minimal success marker to a Drupal JavaScript behavior. For redirects, consume the session receipt on the next appropriate GET request.
- Send the event once per receipt. Deduplicate behavior attachment and browser-history restoration. Expire receipts and bound any browser-side list of already handled identifiers.
This pattern is an implementation recommendation. Adapt the handler to the form module and confirmation method in your project. An AJAX confirmation needs the same success signal and duplicate protection as a redirect-based confirmation.
Keep the marker out of shared page caches. A success marker cached for anonymous visitors could count another person's enquiry. Use Drupal's appropriate uncacheable or lazy-rendered session-specific output, and verify the actual response with caching enabled. Do not disable caching for the whole site to solve one small dynamic element.
Keep personal information out of Analytics
Send controlled values such as form_id, not names, email addresses, phone numbers, message bodies, or CRM identifiers. Also inspect page URLs and titles: a thank-you URL containing an email address can leak data through the ordinary page-view event even when the custom event is clean.
Google's guidance on avoiding personally identifiable information covers these indirect paths. Prefer a generic confirmation URL, avoid reflecting user input into titles, and inspect the request payload during testing. Apply the site's existing consent and privacy choices to lead tracking as well as page views.
Prevent overlapping tracking
Inventory your tag sources before adding code: a Drupal module, a theme snippet, and a Google Tag Manager container can all send events. Pick one owner for this particular lead event.
An automatically observed form interaction does not necessarily confirm Drupal's backend acceptance. Keep interaction events useful for funnel analysis, but do not treat all of them as successful leads. Avoid marking both a generic form submission event and your confirmed-success event as the same business outcome without understanding the resulting counts.
Test the failure cases as carefully as success
- One valid completed enquiry produces one lead event.
- Missing required fields, spam rejection, and draft saves produce none.
- Refreshing the confirmation, using Back and Forward, and reattaching AJAX behaviors do not repeat the same receipt.
- A second genuine enquiry can produce its own event.
- Preview, staging, and internal testing follow the intended analytics exclusions.
- Consent choices and blocked analytics scripts do not break the contact form.
Inspect the browser request and verify the event in GA4 DebugView or Realtime using a controlled test. Once confirmed, mark generate_lead as a key event if it represents an important business outcome. Review acquisition and landing-page reports after normal reporting has processed the data.
Expect analytics totals to differ from your submission records because of consent choices, blockers, and delivery interruptions. Keep Drupal or your CRM as the operational record of enquiries. Contact Druproid Support for help connecting successful form submissions to useful, privacy-conscious measurement.