When working with Web-to-Lead forms, you might run into a situation where you'd like to integrate the form with your frontend framework (React, Vue, Angular, etc...). This can be accomplished quite easily using whatever HTTP library you're most comfortable with.
To demonstrate this, let's take a look at an example Web-to-Lead form, and the JavaScript required to post Leads to a SFDC org.
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>Testing Posting Leads to SFDC</h1>
<p>Use the form below to post a new lead to SFDC. It will post via JS, rather than the standard Form action.</p>
<form>
<input type="hidden" id="oid" name="oid" value="XXXXXXXXXXXXXXX" />
<input type="hidden" id="retURL" name="retURL" value="https://www.johnturnertech.com" />
<div class="field">
<label for="first_name">First Name <span>*</span></label>
<input id="first_name" maxlength="40" name="first_name" size="20" type="text" />
</div>
<div class="field">
<label for="last_name">Last Name <span>*</span></label>
<input id="last_name" maxlength="80" name="last_name" size="20" type="text" />
</div>
<div class="field">
<label for="company">Company <span>*</span></label>
<input id="company" maxlength="40" name="company" size="20" type="text" />
</div>
<div class="field">
<label for="title">Job Title</label>
<input id="title" maxlength="40" name="title" size="20" type="text" />
</div>
<div class="field">
<label for="email">Business Email <span>*</span></label>
<input id="email" maxlength="80" name="email" size="20" type="text" />
</div>
<div class="field">
<label for="phone">Phone Number</label>
<input id="phone" maxlength="40" name="phone" size="20" type="text" />
</div>
<div class="field">
<label for="lead_source">Lead Source</label>
<select id="lead_source" name="lead_source" title="Lead Source">
<option value="">--None--</option>
<option value="Conference">Conference</option>
<option value="Referral">Referral</option>
<option value="Web">Web</option>
<option value="Other">Other</option>
</select>
</div>
<button type="button" id="submit-button" onclick="postLeadToSFDC()">Submit</button>
</form>
</body>
<script src="postLead.js"></script>
</html>
Some things to note from this form:
- We've removed all attributes from the
form
tag, including theaction
- The
<input type="submit" />
has been replaced for a simplebutton
tag with anonclick
handler pointing to a JS function that we'll see shortly - We've linked to a JS file in the
script
tag at the bottom of the HTML
Here's the linked JS file for grabbing the values and posting Leads to SFDC.
function postLeadToSFDC() {
const requestOptions = {
method: 'POST',
mode: 'no-cors',
};
const oid = document.getElementById('oid').value;
const retUrl = document.getElementById('retURL').value;
const firstName = document.getElementById('first_name').value;
const lastName = document.getElementById('last_name').value;
const company = document.getElementById('company').value;
const title = document.getElementById('title').value;
const email = document.getElementById('email').value;
const phone = document.getElementById('phone').value;
const leadSource = document.getElementById('lead_source').value;
fetch(
`https://webto.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8&oid=${oid}&retURL=${retUrl}&first_name=${firstName}&last_name=${lastName}&company=${company}&title=${title}&email=${email}&phone=${phone}&lead_source=${leadSource}`,
requestOptions
)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.log('error', error));
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('submit-button').addEventListener('onclick', () => {
postLeadToSFDC();
});
});
Here are some important things to note about this code:
- We specifically set
no-cors
in the request options in order to avoid hitting errors from the response from Salesforce- This is important: despite returning a CORS error in the browser, the Lead is actually created in Salesforce. So, you can safely turn on Opaque results without worrying about missing other information.
- The data for the form is all passed in via query parameters
Unfortunately SFDC doesn't return anything helpful in terms of server-side validation of your data when using this method. If you happen to send in data that is malformed, or that might trip a duplicate matching rule, you won't be notified via a 400-level response.
Instead, for every request, you'll get a 200 response. Even if the Lead isn't created due to bad data or duplicate rules. In fact, you could run the above code exactly as it is, including with the XXXXXXXXXXXXXXX
as the oid
value, and you'll still get back a 200 from SFDC.
For this reason, it would be wise to layer in some additional client-side validation, at least to catch malformed data.
The above example doesn't have any Date fields in it, however when POST-ing data to be stored in Date fields in Salesforce, you must do it in the correct format. Usually, when performing bulk data loads or posting via standard REST APIs, dates should be sent in YYYY-MM-DD
format. However, for some odd reason, when sending data via Web-to-Lead, you MUST send it over according to your org's local settings.
For example, if your org's locale is set to US, your date string must be sent over in this format: DD/MM/YYYY
, otherwise your date field won't be set at all in the resulting lead.
Here is a sample JS snipped for formatting the date correctly based on US locale settings without any libraries:
const rawDate = new Date();
const day = rawDate.getDate() > 9 ? `${rawDate.getDate()}` : `0${rawDate.getDate()}`;
const dateString = `${rawDate.getMonth() + 1}/${day}/${rawDate.getFullYear()}`;
Explanation of the 3 lines as follows:
- Line 1 gets a new Date instance for today's date
- Line 2 correctly pads the day with a 0 if today's date is less than 10
- Line 3 formats the dateString to
DD/MM/YYYY
.
You can then pass that date string into the URL that you construct when POST-ing the Lead information to Salesforce
Thanks for posting this, any idea how I pass the record type along? I've tried recordType, recordTypeId, record_type. I've tried both the Record type Id and Record Type Name with each of the options just mentioned.