Lead generation forms - custom validation to improve lead quality

Created by Todd Belcher, Modified on Sat, 26 Oct at 2:34 PM by Todd Belcher

Lead gen forms should not accept leads that look like this:

First: asdasd, Last: asdasd


It's why we have previously written this article on custom form validation for Instapage. But what about other forms? We've also put together a script that will allow you to enhance validation on any form.


The example custom JavaScript below can be added by a technical marketer or ZappyPeople, customized to suit your needs.



The script below, unedited, would automatically find the first and last name fields (assuming they have the ID user_first_name and user_last_name), as well as any email or phone inputs, and any inputs with a class of "postal" in the HTML.


Required fields will be checked with custom validation as part of spam reduction in your lead forms.




// Field override selectors (set these to the desired selectors)
var fieldSelectors = {
  firstName: '#user_first_name',
  lastName: '#user_last_name',
  email: '[type="email"]',
  phone: '[type="tel"]',
  zip: 'input.postal'
};

// Selector for the submit button
var submitButtonSelector = 'button[type="submit"]';

// List of patterns for detecting junk email addresses -- log into support site for full version
var junkEmailPatterns = [
  /\d{2,}/, /temp/, /dispos/, /trash/, /fake/, /spam/, /mailinator/
];

// List of fake strings commonly used in spam
var fakeStrings = ['dgf', 'sdf', 'jhk', 'hjk', 'asd', 'asdf'];

// HTML for the validation modal
var modalHtml = `
  <div id="validationModal" class="modal">
    <div class="modal-content">
      <span class="close">×</span>
      <p id="modalMessage"></p>
    </div>
  </div>
`;
document.body.insertAdjacentHTML('beforeend', modalHtml);

// CSS for the validation modal
var modalCss = `
  .modal {
    display: none; 
    position: absolute; 
    background-color: rgba(0,0,0,0.4); 
    z-index: 9999; /* Adjust this value as needed */
  }
  .modal-content {
    background-color: #fff;
    padding: 20px;
    border: 1px solid #ccc;
    width: 100%;
    box-sizing: border-box;
    position: relative; 
  }
  .close {
    position: absolute;
    top: 1px;
    right: 10px;
    color: #aaa;
    font-size: 28px;
    font-weight: bold;
    cursor: pointer;
  }
  .close:hover,
  .close:focus {
    color: black;
    text-decoration: none;
  }
`;
var style = document.createElement('style');
style.type = 'text/css';
style.appendChild(document.createTextNode(modalCss));
document.head.appendChild(style);

// Convert email inputs to lowercase
document.querySelectorAll(fieldSelectors.email).forEach(function(input) {
  input.addEventListener("input", function(e) {
    e.target.value = e.target.value.toLowerCase();
  });
});

// Email validation function
function isValidEmail(email) {
  const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  const isValidFormat = emailPattern.test(email);
  const domain = email.split('@')[1];
  const domainParts = domain.split('.');
  const isSingleCharacterDomain = domainParts.some(part => part.length === 1);
  const matchesJunkPattern = junkEmailPatterns.some(pattern => pattern.test(email));
  const hasFakeStringsTwice = fakeStrings.filter(str => email.includes(str)).length > 1;
  const hasEnoughUniqueChars = new Set(email).size >= 6;
  const hasFiveVowelsInRow = /[aeiou]{5}/i.test(email);

  const front = email.split('@')[0];
  const hasNoVowelsInFront = front.length >= 6 && !/[aeiou]/i.test(front);

  return isValidFormat && 
         !isSingleCharacterDomain && 
         !matchesJunkPattern && 
         !hasFakeStringsTwice && 
         hasEnoughUniqueChars && 
         !hasFiveVowelsInRow && 
         !hasNoVowelsInFront;
}

// Phone number validation function
function isValidPhoneNumber(phoneNumber) {
  const pattern = /^(?:(?:\+?1\s*(?:[.\-\s]*)?)?(?!(?:.*555[\-\s]*555[\-\s]*5555|.*123[\-\s]*456[\-\s]*7890|.*012[\-\s]*345[\-\s]*6789))\(?([2-9][0-9]{2})\)?[\s.\-]*([2-9][0-9]{2})[\s.\-]*([0-9]{4}))$/;
  const cleanedPhoneNumber = phoneNumber.replace(/[^\d+]/g, '');
  return pattern.test(cleanedPhoneNumber);
}

