Enrich a contact data in HubSpot using an email /
with the People Data Labs API

25/10/2023

Having quality and accurate data is an absolute imperative for HubSpot users. Precise data is the lifeblood of any successful CRM strategy, and it serves as the foundation for meaningful customer interactions. Inaccurate or outdated information can lead to missed opportunities, ineffective marketing campaigns, and a decrease in overall productivity. As we delve into the power of contact enrichment via third-party APIs, particularly PeopleDataLabs, it becomes evident that integrating high-quality data is not just an option; it's a strategic necessity for optimizing the capabilities of HubSpot CRM.

Concept

The concept is pretty simple, in a WorkFlow you send the person email address to the PeopleDataLabs’ API. If there’s a match in their record we update the contact’s information.

See how it works / and implement it

Set the custom code block

PeopleDataLabs API key

You need to get an API key on the PeopleDataLabs website’s.

You need to set the peopleDataLabsAPI key in the secret, the API key has to be set in the secret section of the Custom Coded Action. Use the name peopleDataLabsAPI

Set the email variable

Set the variable name email in the property to include in code.

Your setup should look like this :

The code ready to implement

Here’s the JavaScript code you can copy paste to the custom code block.

const axios = require('axios');


exports.main = async (event, callback) => {

    if (!process.env.peopleDataLabsAPI) throw new Error('The peopleDataLabs API key has to be set in the secret section');

    if (process.env.peopleDataLabsAPI.trim() === '') throw new Error(`The peopleDataLabs API key can't be empty`);

    const email = event.inputFields.email;

    if (!email) throw new Error('email is not set, are you sure you put email in the "properties to include in code" ? ');

    const personInfos = await getPersonInfos(email).catch(axiosErrorHandler)

    if (!personInfos.data) throw new Error(`We couldn't grab your email infos`);

    if (personInfos.data.status === 404) throw new Error(`The API query worked but we didnd't find any match`);

    if (personInfos.data.status !== 200) throw new Error(`The API query worked but didn't return a 200 status code instead we got ${personInfos.data.status}`);

    if (personInfos.data.total < 1) throw new Error(`The API query worked but no result has been returned`);

    if (!personInfos.data.data) throw new Error(`The API query worked but there's no data`);

    if (personInfos.data.data.length === 0) throw new Error(`The API query worked but no result has been returned, the data array is empty`);


    const {
        full_name,
        first_name,
        middle_initial,
        middle_name,
        last_initial,
        last_name,
        gender,
        birth_year,
        birth_date,
        linkedin_url,
        linkedin_username,
        linkedin_id,
        facebook_url,
        facebook_username,
        facebook_id,
        twitter_url,
        twitter_username,
        github_url,
        github_username,
        work_email,
        personal_emails,
        recommended_personal_email,
        mobile_phone,
        industry,
        job_title,
        job_title_role,
        job_title_sub_role,
        job_title_levels,
        job_onet_code,
        job_onet_major_group,
        job_onet_minor_group,
        job_onet_broad_occupation,
        job_onet_specific_occupation,
        job_onet_specific_occupation_detail,
        job_company_id,
        job_company_name,
        job_company_website,
        job_company_size,
        job_company_founded,
        job_company_industry,
        job_company_linkedin_url,
        job_company_linkedin_id,
        job_company_facebook_url,
        job_company_twitter_url,
        job_company_location_name,
        job_company_location_locality,
        job_company_location_metro,
        job_company_location_region,
        job_company_location_geo,
        job_company_location_street_address,
        job_company_location_address_line_2,
        job_company_location_postal_code,
        job_company_location_country,
        job_company_location_continent,
        job_last_updated,
        job_start_date,
        location_name,
        location_locality,
        location_metro,
        location_region,
        location_country,
        location_continent,
        location_street_address,
        location_address_line_2,
        location_postal_code,
        location_geo,
        location_last_updated,
        phone_numbers,
        emails,
        interests,
        skills,
        location_names,
        regions,
        countries,
        street_addresses,
        experience,
        education,
        profiles,
        version_status
    } = personInfos.data.data[0];


    const personal_email = Array.isArray(personal_emails) ? personal_emails[0] : null

    const phone_number = Array.isArray(phone_numbers) ? phone_numbers[0] : null

    callback({
        outputFields: {
            full_name,
            first_name,
            middle_initial,
            middle_name,
            last_initial,
            last_name,
            gender,
            birth_year,
            birth_date,
            linkedin_url,
            linkedin_username,
            linkedin_id,
            facebook_url,
            facebook_username,
            facebook_id,
            twitter_url,
            twitter_username,
            github_url,
            github_username,
            work_email,
            personal_email,
            recommended_personal_email,
            mobile_phone,
            industry,
            job_title,
            job_title_role,
            job_title_sub_role,
            job_title_levels,
            job_onet_code,
            job_onet_major_group,
            job_onet_minor_group,
            job_onet_broad_occupation,
            job_onet_specific_occupation,
            job_onet_specific_occupation_detail,
            job_company_id,
            job_company_name,
            job_company_website,
            job_company_size,
            job_company_founded,
            job_company_industry,
            job_company_linkedin_url,
            job_company_linkedin_id,
            job_company_facebook_url,
            job_company_twitter_url,
            job_company_location_name,
            job_company_location_locality,
            job_company_location_metro,
            job_company_location_region,
            job_company_location_geo,
            job_company_location_street_address,
            job_company_location_address_line_2,
            job_company_location_postal_code,
            job_company_location_country,
            job_company_location_continent,
            job_last_updated,
            job_start_date,
            location_name,
            location_locality,
            location_metro,
            location_region,
            location_country,
            location_continent,
            location_street_address,
            location_address_line_2,
            location_postal_code,
            location_geo,
            location_last_updated,
            phone_number
        }
    });

}



