A visitor spends five minutes explaining their project, clicks Submit, and sees:
“Something went wrong.”
Their message disappears. They cannot tell whether the enquiry was received. Clicking again might help—or create a duplicate.
A failed contact form is more than an error message. It is a situation your application needs to resolve clearly.
The starting point is understanding what actually failed.
1. Separate rejection from an unknown outcome
Not every unsuccessful browser request means the enquiry was lost.
Consider these scenarios:
| Scenario | What the application knows | Appropriate response |
|---|---|---|
| Required information is missing | The form is incomplete | Show field-level guidance |
| Backend explicitly rejects a field | Submission was not accepted | Explain what needs correction |
| Service is temporarily unavailable before acceptance | Submission was not accepted | Preserve inputs and offer a retry |
| Request times out | Outcome may be unknown | Explain that receipt could not be confirmed |
| Enquiry is saved, but CRM delivery fails | Website accepted the enquiry | Show acceptance and handle CRM delivery internally |
That last distinction matters.
If the website has safely stored an enquiry, a downstream CRM error should not automatically tell the visitor that their submission failed.
However, showing success is only appropriate when the application has actually accepted responsibility for retaining and processing the enquiry.
2. Preserve the visitor’s work
Do not clear form fields when the request starts.
Clear them only after confirmed acceptance, or leave the submitted content visible alongside the confirmation.
When validation or delivery fails:
- Keep the entered message.
- Keep valid field values.
- Re-enable the submit control when another attempt is appropriate.
- Show errors near the relevant fields.
- Give the visitor a clear next action.
For many forms, preserving values in the current page is enough.
Persisting enquiry text into browser storage requires a separate decision. Messages can contain private business or personal information, especially on shared devices.
Preserving input does not have to mean storing it indefinitely.
3. Make error messages match the evidence
“Please try again” is useful only when another attempt is appropriate.
For a rejected email address:
Enter a valid email address so we can reply to your enquiry.
For a confirmed temporary rejection:
We couldn’t accept your enquiry right now. Your message is still here. Please try again shortly.
For an unknown outcome:
We couldn’t confirm whether your enquiry was received. Your message is still here.
If the system supports safe retries, that last message can include a retry action.
Avoid saying “Your enquiry was not sent” when the browser merely timed out. The backend may have saved it before the connection failed.
Also avoid displaying raw exceptions, database errors, or internal service details to visitors.
4. Make retries safe
Disabling the submit button while a request is running helps prevent rapid double-clicks.
It does not solve every duplicate scenario.
A visitor might retry after a timeout, refresh the page, or submit from another tab.
For retryable submissions, use an idempotency mechanism on the server.
A typical design works like this:
- The client creates a submission identifier for one logical enquiry.
- The server associates that identifier with the processing result.
- A retry of the same enquiry reuses the identifier.
- The server returns the existing result instead of creating another record.
This requires an atomic backend implementation. Two simultaneous requests must not both pass a separate “does this exist?” check and create duplicates.
Define what happens if the same identifier arrives with different form contents. Rejecting the mismatch is generally clearer than silently treating changed content as the original request.
The identifier should represent one submission, rather than becoming a permanent identifier for every enquiry from that visitor.
5. Separate enquiry acceptance from CRM delivery
A direct integration can make form reliability depend on the CRM being available at that exact moment.
An alternative is to accept the enquiry into durable storage and process CRM delivery separately.
That design needs more than a background function:
- A durable record of the accepted enquiry.
- A reliable way to identify pending deliveries.
- Controlled retries for temporary failures.
- Duplicate protection during repeated delivery.
- Visibility into records that still need attention.
For example, an application can save the enquiry and its pending delivery record in the same database transaction.
A worker can then deliver pending records to the CRM.
This avoids a gap where the enquiry is saved but the application crashes before recording that delivery is still required.
If your application cannot durably retain the enquiry, it should not claim acceptance merely because background processing was started.
6. Track the failure stage
A single event called form_error offers limited diagnostic value.
Use a small set of controlled categories:
| Category | Meaning |
|---|---|
validation_rejected | Submitted fields were rejected |
request_failed | Browser request could not complete |
acceptance_unknown | Browser could not establish the outcome |
crm_delivery_failed | Accepted enquiry could not reach the CRM |
The final category belongs in backend monitoring when CRM delivery happens server-side.
Do not put the visitor’s message, email address, or phone number into general analytics events.
Keep detailed operational records access-controlled, and use an opaque reference when support staff need to trace an issue.
Also keep success tracking separate: a failed attempt should not generate the same acquisition event as an accepted enquiry.
7. Test the recovery experience
Testing only the successful submission leaves important behavior unverified.
Try these cases in a test environment:
| Test | What to check |
|---|---|
| Invalid field | Guidance appears and other inputs remain |
| Backend rejection | No success message or success event fires |
| Slow response | Repeated clicks do not create concurrent requests |
| Response lost after saving | Retrying the same submission does not duplicate it |
| CRM unavailable | Accepted enquiries remain available for later delivery |
| Keyboard-only navigation | Errors and recovery controls are usable |
| Screen reader use | Status changes are announced appropriately |
For an unknown outcome, inspect the backend record as well as the browser.
The visitor-facing message and the actual processing state should tell a consistent story.
A useful failure state provides a way forward
When a contact form fails, visitors need three things:
- Their work preserved.
- An honest explanation of what is known.
- A safe next action.
Developers need enough operational visibility to find where processing stopped.
Designing those behaviors alongside the successful submission makes the form easier to trust—and much easier to support.
