All the ways you can invoke the RevenueHero scheduler on your website, from standard form listeners to programmatic triggers like hero.submit() and hero.dialog.open().
The standard way to invoke RevenueHero is hero.schedule('#form-id'), which listens for your form’s submit event and opens the scheduler automatically. But that doesn’t always fit. Maybe you’re running server-side validation before showing the calendar. Maybe your form lives inside an iframe. Maybe you’re building in React and there’s no traditional form submit event to listen to.This article covers every way to invoke the RevenueHero scheduler on your website. For the step-by-step router setup that generates your script snippet, see Create Inbound Router.
The RevenueHero script exposes three methods. The first, hero.schedule(), is the standard method documented in every web forms integration guide. The other two, hero.submit() and hero.dialog.open(), give you programmatic control over the entire flow.
Binds to a form’s native submit event. When the form is submitted, RevenueHero intercepts the data, runs routing rules, and opens the scheduler automatically.
const hero = new RevenueHero({ routerId: '123' });hero.schedule('#demo-form'); // CSS selector for your form element
When to use: Your form uses a standard HTML submit and you don’t need to intercept the submission before the scheduler appears.Limitation: If you call e.preventDefault() on the form’s submit event before RevenueHero can listen to it, hero.schedule() will never fire. Use hero.submit() instead.
Sends form field data directly to RevenueHero for routing and qualification. Returns a Promise that resolves with session data you can use to open the scheduler.
When to use: You need to control what happens between form submission and the scheduler appearing. Custom validation, async API calls, multi-step forms, SPA frameworks, or any flow where hero.schedule() doesn’t work.
Pass a plain object, not a FormData instance. If you’re collecting data from a form element, convert it first:
The most common reason to use hero.submit() is when you need to validate form data before showing the scheduler. Run your validation, and only trigger RevenueHero if it passes.
<form id="bookademoform"> <input name="email" type="email" required /> <input name="firstName" type="text" required /> <input name="company" type="text" /> <button type="submit">Request Demo</button></form><script type="text/javascript" src="https://app.revenuehero.io/scheduler.min.js"></script><script type="text/javascript"> const form = document.getElementById('bookademoform'); form.addEventListener('submit', async function(e) { e.preventDefault(); const data = Object.fromEntries(new FormData(form).entries()); // Your custom validation (API call, domain check, etc.) const response = await fetch('https://your-api.com/validate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: data.email }) }); const result = await response.json(); if (result.status === 'valid') { // Only show the scheduler for valid leads const hero = new RevenueHero({ routerId: '963', showLoader: true }); hero.submit(data).then(function(sessionData) { hero.dialog.open(sessionData); }); } else { // Show an error message document.getElementById('error').textContent = 'Please use a work email.'; } });</script>
This pattern is useful for running checks like email validation services, domain blocklists, or CRM lookups before consuming a RevenueHero routing. If the check fails, the prospect never sees the scheduler and no routing log entry is created.
Webflow forms submit via AJAX by default. If the standard hero.schedule() doesn’t trigger the scheduler on your Webflow site, use this jQuery-based intercept pattern:
<script type="text/javascript" src="https://app.revenuehero.io/scheduler.min.js"></script><script type="text/javascript"> jQuery(document).ajaxComplete(function(event, xhr, settings) { if (settings.url.includes('https://webflow.com/api/v1/form/')) { var formElement = document.querySelector('#wf-form-Email-Form'); var isSuccessful = xhr.status === 200; var isTargetForm = settings.data.includes(formElement.dataset['wfElementId']); if (isTargetForm && isSuccessful) { var submitData = Object.fromEntries(new FormData(formElement).entries()); var hero = new RevenueHero({ routerId: '123' }); hero.submit(submitData).then(function(sessionData) { hero.dialog.open(sessionData); }); } } });</script>
Replace #wf-form-Email-Form with your Webflow form’s CSS ID and '123' with your Router ID.
This script must be placed in the Before </body> tag section in Webflow, not the <head>. The form element needs to exist in the DOM before the script runs.
For the standard Webflow installation that works without this intercept, see Webflow Forms.
Set the trigger to DOM Ready on the pages where your form exists
Publish the container
Do not use the “All Pages” trigger with a Page View firing option. The script needs the form element to be present in the DOM when it executes. Use DOM Ready or Window Loaded as the trigger.
Use RevenueHero’s JavaScript Events to push conversion data into the GTM data layer:
<script type="text/javascript"> window.addEventListener('message', function(ev) { if (ev.data.type === 'PAGE_LOADED') { // Fires when the scheduler is shown (lead qualified) window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'rh_qualified' }); } if (ev.data.type === 'MEETING_BOOKED') { // Fires when a meeting is booked window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'rh_meeting_booked', booker_email: ev.data.meeting.attributes.booker_email, meeting_time: ev.data.meeting.attributes.meeting_time }); } });</script>
The PAGE_LOADED event is particularly useful for Google Ads conversion tracking. It fires when the scheduler with booking slots is displayed, which means the lead passed your routing qualification. Use this as a “Qualified Lead” conversion action.
If you use the same form structure across many pages (e.g., the same HubSpot form on 400+ landing pages), you can install one script at the template level.Add the RevenueHero script to your site’s global template or theme footer. The script will look for the specified form selector on every page. If the form isn’t present on a particular page, the script does nothing.
<!-- Add to your site-wide template, theme footer, or CMS global code --><script type="text/javascript" src="https://app.revenuehero.io/scheduler.min.js"></script><script type="text/javascript"> window.hero = new RevenueHero({ routerId: '123' }); hero.schedule('#demo-form');</script>
If you have multiple forms mapped to different routers, use a single scheduler.min.js include in the <head> and separate hero.schedule() calls in the <body> of each page.
Re-trigger the scheduler (booking incomplete page)
If a prospect fills your form but doesn’t book a meeting, you can create a “Booking Incomplete” page that lets them try again. Store the form data in localStorage after the initial submission, then use hero.submit() on the retry page.
form.addEventListener('submit', function(e) { // Save the form data for the retry page var data = Object.fromEntries(new FormData(form).entries()); localStorage.setItem('rhdata', JSON.stringify(data)); localStorage.setItem('rhid', '963'); // your Router ID});
Check the form selector. The CSS selector passed to hero.schedule() must match your form element exactly. Open your browser’s developer console and run document.querySelector('#your-form-id') to verify the form element exists.Check for e.preventDefault(). If your JavaScript calls e.preventDefault() on the form’s submit event before RevenueHero’s listener fires, the scheduler won’t trigger. Switch to hero.submit() + hero.dialog.open().Check the browser console. Look for errors from scheduler.min.js. A 500 error from the RevenueHero API usually means a field mapping mismatch. Verify that the field names in your form match the mappings in your Inbound Router.
Don’t defer the script. Adding defer or async attributes to the scheduler.min.js script tag can cause it to load after your form’s submit handler runs. Load it synchronously in the <head> section.
WordPress / WP Rocket users: WP Rocket and similar optimization plugins may automatically defer or lazy-load third-party scripts. Exclude scheduler.min.js from defer, delay, and minification settings.
If your form renders inside an iframe (common with Pardot embedded forms), the parent page’s RevenueHero script cannot access the form’s submit event due to cross-origin restrictions.Solutions:
Use the Pardot integration which handles this natively with formType: 'pardot'
Add the RevenueHero script inside the iframe’s HTML (in the form’s “Below Form” or “Thank You” content area)
If neither works, contact support. The team can build a custom script for your form handler setup.
Some CMS platforms (WordPress visual editors, PHP templates) may wrap your <script> tag in <p> or <div> tags, which breaks execution. Use your CMS’s raw HTML or code block to prevent this.Your advanced script installation is configured. Once you’ve added the script to your page, submit a test form entry and check your Routing Logs to confirm submissions are flowing through. 🎉🎉🎉
JavaScript Events
Listen for MEETING_BOOKED, PAGE_LOADED, and other events from the scheduler widget.
Create Inbound Router
Set up routing rules and get your Router ID.
Mapping Your Form
Map your form fields so RevenueHero can use them in routing conditions.
Custom HTML Forms
Standard script installation for custom HTML forms.