Skip to main content

CRM Integration

Connect Google Analytics 4 with your CRM (HubSpot, Salesforce, Pipedrive) for unified customer analytics and attribution.

Why Integrate CRM with Analytics?

Benefits

| Benefit | Description | |---------|-------------| | Full-funnel visibility | Website → Lead → Opportunity → Customer | | Closed-loop reporting | Tie revenue back to marketing sources | | Lead quality insights | Which sources drive best customers | | Sales enablement | Behavior data for sales teams | | Offline conversion import | Track post-website activities |

Data Flow Architecture

┌─────────────────────────────────────────────────────────┐
│                    Website/App                           │
│                        │                                 │
│                        ▼                                 │
│                   GA4 / GTM                              │
│                   (client_id, gclid, user behavior)     │
└───────────────────────┬─────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────┐
│                       CRM                                │
│              (Lead/Contact records)                      │
│                        │                                 │
│    ┌───────────────────┴───────────────────┐            │
│    │                                       │            │
│    ▼                                       ▼            │
│  Lead Stage Changes              Revenue Data           │
│    │                                       │            │
└────┼───────────────────────────────────────┼────────────┘
     │                                       │
     ▼                                       ▼
┌─────────────────────────────────────────────────────────┐
│         GA4 / Google Ads (Offline Conversions)          │
└─────────────────────────────────────────────────────────┘

HubSpot Integration

Method 1: Native HubSpot Tracking + GA4

Run both tracking systems in parallel:

// Data layer event for both systems
dataLayer.push({
  event: 'form_submit',
  form_name: 'contact_sales',
  // GA4 parameters
  lead_type: 'sales_inquiry',
  lead_value: 100,

  // Include GA4 client_id for HubSpot hidden field
  ga_client_id: getGA4ClientId()
});

// HubSpot form with hidden GA4 field
hbspt.forms.create({
  portalId: 'YOUR_PORTAL_ID',
  formId: 'YOUR_FORM_ID',
  onFormReady: function(form) {
    // Populate hidden fields
    form.querySelector('input[name="ga_client_id"]').value = getGA4ClientId();
    form.querySelector('input[name="gclid"]').value = getGclid();
  }
});

Method 2: Server-Side Sync

Use HubSpot Workflows + Webhooks:

  1. Create Workflow triggered on lifecycle stage change
  2. Send Webhook to your server
  3. Server processes and sends to GA4 Measurement Protocol
// Server endpoint receiving HubSpot webhook
app.post('/hubspot-webhook', async (req, res) => {
  const { email, lifecycleStage, dealAmount, ga_client_id } = req.body;

  // Send to GA4 Measurement Protocol
  await fetch('https://www.google-analytics.com/mp/collect', {
    method: 'POST',
    body: JSON.stringify({
      client_id: ga_client_id,
      events: [{
        name: 'crm_stage_change',
        params: {
          stage: lifecycleStage,
          value: dealAmount
        }
      }]
    })
  });

  res.status(200).send('OK');
});

HubSpot Custom Properties

Create these properties in HubSpot:

| Property | Type | Purpose | |----------|------|---------| | ga_client_id | Single-line text | GA4 anonymous ID | | gclid | Single-line text | Google Ads click ID | | first_touch_source | Single-line text | Attribution | | first_touch_medium | Single-line text | Attribution | | first_touch_campaign | Single-line text | Attribution |

Salesforce Integration

Setup Options

| Method | Best For | Complexity | |--------|----------|------------| | Web-to-Lead with hidden fields | Simple forms | Low | | Salesforce Marketing Cloud | Enterprise | High | | Custom Apex + GA4 MP | Full control | Medium | | Third-party (Segment, etc.) | Existing CDP | Medium |

Web-to-Lead Integration

<!-- Salesforce Web-to-Lead with GA4 data -->
<form action="https://webto.salesforce.com/servlet/servlet.WebToLead" method="POST">
  <input type="hidden" name="oid" value="YOUR_ORG_ID">
  <input type="hidden" name="retURL" value="https://yoursite.com/thank-you">

  <!-- Standard fields -->
  <input type="text" name="first_name" placeholder="First Name">
  <input type="text" name="last_name" placeholder="Last Name">
  <input type="email" name="email" placeholder="Email">

  <!-- GA4 hidden fields (custom Salesforce fields) -->
  <input type="hidden" id="ga_client_id" name="00N..." value="">
  <input type="hidden" id="gclid" name="00N..." value="">
  <input type="hidden" id="utm_source" name="00N..." value="">
  <input type="hidden" id="utm_medium" name="00N..." value="">

  <button type="submit">Submit</button>
</form>

<script>
  // Populate hidden fields
  document.getElementById('ga_client_id').value = getGA4ClientId();
  document.getElementById('gclid').value = getGclid() || '';
  document.getElementById('utm_source').value = getUTMParam('utm_source') || '';
  document.getElementById('utm_medium').value = getUTMParam('utm_medium') || '';
</script>

Salesforce Offline Conversion Import

Create Apex class to send to GA4:

// Apex class for GA4 integration
public class GA4OfflineConversion {

