One of the popular CRM services, HubSpot, offers tools such as forms and, similarly, LP pages under marketing. Forms created can be used across various channels via links, and/or through the embed option on websites.
Using HubSpot’s tracking code, unless otherwise specified, form activities on the website can be monitored and converted into actionable data. In the course of the website interface redesign, I decided to prioritize the integration of Typeform for key lead capture fields, while instead of completely removing HubSpot usage, I limited its implementation to tracking and email sign-up functionality. I will publish additional articles detailing the reasons behind this decision in the future.
Returning to our main topic, on the Content page, there is a small email signup field located in the middle section. This compact form is built using HubSpot’s form structure. However, I opted for AJAX as the submission method1. Standard form configurations and, of course, customizations require significant manual intervention. For this reason, I re-evaluated the submission process using the Forms API2 capabilities.
As shown in the relevant explanations, we can send form submissions to HubSpot using the POST method with the following structure.
{
"submittedAt": "1517927174000",
"fields": [
{
"name": "email",
"value": "example@example.com"
},
{
"name": "firstname",
"value": "Jeff"
}
],
"context": {
"hutk": ":hutk",
"pageUri": "www.example.com/page",
"pageName": "Example page"
},
"legalConsentOptions": {
"consent": {
"consentToProcess": true,
"text": "I agree to allow Example Company to store and process my personal data.",
"communications": [
{
"value": true,
"subscriptionTypeId": 999,
"text": "I agree to receive marketing communications from Example Company."
}
]
}
}
}
When examining a standard form3, we observe the endpoint address to which form submissions are sent, defined in the form as endpoint, portalId, and formId. For AJAX submissions, we must use these fields in the standard form we created.
endpoint = "https://api.hsforms.com/submissions/v3/integration/submit",
portalId = <account-id>,
formId = <form-id>,
In addition to these details, we also require the hubspotutk cookie value used by HubSpot for potential customer engagement tracking. HubSpot handles this process on the standard form page; in external scenarios, either a static value or access to the cookie value is required1 4 5. On a form page where the tracking code is active, you can view the relevant cookie value via window.__hsUserToken.
First, I’m presenting the form field in its most minimal form as an example below.
<form id="hs-newsletter-form">
<label class="form-label" for="hs-first-name">First & Last Name</label>
<input name="firstname" id="hs-firstname" type="text" />
<label class="form-label" for="hs-email-address">Email</label>
<input name="email" id="hs-email" type="email" />
<input type="checkbox" required="" name="privacy" id="hs-privacy" />I have read and agreed to the privacy notice.
<button type="submit" id="hb-submit">Submit</button>
</form>
After properly arranging the form elements to match your website’s design, you can now begin using the code snippet that sends the data via AJAX.
document.getElementById('hb-submit').addEventListener('click', function (e) {
e.preventDefault();
const gethutk = Object.fromEntries(
document.cookie.split(/; /).map(c => {
const [key, v] = c.split('=', 2);
return [key, decodeURIComponent(v)];
}),
);
const
name = document.getElementById('hs-firstname'),
email = document.getElementById('hs-email'),
jsonString = JSON.stringify({
"fields": [{
"name": "firstname",
"value": (name && typeof(name) !== 'undefined') ? name.value : null
}, {
"name": "email",
"value": (email && typeof(email) !== 'undefined00') ? email.value : null
}],
"submittedAt": Date.now(),
"context": {
"hutk": gethutk.hubspotutk || "...",
"pageName": document.title,
"pageUri": window.location.href
},
"legalConsentOptions": {
"consent": {
"consentToProcess": true,
"text": "I have read and agreed to the privacy notice"
}
}
}),
xmlhttp = new XMLHttpRequest(),
endpoint = "https://api.hsforms.com/submissions/v3/integration/submit",
portalId = <account-id>,
formId = <form-id>,
theURL = endpoint + '/' + portalId + '/' + formId;
if(document.getElementById('hs-privacy').checked === true){
xmlhttp.open("POST", theURL);
xmlhttp.setRequestHeader("content-type", "application/json;charset=utf-8");
xmlhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
//...
} else {
//...
}
};
xmlhttp.send(jsonString);
}
});
The context object checks for the presence of hutk in its content and, if no value is found, indicates "..." as specified; however, you will use a form page’s cookie check and/or the value obtained from window.__hsUserToken. Outside of this usage, alternative solutions could certainly be explored6 7.
Due to its potential implementation as a shortcode in content management systems such as WordPress, Grav, and similar platforms, the AJAX functionality can be flexibly embedded at the desired point within content and/or pages. Additionally, this approach can streamline the testing process.
*[CRM]: Customer Relationship Management
*[LP]: Landing Page