V4 Multistep form with custom JavaScript for redirects

Hello team.
I hope someone can help with this pickle situation.
TL;DR; How can we use custom JavaScript with the V4 form setup?
We used legacy forms where we would get some of the values onFormSubmit and pass them in custom JavaScript for redirecting to a custom link. This looked along the lines of this:

<script charset="utf-8" type="text/javascript" src="//js-eu1.hsforms.net/forms/embed/v2.js"></script>
<script>
	hbspt.forms.create({
		portalId: "xxxxxxx",
		formId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
		onFormSubmit: function($form) {
			var choice = $form.find('input[name="xxxx(internal property name)xxxx"]:checked').val();
			var company = $form.find('input[name="company"]').val();
 	var phone = $form.find('input[name="phone"]').val();

			var redirectBase = "https://somelink.com?property1=value";

			window.location =
			redirectBase +
			"&choice=" +
			choice +
			"&company=" +
			company +
			"&phone=" +
			phone;
		} 
	});
</script> 

Now we had to implement a multistep form, which can work only with V4. I haven’t been able to find any documentation on how to do custom JavaScript on V4. I’ve written support, where a bot had suggested using a global event listener for “message” (didn’t work). I’ve tried changing the order of the custom code, using setTimeout - all to no result. I’ve literally spent 2 days now on this without any breakthrough, so any help would be greatly appreciated.

V4 forms don’t support onFormSubmit callbacks directly. You’ll need to use a global message event listener (window.addEventListener(“message”, …)) and check for type: “hsFormCallback”, eventName: “onFormSubmitted”. From there you can grab values via the form fields and handle your redirect logic.

Thank you for the suggestion PSafdar. This is what I also have been trying to do and have been going in a circle with the Support bot without result. I’ve tried to simplify it to the bare minimum of running a console.log, yet it seems the event “message” event is ran only once upon loading the page, or upon switching the tab, but never upon submitting the multistep form.
Here is my code and a screenshot of the logs I get:

<script src="https://js-eu1.hsforms.net/forms/embed/25284517.js" defer></script>
<div
 class="hs-form-frame"
 data-region="eu1"
 data-form-id="xxxxxxxxxxxxxxxxx"
 data-portal-id="xxxxxxx"
></div>

<script>
 (function () {
 var FORM_ID = "xxxxxxxxxxxxxxxxx";

 window.addEventListener("message", function (event) {
 console.log("Message event received");

 if (!event || !event.data) {
 console.log("Event or event.data is missing");
 }

 var payload = event.data;
 console.log("Event payload: ", payload);
 console.log("Event payload type: ", payload.type);
 console.log("Event form ID: ", payload.id);

 if (payload.type !== "hsFormCallback") {
 console.log("Not a HubSpot form callback");
 }
 if (payload.id !== FORM_ID) {
 console.log("Form ID mismatch");
 }

 console.log("Event name: ", payload.eventName);

 if (payload.eventName === "onFormReady") {
 console.log("Form is ready");
 }

 if (
 payload.eventName === "onFormSubmit" ||
 payload.eventName === "onFormSubmitted"
 ) {
 console.log("Form submission detected");

 setTimeout(function () {
 console.log("Executing redirect...");
 }, 300);
 }
 });

 console.log("Event listener setup completed");
 })();
</script>

I’ve clicked through all the settings of the form in HS and don’t see anything that could potentially hold the key, but this global eventListener really hasn’t helped me no matter how many variations of it I’ve tried so far :confused:

Hey, @YVasilev :waving_hand: Thanks for putting in the work and sharing your examples. I’d like to invite some of our Community Champions to the converstaion — hey @Anton @evaldas do you have any wisdom or troubleshooting steps you can share with @YVasilev?

Thank you very much! — Jaycee

Thanks, @Jaycee_Lewis . I did a bit more thorough research and stumbled on a duplicate that’s been solved by @Eric_Hoyer here https://community.hubspot.com/t5/Lead-Capture-Tools/Onsubmit-function-in-multistep-beta-forms/m-p/1033290#M11915 His solution worked like a charm. I am refining it a bit with Cursor and will make sure to share code with example properties and redirects tomorrow some time (:

