Lux Marketing

CRM & Data

Connecting External CDP Data to Anonymous Users in HubSpot Using the Form API

If a customer data platform (CDP) or another tool already tracks your visitors, you can pass its visitor ID into HubSpot, so the two systems can be matched later. Connecting customer data from several sources this way lets you look up a contact’s earlier, anonymous activity in the CDP once they become known in HubSpot. This article shows how to do it with HubSpot’s Forms API.

A shared visitor ID lets HubSpot and your CDP describe the same person

Once both systems carry the same ID, you can:

  1. Personalize marketing campaigns based on external data points
  2. Segment and target audiences more effectively
  3. Enhance lead scoring and prioritization
  4. Improve customer journey mapping and analysis

The Forms API can submit the ID in the background, without a visible form

HubSpot’s Forms API accepts form submissions sent from code. Paired with the visitor’s hubspotutk cookie, a background submission ties your external ID to that visitor’s HubSpot tracking record without asking them to fill anything in.

The example below sends a Mautic contact ID (the mtc_id cookie) into a custom HubSpot property called mautic_id. Mautic is just the example: swap in the cookie and property name of whichever tool holds your visitor ID (Segment’s anonymous ID, your own first-party ID, and so on).

<script>
        // Function to get cookie value by name
        function getCookie(name) {
          var value = "; " + document.cookie;
          var parts = value.split("; " + name + "=");
          if (parts.length == 2) return parts.pop().split(";").shift();
        }

        // Prepare the form data
        function prepareFormData() {
          var mtc_id = getCookie('mtc_id'); // Get mtc_id cookie value
          var hubspotutk = getCookie('hubspotutk'); // Get hubspotutk cookie value

          return JSON.stringify({
            "fields": [
              {
                "objectTypeId": "0-1",
                "name": "mautic_id",
                "value": mtc_id || "" // Use mtc_id as the external unique identifier value or empty string if not found
              }
            ],
            "context": {
              "hutk": hubspotutk, // Include hubspotutk for tracking
              "pageUri": window.location.href,
              "pageName": document.title
            }
          });
        }

        // Function to submit form data
        function submitToHubSpot() {
          // Check if the form has already been submitted by looking up 'hasSubmitted' in localStorage
          if (localStorage.getItem('hasSubmitted') !== 'true') {
            var formData = prepareFormData();
            var endpointUrl = 'https://api.hsforms.com/submissions/v3/integration/submit/XXXX/YYYY'; // Replace XXXX with your HubSpot portal ID and YYYY with your form GUID

            fetch(endpointUrl, {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
              },
              body: formData
            })
            .then(function(response) { return response.json(); })
            .then(function(data) {
              console.log('Form submission successful', data);
              // Set 'hasSubmitted' to 'true' in localStorage to indicate submission has occurred
              localStorage.setItem('hasSubmitted', 'true');
            })
            .catch(function(error) {
              console.error('Form submission error:', error);
            });
          }
        }

        // Run the submission function conditionally
        // Check if the form should not be submitted based on 'hasSubmitted' in localStorage
        if (!window.location.href.includes('gtm') && localStorage.getItem('hasSubmitted') !== 'true') {
          submitToHubSpot();
        }
        </script>

In this code example:

  1. The getCookie function is used to retrieve the values of the mtc_id and hubspotutk cookies.
  2. The prepareFormData function constructs the form data payload to be submitted to HubSpot. It includes the mtc_id value as the external unique identifier in the mautic_id field, along with the hubspotutk value in the context object.
  3. The submitToHubSpot function checks if the form has already been submitted by looking up the hasSubmitted flag in localStorage. If the form hasn’t been submitted, it proceeds with the submission.
  4. The endpointUrl variable should be updated with your HubSpot portal ID (replace XXXX) and the form GUID (replace YYYY) that you want to submit the data to.
  5. The form data is submitted to HubSpot using the Fetch API, with the formData as the request body.
  6. If the submission is successful, a success message is logged to the console, and the hasSubmitted flag is set to 'true' in localStorage to prevent duplicate submissions.
  7. If an error occurs during the submission, an error message is logged to the console.
  8. The submitToHubSpot function is conditionally executed based on the URL and the hasSubmitted flag in localStorage. This ensures that the form is not submitted on certain pages (e.g., GTM pages) and prevents duplicate submissions.

Please note that you need to replace XXXX with your actual HubSpot portal ID and YYYY with the form GUID you want to submit the data to.

Create the mautic_id property (or your own ID property) in HubSpot and add it to the form before you deploy the script, and test it in a sandbox or test portal first.

Run it only with consent, and only once per visitor

  1. Fire the script only after the visitor has accepted analytics or marketing cookies, and mention the data sharing in your privacy policy.
  2. Implement error handling and retry mechanisms to handle potential API failures or network issues.
  3. Avoid submitting duplicate form data by tracking submission status using browser storage or cookies.
  4. Regularly monitor and analyze the integration’s performance and data quality to ensure accuracy and reliability.

Once the visitor becomes a contact, their earlier activity is one lookup away

When the visitor later submits their email, HubSpot links the tracking cookie’s earlier page views to the new contact. Check on a test contact that your ID property came across too; if it didn’t, also send the ID as a hidden field on your real forms. You can then pull that person’s anonymous history from your CDP, which often holds more detail than HubSpot’s own page-view record.

If you also want to send custom events from your CDP into HubSpot (not just the ID), check your HubSpot subscription first: custom behavioral events aren’t available on every tier.

Julio Lopez
About the author

Julio Lopez · Founder & Head of Growth, Lux Marketing

Julio has spent 12+ years in paid media and analytics, and founded Lux in 2018. He has worked with 30+ clients across six industries, from DTC brands and premium wineries to a history museum. As Head of Growth at Glossi, he built the tracking and AI lead scoring behind twice the sign-ups the sales team produced, and he still writes the tracking code himself.

Julio on LinkedIn

Your CRM, ad platforms and analytics can work from the same data.

A RevOps build connects your sales, marketing and customer data so each team reads the same numbers. It starts with a $2,500 audit. Applying takes two minutes, and Julio reviews every application.