/**
 * Checks if a given email address is valid.
 *
 * @param {string} email - The email address to be validated.
 * @returns {boolean} True if the email is valid, false otherwise.
 *
 * @example
 * const isEmailValid = isValidEmail("user@example.com");
 * // Returns true
 */
const isValidEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);



/**
 * Gets the personal information of a person from People Data Labs, given their email address.
 *
 * @param email The email address of the person to get information for.
 * @throws {Error} If the email parameter is not a valid string or is empty.
 * @returns {Promise<axios.Response>} A promise that resolves to an axios response object containing the person's information.
 */
const getPersonInfos = async (email) => {

    if (typeof email !== 'string' || email.trim() === '') throw new Error('Invalid email parameter. It must be a non-empty string.');

    if (!isValidEmail(email)) throw new Error('Not a valid email passed as a parameter of the getPersonInfos() function ');

    const endpoint = 'https://api.peopledatalabs.com/v5/person/search';

    const params = {
        "dataset": "email",
        "size": 1,
        "sql": `SELECT * FROM person WHERE (emails.address = '${email}' )`,
        pretty: true,
    };

    const config = {
        headers: {
            'X-Api-Key': process.env.peopleDataLabsAPI,
        },
        params,
    };

    return axios.get(endpoint, config)

}


/**
 * Handles errors thrown by axios requests and logs relevant information.
 *
 * @param {Error} error - The error object thrown by axios.
 */
const axiosErrorHandler = error => {
    if (error.response) {
        // The request was made and the server responded with a status code
        // that falls out of the range of 2xx
        console.log(error.response.data);
        console.log(error.response.status);
        console.log(error.response.headers);
    } else if (error.request) {
        // The request was made but no response was received
        // `error.request` is an instance of XMLHttpRequest in the browser 
        // and an instance of http.ClientRequest in node.js
        console.log(error.request);
    } else {
        // Something happened in setting up the request that triggered an Error
        console.log('Error', error.message);
    }
}

Output

The output should look like this :