A visitor submits an enquiry. The browser times out, so they submit it again. Two records reach the sales team, two representatives make contact, and one person receives the same introduction twice.

Duplicate prevention starts by separating two questions: is this the same submission, and is this the same contact?

Model contacts and enquiries separately

A contact represents a person or business identity. An enquiry represents a specific request. One contact can legitimately send several enquiries about different projects.

If someone returns next month with a new requirement, attaching a new enquiry to an existing contact usually preserves more useful history than silently discarding the request.

Consider a hypothetical software agency. A contact asks about a CRM in January and a mobile app in March. Matching the email can help locate the contact. It does not prove the March enquiry is a duplicate.

Give each submission an identity

Create a stable identifier for each logical submission. Retries of unchanged content reuse that identifier. A genuinely new enquiry receives a new one.

Enforce uniqueness atomically in the backend. A separate lookup followed by an insert can race when two requests arrive together. A database constraint or an equivalent atomic operation should enforce the boundary.

Associate the identifier with the request fingerprint and outcome. Define how changed content under an existing identifier is rejected. Do not let one caller retrieve another caller's result merely by guessing an identifier.

Match people conservatively

Use a documented contact-matching rule. An authenticated account identifier is stronger evidence than a similar name. Email and phone matches require care: shared inboxes and shared telephone numbers exist.

Ambiguous matches belong in review rather than an automatic merge. Merging records can move private notes and ownership between people, so it deserves a higher confidence threshold than suggesting a possible duplicate.

Keep downstream delivery safe

A worker can retry after the CRM accepted a record but before the response reached your application. Store a stable external enquiry reference in the CRM when supported. Use the provider's documented idempotency mechanism where available.

If neither capability exists, document the remaining ambiguity and reconcile uncertain deliveries. A local flag alone cannot guarantee exactly one remote record after a network failure.

Verify these scenarios

Scenario Expected behavior
Same submission retried Existing outcome returned
Same contact, new requirement New enquiry linked to contact
Two requests arrive together Unique submission boundary holds
Similar names, different emails No automatic merge
CRM response is lost Delivery is reconciled before blind replay

Measure duplicate submissions and suspected duplicate contacts separately. They describe different problems and require different fixes.