Dev Request: Dev Request - Pass Web IDs to HubSpot Contacts - SimpleMDM

Status: Complete
Last updated: November 08, 2022 3:58 PM MST
Originally delivered at: November 19, 2021 5:00 PM MST

Instructions

Motivation

We want to accurately credit marketing efforts, content, and spend for customer acquisition, product purchases and lifetime value.

Because the customer journey often takes place across devices and beyond reliable, cookie-based tracking, we cannot use web analytics data alone for this attribution. We need to join web data (Google Analytics and ad-buying platforms) with CRM data (Hubspot).

Methodology

The way to do this is to join the web and CRM datasets in the data warehouse (Google BigQuery). This requires having foreign keys to join the data sets. We can store the web data keys (to be used as foreign keys) on each Contact record created in Hubspot. This happens when a form is submitted to Hubspot or the Hubspot Contacts API is used to create a contact.

Here is a diagram of what the system integration looks like.

Here is an example of the ways Hubspot Contacts are created in PDQ's scenario. Not all will apply to SimpleMDM and there may be others not shown here.

This process will have two parts:

  • Creating fields on the Hubspot Contact to store the web ids and modifying Hubspot forms/API calls to be include these fields in submissions to Hubspot.
  • Capturing/saving the data (see list below) for including in Contact creation submissions to Hubspot.

Tasks

Task 1: Creating Fields on Hubspot Contacts and Hubspot Forms

The following fields need to be created on Hubspot Contact records and also included on all Hubspot Forms that are currently in use.

Field Machine-Readable (API) Name Field Type Description
Google Analytics Client ID cid Single-Line Text Google Analytics randomly-generated id. Unique per web visitor (approximately, given cookie limitations). Stored in client-side set cookie.
Google Ads Click ID gclid Single-Line Text Google Ads Click ID. Unique per Google Ad Click. Only applicable for Google Ads-visits.
Microsoft Ads Click ID msclkid Single-Line Text Microsoft Ads Click ID. Unique per Microsoft Ad Click. Only applicable for Microsoft Ads-visits.
Reddit Ads Click ID rdt_cid Single-Line Text Reddit Ads Click ID. Unique per Reddit Ad Click. Only applicable for Reddit Ads-visits.
Facebook Ads Click ID fbclid Single-Line Text Facebook Ads Click ID. Unique per Facebook Ad Click. Only applicable for Facebook Ads-visits.
Linked In Ads FAT ID li_fat_id Single-Line Text Linked In ID. Unique per Linked In User (apparently, based on LI docs). Only applicable for some Linked IN Ads-visits.
Full Attribution Mapping attribution_mapping Multi-Line Text Delimited string of all UTMs that lead to this form submission

Task 2: Injecting Field Values Into Hubspot Forms API Submissions

This deserves a real-time discussion to evaluate options.

The Most Typical Scenario adMind Encounters Typically this work is done by creating hidden fields on lead forms and then populating those hidden fields when pages load. adMind has a lightweight, well tested JS library that is loaded through Google Tag Manager for this purpose. The library extracts and stores the necessary fields in localStorage. Then minimal JS is used to read the values from localStorage and inject them in the hidden form fields (where applicable).

According to our review, this won't work for SimpleMDM b/c the contact record creation happens server-side in the code base that serves up a.simplemdm.com.

PDQ is currently importing this library as a vendor dependency in their React application.

Capturing Key Fields in SimpleMDM Code

Option 1: adMind's JS Library Loaded in SimpleMDM Client-Side Code

  • Include adMind code as dependency on www and a
    • Configure code
  • Call adMind code library to retrieve web ids

This is what the PDQ codebase is doing.

Option 2: Recreate adMind Code Functionality This should happen on www and on a

This should be discussed in a grooming meeting.

Appendix

Example Loading and Configuration of adMind Code Library The follwing would be the configuration and library load.

<!-- Config -->
<script>
window._sourcesStoreConfig = {
  additionalParametersToPersist: [
    'effort'
  ],
  callback: function(){
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      'event': 'sourcesStoreLoaded'
    });
    // anything needed to be done after the library is loaded
  }
}
</script>

<!-- Library Script -->
<script src="https://d1m09pg603vjt9.cloudfront.net/assets/js/app.bundle.js"></script>

Once the library is loaded, the data store can be accessed to retrieve the data to include with HubSpot Forms API submissions as follows:

<script>
    (function(){
        var lastSource = window.sourcesStore.getLastNonDirect();
        var cid = lastSource.cid;
        var effort = lastSource.effort;

        // These calls will get the most recent parameter if any, or JS undefined if there is none.
        var gclid = window.sourcesStore.getLastParameter('gclid');
        var msclkid = window.sourcesStore.getLastParameter('msclkid');
        var fbclid = window.sourcesStore.getLastParameter('fbclid');
        var rdt_cid = window.sourcesStore.getLastParameter('rdt_cid');
        var li_fat_id = window.sourcesStore.getLastParameter('li_fat_id');

        // Insert values into Hubspot Forms API form submission call
    })();
</script>