Client-side custom code in workflow automation not triggering on form submit events

I’m having trouble with custom JavaScript that’s supposed to trigger workflow automation in HubSpot 2021. The workflow is designed to activate when a contact form is submitted, but my custom code that sends additional data via AJAX isn’t executing consistently.

The form submission works fine and creates the contact, but the custom JavaScript that should fire immediately after to trigger the workflow with enriched data just doesn’t run about 30% of the time. I’ve added the script to the form’s custom code section, but I’m wondering if there’s an issue with event delegation or the script load order.

When it does work, everything processes correctly. But the inconsistency is causing workflow automation failures and our sales team is missing important lead context. Has anyone experienced similar issues with custom code execution timing in HubSpot forms?

I agree with Marcus. Also, check if you’re using event.preventDefault() anywhere in your code. If your custom script prevents the default form submission while it’s processing the AJAX call, but then fails to manually trigger the submission, the workflow will never fire. The form needs to actually submit to HubSpot for the workflow trigger to activate. Your AJAX enrichment should happen in parallel or as a follow-up, not as a blocker to the main submission.

Let me provide a complete solution that addresses event delegation, AJAX form submission, and script load order issues.

First, use HubSpot’s proper form callback system to ensure your code runs at the right time:

window.addEventListener('message', event => {
  if (event.data.type === 'hsFormCallback') {
    if (event.data.eventName === 'onFormSubmit') {
      handleFormSubmission(event.data);
    }
  }
});

For the AJAX enrichment, never prevent the default submission. Instead, send your enrichment data in parallel:

function handleFormSubmission(formData) {
  const enrichmentData = prepareEnrichmentData(formData);
  fetch('/api/enrich-contact', {
    method: 'POST',
    body: JSON.stringify(enrichmentData)
  }).catch(err => console.error('Enrichment failed:', err));
}

Notice we’re using .catch() but not blocking the form. The form submission completes normally, triggering your workflow, while enrichment happens asynchronously. If enrichment fails, the workflow still fires.

For script load order, inline critical initialization code directly in your HubSpot form embed:

<script>
(function() {
  if (typeof window.hsFormCallbacks === 'undefined') {
    window.hsFormCallbacks = [];
  }
  window.hsFormCallbacks.push(handleFormSubmission);
})();
</script>

This ensures the callback is registered before the form loads, eliminating timing issues.

The key insight here is separation of concerns: let HubSpot handle form submission and workflow triggering normally, while your custom code runs as a non-blocking enhancement. This architecture prevents the 30% failure rate you’re experiencing because the critical path (form submit → workflow trigger) never depends on your custom code succeeding.

For event delegation specifically, avoid direct element selectors. Use the form callback system which provides you with form data regardless of DOM structure. This makes your code resilient to HubSpot’s form rendering changes.

Implement error logging in your enrichment function so you can track when and why it fails without impacting the main workflow. This gives you visibility into the 30% failure cases while ensuring they don’t break the user experience.

This sounds like a classic AJAX race condition. When the form submits, HubSpot’s native form handler might be completing before your custom code runs, or vice versa. Are you using onFormSubmit callback? That’s the proper way to ensure your code executes at the right time in the form submission lifecycle. If you’re just attaching to the submit event directly, the timing will be unpredictable.