What a form event confirms
To check that an enquiry was accepted, find the receiving system’s acceptance record for that submission. Match it to the response the browser received. Keep email delivery, lead qualification and a sale as separate checks.
In GA4 enhanced measurement, form_start records the first interaction with a form in a session. form_submit records a form submission. These events help describe form use; their definitions do not require your server to save the enquiry. Check how your particular form and tags behave, especially if JavaScript handles submission. See Google’s enhanced measurement definitions.
| Observation | What you can conclude |
|---|---|
| Click, form event or a success message | The interface or tag reached that point. Acceptance needs a separate check. |
| A saved server record with an acceptance ID | The receiving system accepted this submission under its documented rule. |
| The mail provider accepted a send request | The provider accepted that request. Receipt by the intended mailbox is still a separate fact. |
| The recipient finds the matching message | Receipt is confirmed for that message. Lead quality still needs review. |
| A person records qualification or a completed deal | That later business outcome is known to the extent supported by its own record. |
Define “accepted” with the form owner before counting. In this guide it means the receiving application validated the submission and created one record. Another system may accept only after queuing work or handing it to a provider. Record that rule explicitly. HTTP 200 by itself says too little about the application’s result.
Trace one submission
Use an authorized test environment and fictional inputs. Agree how test records are excluded from business totals. The downloadable example below already provides an isolated test; it does not send an enquiry to Extcorp.
- Record the context. Note the page, form, environment, time and time zone. For GA4, also note the property, web stream and tag configuration being checked.
- Find the acceptance rule. Ask the application owner where the record is written, which response confirms it and which ID links the response to the record. An animated success message is insufficient evidence.
- Inspect a rejected attempt. Verify both the response and the absence of a new acceptance record in the authorized test store. Check an application error even when its HTTP status is 200.
- Inspect an accepted attempt. Read the response body and find its matching record. Record the acceptance time and ID in the restricted test log. Keep contact details out of analytics and shared screenshots.
- Repeat the same logical submission. Reuse its retry key and check that the server returns the existing acceptance ID. Test a lost response as well: the browser may report a network error after the server has saved the enquiry.
- Check subsequent outcomes separately. If you did not inspect the mail provider, recipient mailbox or qualification record, write
UNKNOWN. An unknown outcome contributes neither a confirmed success nor a confirmed failure.
A network error leaves acceptance uncertain until you reconcile it with the receiving system. Avoid creating a new retry key merely because the response was lost; that can turn a retry into another record.
Run the filled example
This teaching example uses six requests to a temporary loopback server on your computer. Its keys and IDs are fictional. It keeps records in memory, uses no contact fields and exits after checking the results. It makes no external requests, loads no GA4 tag and sends no email.
Download the Node.js example, then run it with Node.js 22 or later:
node ga4-enquiry-demo.mjs
The file creates its own free loopback port. All six requests and the final counts print as JSON. A failed assertion stops the run; checks: "PASS" confirms the expected fixture results. A machine policy that blocks loopback connections prevents the test from passing. Run it only where local connections are permitted.
| Attempt | Browser observation | Server record |
|---|---|---|
| 1. Validation fails | HTTP 422, accepted: false | No record created |
| 2. Application rejects | HTTP 200, accepted: false | No record created |
| 3. Accept demo-A | HTTP 201, accepted: true, demo-001 | demo-001 created |
| 4. Retry demo-A | HTTP 200, demo-001, duplicate: true | Existing demo-001 returned |
| 5. Accept demo-B; lose response | Network error; acceptance UNKNOWN | demo-002 created before the connection closed |
| 6. Retry demo-B | HTTP 200, demo-002, duplicate: true | Existing demo-002 returned |
The final server inspection explains attempt 5. A browser-only observer could not know at that moment whether the enquiry had been saved. Attempt 6 recovers the same ID.
6 attempts → 3 positive browser responses → 2 unique accepted records. The local analytics simulation contains 2 generate_lead entries. Actual GA4 events are NOT_SENT. Provider acceptance, recipient delivery, qualification and sale are all UNKNOWN.
The simulation adds a local entry the first time the browser sees each accepted ID, including the recovered response in attempt 6. It sends only a fictional form_id to that local array. The retry key and receipt ID stay inside the demo. The six attempts are a fixture count, not a prediction of how many form_submit events GA4 would collect.
The example demonstrates the distinction, not a production backend. Its memory is cleared on exit. A real implementation needs durable storage, an atomic uniqueness rule, a retry-key lifetime and a policy for changed payloads. Reloading a page must not reset the server’s duplicate protection.
Count accepted enquiries without retries
For the defined period and environment, count distinct acceptance IDs in the authoritative acceptance store. Exclude test records and apply the documented acceptance rule. Use the time the record was first accepted; a later retry does not move it to a new period.
In the example, the set is {demo-001, demo-002}, so the count is 2. Adding three positive responses would count demo-001 twice. Counting six attempts would also include both rejected attempts and the response that was lost.
This removes transport retries under the same key. It does not identify a person who sends the same commercial request with a new key or from another device. Keep a separate reviewed duplicate classification for that situation. The acceptance count is also separate from the count of qualified leads.
When comparing with GA4, align the reporting period, time zone, form, environment and event definition. Do not divide the two totals into a conversion rate until their populations and coverage are understood. Missing analytics events can reflect consent, blockers, configuration or processing; missing server evidence remains unknown rather than zero.
Check GA4 after the acceptance step
Google recommends generate_lead for a submitted form or request for information. It requires deliberate setup; adding an enhanced-measurement form event does not configure it. For this diagnostic, define its trigger as a confirmed accepted response and document that local choice. Google does not make generate_lead a server receipt. See the recommended event reference.
Have the measurement owner check the following in an authorized test setup:
- Enable debug mode for the test device and inspect Admin → Data display → DebugView. Match the event name, parameters and timing to the application result. A request in the browser’s Network panel alone does not prove that it reached the intended GA4 property.
- Verify that validation failure and application rejection do not fire the acceptance event. Verify that repeating a confirmed response does not add another event for the same logical submission. Check whether automatic and custom tags both track the same action.
- Send only approved non-personal parameters, such as a fixed form label. Inspect URLs and automatically collected parameters too. Names, email addresses, phone numbers, enquiry text and CRM content must stay out of analytics. Keep the correlation ID in the restricted application log for this procedure; the example does not transmit it to GA4.
- If the event represents an important business action, an authorized editor can mark it as a key event. Its counting method still needs review. Once per event can count repeated firing; once per session can combine distinct enquiries in one session. Neither setting replaces deduplication in the acceptance store.
DebugView checks event collection for a device, not mail delivery or lead quality. Google’s guidance notes that privacy controls or lack of Analytics consent may keep events out of DebugView. Collection and report processing can also delay or limit comparisons. Never promise complete collection. Remove the debug_mode parameter to disable it; setting it to false does not disable debug mode.
Sources checked 13 October 2026: DebugView, marking key events, key-event counting and avoiding personally identifiable information. Account-specific settings and permissions must be checked in the actual property.
Choose the next check
If GA4 shows an event and no acceptance record is available, inspect the application’s validation and save step. If a record exists but the event is absent, investigate collection and consent. If acceptance is confirmed but the email is missing, follow the mail provider and recipient evidence. Each branch needs a different source.
Qualification needs its own agreed criteria and review. A sale needs its own transaction or deal record. Google also defines separate qualify_lead and close_convert_lead events; their availability does not mean those business outcomes have occurred or are being tracked on your site.
For a question about traffic, use the existing GA4 traffic service. You can send a short question about GA4 traffic; website and report details can follow. Changes to tagging, form handling or integrations require a separately agreed scope. For the difference between first-party data and external estimates, see the traffic-platform comparison.