AttributeIQ/
    Docs
    HomePricingSecurity
    HubSpot Integration

    HubSpot Integration

    HubSpot Integration

    Connect HubSpot to see real contact names, company details, and deal values directly in your analytics. Instead of seeing anonymous GA4 client IDs, you’ll see actual people who filled out your forms, their company information, and the value of deals they’re associated with.

    This integration requires a Pro plan or higher. The HubSpot tab will appear in Settings only for users on eligible plans.

    Setup Overview

    There are five steps. Complete them in order, each one depends on the last.

    1

    Connect HubSpot

    2

    GA4 Property

    3

    Tracking Script

    4

    Form Setup

    5

    Sync Contacts

    Step 1: Connect Your HubSpot Account

    The first thing to do is authorise AttributeIQ to read your HubSpot contacts and deals. This is a one-time OAuth flow, you’ll never need to do it again.

    How to connect

    1

    In your app, go to Settings → Integrations → HubSpot

    2

    Click Connect HubSpot and complete the OAuth authorisation

    3

    You’ll be redirected back and should see a “Connected” status with your portal ID

    Step 2: GA4 Client ID Property in HubSpot

    AttributeIQ automatically creates the ga4_client_id contact property in your HubSpot account when you connect in Step 1. In most cases you don’t need to do anything here.

    If the automatic creation fails, for example, due to HubSpot permission restrictions, follow the manual steps below.

    Manual setup

    1

    Log into HubSpot and click the settings gear in the top-right corner

    2

    Go to Properties → Contact properties

    3

    Click Create property

    4

    Set Label to GA4 Client ID

    5

    Set Internal name to exactly ga4_client_id, this must match precisely

    6

    Set Field type to Single-line text, then click Create

    Step 3: Add the Tracking Script to Your Website

    This script does three things: it captures the visitor’s GA4 client ID, tracks every page visit to build a session journey, and, when someone submits a HubSpot embedded form, links their email to their session automatically.

    Paste this script into your website’s <head> section, replacing G-XXXXXXXXXX with your GA4 Measurement ID.

    Tracking script

    <!-- AttributeIQ + GA4 tracking -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
    <script>
      /* ── Base GA4 setup ──────────────────────────────────────── */
      window.dataLayer = window.dataLayer || [];
      function gtag() { dataLayer.push(arguments); }
      gtag('js', new Date());
      gtag('config', 'G-XXXXXXXXXX');
    
      /* ── Persistent user ID ──────────────────────────────────── */
      function getOrCreatePersistentUserId() {
        let persistentId = localStorage.getItem('persistent_user_id');
        if (!persistentId) {
          persistentId = 'user_' + Date.now() + '_' + Math.random().toString(36).substring(2, 10);
          localStorage.setItem('persistent_user_id', persistentId);
        }
        return persistentId;
      }
      const persistentUserId = getOrCreatePersistentUserId();
    
      /* ── GA4 client ID capture ───────────────────────────────── */
      gtag('get', 'G-XXXXXXXXXX', 'client_id', (id) => {
        window.ga4ClientId = id;
        localStorage.setItem('ga4_client_id', id);
        console.log('AttributeIQ: GA4 Client ID captured:', id);
      });
    
      /* ── Page visit tracking ─────────────────────────────────── */
      function trackPage() {
        const id = localStorage.getItem('ga4_client_id') || window.ga4ClientId;
        if (!id) return;
        fetch('https://attribute-iq.com/api/track/track-page-visit', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ pageUrl: location.href, ga4ClientId: id, persistentUserId: persistentUserId }),
        }).catch(() => {});
      }
    
      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', trackPage);
      } else { trackPage(); }
    
    
      /* ── HubSpot embedded form tracking ────────────────────────
         Only relevant if you use HubSpot's embedded forms.
         This handles injecting the GA4 ID into the form payload
         and capturing identity once the form is submitted.
         If you only use custom HTML forms, this block is inactive
         but harmless to leave in.
      ─────────────────────────────────────────────────────────── */
    
      window.addEventListener('message', function(e) {
        if (e.data?.type !== 'hsFormCallback') return;
    
        if (e.data.eventName === 'onBeforeFormSubmit' && Array.isArray(e.data.data)) {
          const id = localStorage.getItem('ga4_client_id') || window.ga4ClientId;
          if (id) {
            e.data.data.push({ name: 'ga4_client_id', value: id });
          }
        }
    
        if (e.data.eventName === 'onFormSubmit') {
          const email = e.data.data?.find(function(f) { return f.name === 'email'; })?.value;
          const id = localStorage.getItem('ga4_client_id') || window.ga4ClientId;
          if (email && id) {
            fetch('https://attribute-iq.com/api/track/capture-identity', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({
                email: email,
                ga4_client_id: id,
                persistent_user_id: persistentUserId,
                property_id: 'default'
              }),
            }).catch(() => {});
          }
        }
      });
    </script>

    Verify the Script is Working

    Script is live on your site

    Paste the script into your <head>, publish, and load any page.

    GA4 client ID is being captured

    Open your browser’s developer console (F12). You should see “AttributeIQ: GA4 Client ID captured: xxx”.

    HubSpot embedded forms are tracked

    Submit a test HubSpot form. The contact in HubSpot should have the GA4 Client ID field populated.

    Step 4: Custom Form Setup (Optional)

    If you use HubSpot embedded forms, the script from Step 3 already handles everything, skip ahead to Step 5. If you have custom HTML forms that use JavaScript to submit data directly to HubSpot’s API, follow the steps below to connect them.

    Setting up a custom HTML form

    1

    In HubSpot go to Marketing → Forms and click Create form

    2

    Add a field for each field on your front-end form. The internal name of each field must exactly match what you pass in the snippet’s fields array, for example, firstname, email, message

    3

    Add one more field: search for ga4_client_id and select it, then set it as a Hidden field

    4

    Save and publish the form. Copy the form GUID from the URL, it looks like xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

    5

    In the snippet below, replace YOUR_FORM_GUID with your form GUID, update the fields array to match your form, and replace YOUR_FORM_SELECTOR with your form’s CSS selector (e.g. .contact-form form)

    6

    Paste the snippet into the <head> of the page where your form lives

    Custom form snippet

    document.addEventListener('DOMContentLoaded', function() {
    
      // Replace YOUR_FORM_SELECTOR with your form's CSS selector
      // e.g. '.contact-form form', '#signup form', '.hero-form form'
      const form = document.querySelector('YOUR_FORM_SELECTOR');
      if (!form) return;
    
      form.addEventListener('submit', function(e) {
    
        // Add a line here for each field in your form
        const name    = form.querySelector('input[name="name"]')?.value || '';
        const email   = form.querySelector('input[type="email"]')?.value || '';
        const subject = form.querySelector('select[name="subject"]')?.value || '';
        const message = form.querySelector('textarea[name="message"]')?.value || '';
    
        // These are set automatically by the main script, do not change
        const ga4ClientId      = localStorage.getItem('ga4_client_id') || window.ga4ClientId;
        const persistentUserId = localStorage.getItem('persistent_user_id');
    
        if (!email || !ga4ClientId) return;
    
        // Link this visitor’s email to their GA4 session
        fetch('https://attribute-iq.com/api/track/capture-identity', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            email: email,
            ga4_client_id: ga4ClientId,
            persistent_user_id: persistentUserId,
            property_id: 'default'
          })
        }).catch(() => {});
    
        // Send form data to HubSpot
        // Replace YOUR_PORTAL_ID and YOUR_FORM_GUID with your values
        // Update the fields array to match your form’s internal names
        fetch('https://api.hsforms.com/submissions/v3/integration/submit/YOUR_PORTAL_ID/YOUR_FORM_GUID', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            fields: [
              { name: 'firstname',    value: name    },
              { name: 'email',        value: email   },
              { name: 'subject',      value: subject },
              { name: 'message',      value: message },
              { name: 'ga4_client_id', value: ga4ClientId }, // always include this
            ],
            context: { pageUri: window.location.href, pageName: document.title }
          })
        }).catch(() => {});
    
      });
    });

    Step 5: Sync Contacts

    With everything in place, run your first sync to pull contacts from HubSpot. AttributeIQ will import every contact that has a ga4_client_id property populated and match them to their session journeys.

    Running a sync

    1

    In the HubSpot tab, click Sync now

    2

    Wait for the sync to complete, you’ll see a “Synced X contacts” confirmation

    3

    Go to Journey Explorer. Within 2–3 minutes, anonymous IDs will be replaced with real contact names

    Contacts sync automatically every 6 hours. Click Sync now at any time for an immediate update.

    Troubleshooting

    GA4 client ID not appearing in HubSpot

    Possible causes

    • The ga4_client_id property hasn’t been created in HubSpot
    • The property’s internal name doesn’t match ga4_client_id exactly
    • The form doesn’t include the ga4_client_id field
    • The field hasn’t been added as a hidden field in the HubSpot form builder

    Solution: Verify the property exists with the correct internal name. Add it as a hidden field to your HubSpot form.

    Sync returns 0 contacts

    Possible causes

    • No contacts in HubSpot have the ga4_client_id property populated yet
    • The HubSpot connection token has expired or been revoked
    • The ga4_client_id property doesn’t exist in your HubSpot account

    Solution: Submit a test form first to create a contact with a GA4 client ID, then re-run the sync.

    No contact names in Journey Explorer

    Possible causes

    • A sync hasn’t been run since the contacts were created
    • The GA4 client ID in the journey doesn’t match any synced contact
    • The contact’s GA4 client ID was populated after the last sync

    Solution: Run a manual sync in Settings → HubSpot. Wait 2–3 minutes and refresh Journey Explorer.

    On this page