How to stop bot spam in your AI Chatbot

Tired of bots spamming your AI Chatbot and wasting your message limit? While the widget doesn’t have a built-in feature for this, our devs came up with a simple and effective solution — adding a Honeypot to filter out bot submissions :honey_pot:

How it works?


The Honeypot solution adds an invisible input field that real users never see. Bots, however, tend to fill in every field they find.

If this hidden field is filled out, the message is automatically blocked and won’t be sent :sparkles:


How to set it up ?


Add the custom script

Go to the General tab in the widget editor, find the Custom JS section, and add the following script:

const CHAT_PORTAL_SELECTOR = ".es-portal-root[class*='eapps-ai-chatbot']";
const HONEYPOT_SELECTOR = ".es-field";
const HONEYPOT_NAME = "Message";

const waitForElement = (selector, root = document) =>
  new Promise((res) => {
    const observer = new MutationObserver(() => {
      const element = root.querySelector(selector);
      if (element) {
        res(element);
        observer.disconnect();
      }
    });

    observer.observe(root, {
      childList: true,
      subtree: true,
    });
  });

const insertHoneyPot = (form) => {
	const submitButton = form.querySelector('[type="submit"]');
	const fieldClone = form.querySelector('.es-form-field-shortText').cloneNode(true);
  const input = fieldClone.querySelector('input');
  const placeHolder = fieldClone.querySelector('[class*="TextControlBasePlaceholder-sc"');
  input.type = "text";
  
  const normolizedHoneypotName = HONEYPOT_NAME.toLowerCase();
  
  input.value = "";
  input.id = normolizedHoneypotName;
  input.name = normolizedHoneypotName;
  input.placeholder = normolizedHoneypotName;
  if (placeHolder) {
    placeHolder.textContent = HONEYPOT_NAME;
  }
  
  fieldClone.classList.add(HONEYPOT_SELECTOR.slice(1));

  form.insertBefore(fieldClone, submitButton);
};

const patchedForms = new WeakSet();

const handlePreSubmit = (e) => {
	const form = e.target.closest('form');
  const honeyPot = form.querySelector(HONEYPOT_SELECTOR);
  
  if (honeyPot.value) {
  	e.preventDefault();
  	e.stopPropagation();
  }
};

const portalObserve = (portal) => {
  const observer = new MutationObserver(() => {
    const chat = portal.querySelector(".es-window-container");
    if (!chat) {
    	return;
    }

    const form = chat.querySelector("form");
    const honeyPot = form?.querySelector(HONEYPOT_SELECTOR);
    
    if (form && !honeyPot) {
      insertHoneyPot(form);
      
      patchedForms.add(form);
    
      const submitButton = form.querySelector('[type="submit"]');
    
      submitButton.addEventListener("click", handlePreSubmit);
    }
  });

  observer.observe(portal, { childList: true, subtree: true });
};

const initHoneyPot = async () => {
  const portal = await waitForElement(CHAT_PORTAL_SELECTOR);
  portalObserve(portal);
};

initHoneyPot();

Note: Custom JS only works on the live site after the widget is installed —it won’t run inside the widget editor or preview.


Add the CSS code

Then, open the Custom CSS section, paste the code below and publish changes:

 .es-field {
  position: absolute !important;
  left: -9999px !important;
  top: auto !important;
  height: 0 !important;
  width: 0 !important;
  overflow: hidden !important;
  opacity: 0 !important;
  pointer-events: none !important;
}


That’s it! Your AI Chatbot is now protected from bot spam and unnecessary message usage.

Guys, was this solution helpful for you? We’d love to hear your thoughts — feel free to share them in the comments :slightly_smiling_face:

2 Likes