Hey, @YVasilev :waving_hand: That’s amazing! I’m going to accept your reply as a solution, and I’ll do the same when you share your updated example(s). Cheers! — Jaycee

thank @YVasilev, that genuinely makes my day if that helped you. Thank you for paying it forward with your own additions! :heart:

Here is how to add custom JavaScript to multistep V4 HubSpot forms:
1. Make sure you copy the “Developer code (Advanced)” embed code. This loads a different script, besides pointing to `hs-form-html` and not `hs-form-frame`

2. Use a combination of JS methods (attachHubSpotFormSubmitListener(), onHubSpotFormSubmit(event)) and a DOMContentLoaded eventListener.
Here is an example code for catching properties upon submission and then passing them on as URL redirect parameters. I’ve added a bit of variety by selecting a dropdown, checkbox, and text field properties and having some conditional logic.

<script src="https://js-eu1.hsforms.net/forms/embed/developer/25284517.js" defer></script>
<div class="hs-form-html" data-region="eu1" data-form-id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" data-portal-id="xxxxxxxx"></div>

<script>
 function onHubSpotFormSubmit(event) {
 event.preventDefault();

 var form = event.target;
 var data = Object.fromEntries(new FormData(form).entries());

 const {
 ["0-1/firstName"]: firstName,
 ["0-1/lastName"]: lastName,
 ["0-1/email"]: email,
 ["0-1/phone"]: phone,
 ["0-1/us_role_select"]: role_select,
 ["LEGAL_CONSENT.processing"]: legal_consent_processing,
 } = data;

 // Build redirect URL
 var redirectBase = "https://your-url.com?page=form_page";
 var redirectUrl =
 redirectBase +
 "&firstName=" +
 encodeURIComponent(firstName || "") +
 "&lastName=" +
 encodeURIComponent(lastName || "") +
 "&email=" +
 email +
 "&phone=" +
 encodeURIComponent(phone || "") +
 "&role=" +
 (role_select || "");

 if (role_select === "MANAGER") {
 if (!firstName || !lastName || !email || !phone || !legal_consent_processing) {
 console.log("Please, fill in all required fields!");
 } else {
 window.location.href = redirectUrl;
 }
 }

 if (role_select === "EMPLOYEE") {
 if (!firstName || !lastName || !email || !phone || !reasons_to_join_trial_us || !legal_consent_processing) {
 console.log("Please, fill in all required fields!");
 } else {
 window.location.href = redirectUrl;
 }
 }
 }

 // Check if the form is loaded and then add the event listener
 function attachHubSpotFormSubmitListener() {
 var formElement = document.querySelector(".hs-form-html form");
 if (formElement) {
 formElement.addEventListener("submit", onHubSpotFormSubmit);
 } else {
 // Retry after a short delay if the form is not yet loaded
 setTimeout(attachHubSpotFormSubmitListener, 500);
 }
 }

 // Ensure the script runs after the page is fully loaded
 document.addEventListener("DOMContentLoaded", function () {
 attachHubSpotFormSubmitListener();
 });
</script>

It took me 4 days to get to this solution, due to looking at the wrong place for help. Hope this code helps anyone who might need a similar setup. Once again, big thanks to @Eric_Hoyer

The docs have global event listeners for the V4 forms here - Global form events - HubSpot docs
Just make sure you are embedding the form using the developer version:

Set up your event listeners like this:

Form Ready:

window.addEventListener("hs-form-event:on-ready", event => {
 const { formId, instanceId } = event.detail;
 console.log(formId);
});

Form Submit Success:

window.addEventListener("hs-form-event:on-submission:success", event => {
 const form = HubSpotFormsV4.getFormFromEvent(event);
 const conversionId = form.getConversionId();
 console.log(conversionId);
 //DO YOUR LOGIC HERE
});

Tremendous shoutout to @amcintosh for providing the references and appropriately crapping on GPT on this other forum - Solved: HubSpot Community - Onsubmit function in multistep beta forms - HubSpot Community