  @future(callout=true)
  public static void sendConversion(String clientId, String eventName, Decimal value) {
    String measurementId = 'G-XXXXXXXXXX';
    String apiSecret = 'YOUR_API_SECRET';

    String endpoint = 'https://www.google-analytics.com/mp/collect?measurement_id='
      + measurementId + '&api_secret=' + apiSecret;

    Map<String, Object> payload = new Map<String, Object>{
      'client_id' => clientId,
      'events' => new List<Map<String, Object>>{
        new Map<String, Object>{
          'name' => eventName,
          'params' => new Map<String, Object>{
            'value' => value,
            'currency' => 'USD'
          }
        }
      }
    };

    Http http = new Http();
    HttpRequest request = new HttpRequest();
    request.setEndpoint(endpoint);
    request.setMethod('POST');
    request.setBody(JSON.serialize(payload));

    HttpResponse response = http.send(request);
  }
}

// Trigger on Opportunity stage change
trigger OpportunityStageChange on Opportunity (after update) {
  for (Opportunity opp : Trigger.new) {
    Opportunity oldOpp = Trigger.oldMap.get(opp.Id);

    if (opp.StageName == 'Closed Won' && oldOpp.StageName != 'Closed Won') {
      // Get related Lead's GA client_id
      String clientId = opp.Lead__r.GA_Client_ID__c;

      if (clientId != null) {
        GA4OfflineConversion.sendConversion(clientId, 'closed_won', opp.Amount);
      }
    }
  }
}

Pipedrive Integration

Using Pipedrive API + Zapier

  1. Capture GA4 data at form submission
  2. Create Person/Deal via Pipedrive API
  3. Trigger Zap on deal stage change
  4. Send to GA4 Measurement Protocol

Custom Fields Setup

Create in Pipedrive:

  • Person field: ga_client_id
  • Person field: gclid
  • Person field: utm_source
  • Person field: utm_medium

Zapier Integration

Trigger: Pipedrive - Deal Stage Changed

Filter: Stage = "Won"

Action: Webhooks by Zapier - POST Request
URL: https://www.google-analytics.com/mp/collect?measurement_id=G-XXX&api_secret=YYY
Body: {
  "client_id": "{{ga_client_id}}",
  "events": [{
    "name": "deal_won",
    "params": {
      "value": {{deal_value}},
      "currency": "USD"
    }
  }]
}

Google Ads Offline Import

From CRM to Google Ads

Requirements:

  • GCLID captured at lead time
  • Conversion action created in Google Ads
  • Stored in CRM with conversion data

Automated Import

# CSV format for Google Ads offline import
Parameters:TimeZone=America/Los_Angeles
Google Click ID,Conversion Name,Conversion Time,Conversion Value,Conversion Currency
abc123def456,SQL,2024-01-15 14:30:00,0,USD
xyz789ghi012,Closed Won,2024-01-20 09:15:00,50000,USD

Upload Methods

| Method | Best For | Frequency | |--------|----------|-----------| | Manual upload | Low volume | Weekly | | Scheduled upload | Medium volume | Daily | | API integration | High volume | Real-time |

Attribution Strategies

Multi-Touch Attribution

Store all touchpoints for accurate attribution:

// Store all touchpoints
function recordTouchpoint() {
  const touchpoint = {
    source: getUTMParam('utm_source') || document.referrer,
    medium: getUTMParam('utm_medium') || 'organic',
    campaign: getUTMParam('utm_campaign'),
    timestamp: new Date().toISOString()
  };

  // Get existing touchpoints
  let touchpoints = JSON.parse(localStorage.getItem('touchpoints') || '[]');
  touchpoints.push(touchpoint);

  // Keep last 10 touchpoints
  localStorage.setItem('touchpoints', JSON.stringify(touchpoints.slice(-10)));
}

// Send all touchpoints with form submission
function getAttributionData() {
  const touchpoints = JSON.parse(localStorage.getItem('touchpoints') || '[]');

  return {
    first_touch: touchpoints[0],
    last_touch: touchpoints[touchpoints.length - 1],
    all_touchpoints: touchpoints
  };
}

CRM Custom Fields for Attribution

| Field | Description | |-------|-------------| | first_touch_source | Original source | | first_touch_date | First visit date | | last_touch_source | Converting source | | touchpoint_count | Number of visits | | days_to_convert | Time from first visit |

Reporting & Analytics

Closed-Loop Reports

| Metric | Calculation | |--------|-------------| | Cost per SQL | Ad spend / SQLs | | Cost per Opportunity | Ad spend / Opportunities | | Cost per Customer | Ad spend / Customers | | Revenue per Source | Total revenue by first_touch_source |

BigQuery Analysis

-- Revenue by original traffic source
SELECT
  crm.first_touch_source,
  crm.first_touch_medium,
  COUNT(DISTINCT crm.contact_id) as customers,
  SUM(crm.lifetime_revenue) as total_revenue,
  AVG(crm.lifetime_revenue) as avg_ltv
FROM `project.crm_data.contacts` crm
WHERE crm.status = 'Customer'
GROUP BY first_touch_source, first_touch_medium
ORDER BY total_revenue DESC

Next: Email Platform Integration