Website: Update user routing in deliver-talk-to-us-submission action (#47457)

Related to: https://github.com/fleetdm/confidential/issues/16303

Changes:
- Added a new Salesforce helper: getTerritoryUserId, a helper that
returns the ID of the Salesforce user associated with a provided
location (state, country, city)
- Updated the deliver-talk-to-us-form-submission action to send ICP
users to one of five different Calendly events based on their company's
headquarters location.
- Updated the get-enriched helper to include company headquarters
information when enriching a user.
This commit is contained in:
Eric
2026-06-11 16:37:37 -05:00
committed by GitHub
parent f3034ab1de
commit fee63bba51
3 changed files with 199 additions and 46 deletions
+93 -45
View File
@@ -94,58 +94,106 @@ module.exports = {
marketingAttributionCookie: attributionCookieOrUndefined
};
// If the user said they have 700+ hosts, Update/create a contact and account, and send them to the "Talk to us" Calendly event.
if(numberOfHosts >= 700){
// Simultaneously run the enrichment helper and send a prompt to an LLM to try to guess the company's headquarters location (city/country/state) from the email domain.
// We use the information returned by the LLM as a fallback for the territory lookup below when the enrichment helper doesn't return location information.
let locationGuessSystemPrompt = 'You are a precise data-extraction function. Respond with a single raw JSON object and nothing else.';
let locationGuessPrompt =
`Where is the company that owns the email domain "${emailDomain}" headquartered?
Respond with a JSON object using these keys:
- "city": the headquarters city name.
- "country": the full country name in English (for example, "United States").
- "state": the full state name. Only include this key when the country is the United States.
Only include a key when you are confident of its value. Omit any key you are unsure of; do not guess, and do not use null or empty strings.`;
let { enrichmentInformation, locationGuessFromEmailDomain } = await sails.helpers.flow.simultaneously({
enrichmentInformation: async()=>{
return await sails.helpers.iq.getEnriched.with({
emailAddress,
includeEmployerHeadquartersInformation: true,
}).tolerate((err)=>{
sails.log.warn(`When a user (${emailAddress}) submitted the "Talk to us form", an error occurred while getting enrichment information for this user. Error from get-enriched helper: ${require('util').inspect(err)}`);
return {};
});
},
locationGuessFromEmailDomain: async()=>{
return await sails.helpers.ai.prompt.with({
prompt: locationGuessPrompt,
baseModel: 'gpt-5-nano-2025-08-07',
expectJson: true,
systemPrompt: locationGuessSystemPrompt,
}).tolerate((err)=>{
sails.log.warn(`When a user (${emailAddress}) submitted the "Talk to us form", an error occurred while guessing their company's headquarters location from the email domain (${emailDomain}). Error from prompt helper: ${require('util').inspect(err)}`);
return {};
});
},
});
let employeeCountFromEnrichmentHelper = (enrichmentInformation.employer || {}).numberOfEmployees;
// If we got a employer.numberOfEmployees value from the getEnriched helper, or the user entered more than 700 hosts, get the SF user who owns the territory that this user's company is in, and send them to a "Talk to us" calendly event.
if(numberOfHosts >= 700 || (employeeCountFromEnrichmentHelper && employeeCountFromEnrichmentHelper >= 700)) {
contactInformation.contactSource = 'Website - Contact forms - Demo - ICP';
contactInformation.description = `Submitted the "Talk to us" form and was taken to the Calendly page for the "Talk to us" event. Provided organization name: ${organization}, Number of employees: ${numberOfHosts}`;
if(employeeCountFromEnrichmentHelper && employeeCountFromEnrichmentHelper >= 700) {
contactInformation.description = `Submitted the "Talk to us" form and was taken to the Calendly page for the "Talk to us" event because of the number of employees (${employeeCountFromEnrichmentHelper}) returned by Coresignal. Provided organization name: ${organization}, Number of employees: ${numberOfHosts}`;
} else {
contactInformation.description = `Submitted the "Talk to us" form and was taken to the Calendly page for the "Talk to us" event. Provided organization name: ${organization}, Number of employees: ${numberOfHosts}`;
}
sails.helpers.salesforce.updateOrCreateContactAndAccount.with(contactInformation).exec((err)=>{
if(err) {
sails.log.warn(`Background task failed: When a user submitted the "Talk to us" form, a lead/contact could not be updated in the CRM for this email address: ${emailAddress}. Full Error: ${require('util').inspect(err)}`);
}
});//_∏_
// Prefer the enrichment helper's location, but fall back to the email-domain location
// guess when enrichment didn't return a country (the field getTerritoryUserId requires).
let employerLocation = enrichmentInformation.employer || {};
let locationForTerritoryLookup = (employerLocation.country ? employerLocation : locationGuessFromEmailDomain) || {};// Default to an empty object if neither sources returned this information.
let territoryUserId = await sails.helpers.salesforce.getTerritoryUserId.with({
state: locationForTerritoryLookup.state,
country: locationForTerritoryLookup.country,
city: locationForTerritoryLookup.city
}).tolerate((err)=>{
sails.log.warn(`When a user submitted the "Talk to us" form, Salesforce territory information could not be found using the provided information. This user will be sent to the calendly link for the washingtonDc region. Full error: ${require('util').inspect(err)}`);
return '0054x0000086sOlAAI';
});
let bookingUrlByUserId = {
'005UG000006YYDVYA4': 'https://calendly.com/d/d3fs-28g-vdk/talk-to-us', //newYorkCity
'0054x0000086sOlAAI': 'https://calendly.com/d/dzyz-tt7-yt8/talk-to-us', //washingtonDc
'005UG000008y0wbYAA': 'https://calendly.com/d/ds9c-9vt-mz6/talk-to-us', //losAngeles
'0054x0000086wsGAAQ': 'https://calendly.com/d/dz4c-mjx-6xv/talk-to-us', //sanFrancisco
'005UG000009NnSfYAK': 'https://calendly.com/d/ds88-n2m-ddt/talk-to-us', //stockholm
};
let eventUrlForThisUsersTerritory = bookingUrlByUserId[territoryUserId];
if(!eventUrlForThisUsersTerritory) {
// If the user ID returned by the helper is not one of the five expected values above, log a warning to alert us, and send the user to the washingtonDc calednly link.
sails.log.warn(`When looking up Salesforce territory information to route a user (email: ${emailAddress}) who submitted the "Talk to us" form to the correct meeting link, the user ID returned by the getTerritoryUserId helper (${territoryUserId}) did not match the hardcoded user IDs in the bookingUrlByUserId dictionary. This user will be sent to the callendly link for the washingtonDc region.`);
eventUrlForThisUsersTerritory = 'https://calendly.com/d/dzyz-tt7-yt8/talk-to-us';
}
return {
icp: true,
eventUrl: eventUrlForThisUsersTerritory +`?email=${encodeURIComponent(emailAddress)}&name=${encodeURIComponent(firstName+' '+lastName)}`,
};
} else {
// If the enrichment helper didn't return a employer.numberOfEmployees value and this user has <700 hosts, send them to the "Let's get you set up!" Calendly event
contactInformation.contactSource = 'Website - Contact forms - Demo';
contactInformation.description = `Submitted the "Talk to us" form and was taken to the Calendly page for the "Let\'s get you set up!" event. Provided organization name: ${organization}, Number of employees: ${numberOfHosts}`;
sails.helpers.salesforce.updateOrCreateContactAndAccount.with(contactInformation).exec((err)=>{
if(err) {
sails.log.warn(`Background task failed: When a user submitted the "Talk to us" form, a lead/contact could not be updated in the CRM for this email address: ${emailAddress}.`, err);
}
});
});//_∏_
return {
icp: true,
eventUrl: `https://calendly.com/fleetdm/talk-to-us?email=${encodeURIComponent(emailAddress)}&name=${encodeURIComponent(firstName+' '+lastName)}`
icp: false,
eventUrl: `https://calendly.com/fleetdm/chat?email=${encodeURIComponent(emailAddress)}&name=${encodeURIComponent(firstName+' '+lastName)}`
};
} else {
// If the user has <700 hosts, use the get-enriched helper to try to find the number of employees at their organization.
let enrichmentInformation = await sails.helpers.iq.getEnriched.with({
emailAddress,
firstName,
lastName,
}).tolerate((err)=>{
sails.log.warn(`When a user (${emailAddress}) submitted the "Talk to us form", an error occured while getting enrichment information for this user. Error from get-enriched helper: ${require('util').inspect(err)}`);
return {};
});
// If we got a employer.numberOfEmployees value from the getEnriched helper, send the user to the "talk to us" calendly event if it is 700+.
if(enrichmentInformation.employer && enrichmentInformation.employer.numberOfEmployees && enrichmentInformation.employer.numberOfEmployees >= 700) {
contactInformation.contactSource = 'Website - Contact forms - Demo - ICP';
contactInformation.description = `Submitted the "Talk to us" form and was taken to the Calendly page for the "Talk to us" event because of the number of employees (${enrichmentInformation.employer.numberOfEmployees}) returned by Coresignal. Provided organization name: ${organization}, Number of employees: ${numberOfHosts}`;
sails.helpers.salesforce.updateOrCreateContactAndAccount.with(contactInformation).exec((err)=>{
if(err) {
sails.log.warn(`Background task failed: When a user submitted the "Talk to us" form, a lead/contact could not be updated in the CRM for this email address: ${emailAddress}.`, err);
}
});
return {
icp: true,
eventUrl:`https://calendly.com/fleetdm/talk-to-us?email=${encodeURIComponent(emailAddress)}&name=${encodeURIComponent(firstName+' '+lastName)}`
};
} else {
// If the enrichment helper didn't return a employer.numberOfEmployees value and this user has <700 hosts, send them to the "Let's get you set up!" Calendly event
contactInformation.contactSource = 'Website - Contact forms - Demo';
contactInformation.description = `Submitted the "Talk to us" form and was taken to the Calendly page for the "Let\'s get you set up!" event. Provided organization name: ${organization}, Number of employees: ${numberOfHosts}`;
sails.helpers.salesforce.updateOrCreateContactAndAccount.with(contactInformation).exec((err)=>{
if(err) {
sails.log.warn(`Background task failed: When a user submitted the "Talk to us" form, a lead/contact could not be updated in the CRM for this email address: ${emailAddress}.`, err);
}
});
return {
icp: false,
eventUrl: `https://calendly.com/fleetdm/chat?email=${encodeURIComponent(emailAddress)}&name=${encodeURIComponent(firstName+' '+lastName)}`
};
}
}
}
+42 -1
View File
@@ -23,6 +23,8 @@ module.exports = {
lastName: { type: 'string', defaultsTo: '', },
organization: { type: 'string', defaultsTo: '', },
includeEmployerHeadquartersInformation: {type: 'boolean', defaultsTo: false}
},
@@ -51,7 +53,7 @@ module.exports = {
},
fn: async function ({emailAddress,linkedinUrl,firstName,lastName,organization}) {
fn: async function ({emailAddress,linkedinUrl,firstName,lastName,organization, includeEmployerHeadquartersInformation}) {
require('assert')(sails.config.custom.iqSecret);// FUTURE: Rename this config
require('assert')(sails.config.custom.RX_PROTOCOL_AND_COMMON_SUBDOMAINS);
@@ -289,6 +291,7 @@ module.exports = {
return undefined;
});
if (matchingCompanyPageInfo) {
let emailDomain;
if(matchingCompanyPageInfo.website) {
let parsedCompanyEmailDomain = require('url').parse(matchingCompanyPageInfo.website);
@@ -301,6 +304,44 @@ module.exports = {
emailDomain: emailDomain,
linkedinCompanyPageUrl: matchingCompanyPageInfo.canonical_url.replace(sails.config.custom.RX_PROTOCOL_AND_COMMON_SUBDOMAINS,''),
};
// If we're including location information, use the prompt helper to transform the location information returned by Coresignal into a JSON object.
if(includeEmployerHeadquartersInformation) {
let primaryLocation = _.find(matchingCompanyPageInfo.company_locations_collection, (location)=>{
return location.is_primary === 1;
});
let locationInfo = {};
if(primaryLocation && primaryLocation.location_address) {
let systemPromptForAddressInformation = 'You are a precise data-extraction function. Respond with a single raw JSON object and nothing else.';
let locationPrompt =
`Extract the location from the following company headquarters address.
Address: "${primaryLocation.location_address}"
Respond with a JSON object using these keys:
- "city": the city name.
- "country": the full country name in English (for example, "United States").
- "state": the full state name. Only include this key when the country is the United States.
Only include a key when its value is present in the address. Omit any key whose value you cannot determine; do not guess, and do not use null or empty strings.`;
locationInfo = await sails.helpers.ai.prompt.with({
prompt: locationPrompt,
baseModel: 'gpt-5-nano-2025-08-07',
expectJson: true,
systemPrompt: systemPromptForAddressInformation,
}).tolerate((err)=>{
sails.log.warn(`When parsing a company's headquarters address ("${primaryLocation.location_address}") into structured location data, the prompt helper responded with an error: `, err);
return {};
});
}
employer.state = locationInfo.state;
employer.country = locationInfo.country;
employer.city = locationInfo.city;
}
if (organization && employer.organization && employer.organization !== organization) {
sails.log.info(`Unexpected result when enriching: Matched organization name (${employer.organization}) does not equal the provided "organization" (${organization})`);
}//fi
+64
View File
@@ -0,0 +1,64 @@
module.exports = {
friendlyName: 'Get territory user ID' ,
description: 'Returns a Salesforce User ID who is associated with a location.',
inputs: {
state: { type: 'string' },
city: { type: 'string' },
country: { type: 'string', required: true},
},
exits: {
success: {
outputFriendlyName: 'territoryUserId',
},
},
fn: async function ({state, city, country}) {
// ╦ ╔═╗╔═╗╦╔╗╔ ╔╦╗╔═╗ ╔═╗╔═╗╦ ╔═╗╔═╗╔═╗╔═╗╦═╗╔═╗╔═╗
// ║ ║ ║║ ╦║║║║ ║ ║ ║ ╚═╗╠═╣║ ║╣ ╚═╗╠╣ ║ ║╠╦╝║ ║╣
// ╩═╝╚═╝╚═╝╩╝╚╝ ╩ ╚═╝ ╚═╝╩ ╩╩═╝╚═╝╚═╝╚ ╚═╝╩╚═╚═╝╚═╝
// Log in to Salesforce.
let jsforce = require('jsforce');
let salesforceConnection = new jsforce.Connection({
loginUrl : 'https://fleetdm.my.salesforce.com'
});
await salesforceConnection.login(sails.config.custom.salesforceIntegrationUsername, sails.config.custom.salesforceIntegrationPasskey);
// If the state is not set to California, remove the city (This is the only state that is in two different territories.)
if(state && state.toLowerCase() !== 'california') {
city = undefined;
}
let apexInputs = new URLSearchParams();
if(state) { apexInputs.append('state', state); }
if(country) { apexInputs.append('country', country); }
if(city) { apexInputs.append('city', city); }
let territoryInformation = await sails.helpers.flow.build(async ()=>{
return await salesforceConnection.apex.get(`/territory-lookup?${apexInputs.toString()}`);
}).intercept((err)=>{
throw new Error(`When sending a request to Salesforce to lookup the territory ID for an address (${require('util').inspect({state, city, country})}) an error occurred. Full error: ${require('util').inspect(err)}`);
});
if(!territoryInformation.users || !_.isArray(territoryInformation.users)) {
throw new Error(`When looking up the territory ID for an address (${require('util').inspect({state, city, country})}), the information returned by Salesforce did not include a list of users. Territory information returned by Salesforce: ${require('util').inspect(territoryInformation)}`);
} else if(!territoryInformation.users[0] || !territoryInformation.users[0].userId) {
throw new Error(`When looking up the territory ID for an address (${require('util').inspect({state, city, country})}), the user information returned by Salesforce did not include the required information. Territory information returned by Salesforce: ${require('util').inspect(territoryInformation)}`);
}
let userIdForThisTerritory = territoryInformation.users[0].userId;
// Send back the result through the success exit.
return userIdForThisTerritory;
}
};