// Zip code validation function
function isValidZipCode(zip) {
  const usZipPattern = /^\d{5}$/;
  const caZipPattern = /^[A-Za-z]\d[A-Za-z]\d[A-Za-z]\d$/;
  
  if (zip.length === 5) {
    return usZipPattern.test(zip);
  } else if (zip.length === 6) {
    return caZipPattern.test(zip);
  }
  return false;
}

// Name validation function
function isValidName(firstName, lastName) {
  const fullName = firstName + lastName;
  const hasThreeUniqueChars = new Set(fullName).size >= 3;
  const fiveConsonantsPattern = /[^aeiou]{5}/i;
  const threeSameLetterPattern = /(.)\1\1/;
  const hasConsecutiveConsonants = fiveConsonantsPattern.test(firstName) || fiveConsonantsPattern.test(lastName);
  const hasSameLetterInRow = threeSameLetterPattern.test(firstName) || threeSameLetterPattern.test(lastName);
  const hasFakeStrings = fakeStrings.some(str => firstName.includes(str) || lastName.includes(str));
  const hasTestInBoth = firstName.toLowerCase().includes('test') && lastName.toLowerCase().includes('test');

  return hasThreeUniqueChars && !hasConsecutiveConsonants && !hasSameLetterInRow && !hasFakeStrings && !hasTestInBoth;
}

// Validation functions for different field types
var validationFunctions = {
  email: function(input) {
    var email = input.value;
    var isValidEmailAddress = email.length >= 8 && isValidEmail(email);
    return {
      isValid: isValidEmailAddress,
      message: 'Please enter a valid email address.',
    };
  },
  phone: function(input) {
    var phone = input.value;
    var isValidPhone = isValidPhoneNumber(phone);
    return {
      isValid: isValidPhone,
      message: 'Please enter a valid phone number.',
    };
  },
  zip: function(input) {
    var zip = input.value;
    var isValidZip = isValidZipCode(zip);
    return {
      isValid: isValidZip,
      message: 'Please enter a 5-digit US or 6-character CA postal code.',
    };
  },
  name: function(input) {
    var firstName = document.querySelector(fieldSelectors.firstName).value;
    var lastName = document.querySelector(fieldSelectors.lastName).value;
    var isValid = isValidName(firstName, lastName);
    return {
      isValid: isValid,
      message: 'Please enter a valid name.',
    };
  }
};

// Validate fields when form button is clicked
document.querySelectorAll(submitButtonSelector).forEach(function(button) {
  button.addEventListener('click', function(event) {
    var form = button.closest('form');
    var allValid = true;
    var messages = new Set();
    var lastInvalidField = null;

    // Check if all targeted inputs are empty
    var allInputsEmpty = Object.keys(fieldSelectors).every(function(key) {
      var input = form.querySelector(fieldSelectors[key]);
      return input && input.value.trim() === '';
    });

    if (allInputsEmpty) {
      return; // Do not run the script if all inputs are empty
    }

    Object.keys(validationFunctions).forEach(function(validationType) {
      var input = form.querySelector(fieldSelectors[validationType]);
      if (input) {
        var result = validationFunctions[validationType](input);
        if (!result.isValid) {
          allValid = false;
          messages.add(result.message);
          lastInvalidField = input;
        }
      }
    });

    if (!allValid && lastInvalidField) {
      event.preventDefault();
      var formRect = form.getBoundingClientRect();
      var buttonRect = button.getBoundingClientRect();
      showModal(Array.from(messages).join('\n'), formRect.width, buttonRect.top - formRect.top - 10);
    }
  });
});

var modal = document.getElementById("validationModal");
var span = document.getElementsByClassName("close")[0];

// Show validation modal with error messages
function showModal(message, formWidth, buttonTop) {
  document.getElementById("modalMessage").innerText = message;
  var modalContent = modal.querySelector('.modal-content');
  modalContent.style.width = formWidth + 'px';
  modal.style.top = buttonTop + 'px';
  modal.style.left = '50%';
  modal.style.transform = 'translateX(-50%)';
  modal.style.display = 'block';
}

// Close the modal when the close button is clicked
span.onclick = function() {
  modal.style.display = "none";
}

// Close the modal when clicking outside of it
window.onclick = function(event) {
  if (event.target == modal) {
    modal.style.display = "none";
  }
}

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article