Skip to main content

Email Platform Integration

Connect GA4 with email marketing platforms (Klaviyo, Mailchimp) for email attribution, campaign analytics, and customer journey tracking.

Why Integrate Email with Analytics?

Key Benefits

| Benefit | Description | |---------|-------------| | Email attribution | Track revenue from email campaigns | | Customer journey | See pre/post email behavior | | Segment sync | Use GA4 audiences in email | | Lifecycle tracking | Email engagement + web behavior | | ROI measurement | True email channel value |

Email Tracking Fundamentals

UTM Parameters

Every email link should include UTM parameters:

https://yoursite.com/products?
  utm_source=klaviyo
  &utm_medium=email
  &utm_campaign=summer_sale
  &utm_content=hero_button
  &utm_term=discount

Standard Naming Convention

| Parameter | Format | Example | |-----------|--------|---------| | utm_source | platform | klaviyo, mailchimp | | utm_medium | email | email | | utm_campaign | campaign_name | summer_sale_2024 | | utm_content | link_location | hero_cta, footer | | utm_term | variant/segment | vip, new_customer |

Klaviyo Integration

Setup UTM Tracking

In Klaviyo, enable automatic UTM tracking:

  1. SettingsUTM Tracking
  2. Enable for all email campaigns
  3. Configure default parameters:
utm_source: klaviyo
utm_medium: email
utm_campaign: {{ campaign.name|slugify }}

Event Sync to GA4

Use Klaviyo webhooks + GA4 Measurement Protocol:

// Server endpoint for Klaviyo webhooks
app.post('/klaviyo-webhook', async (req, res) => {
  const event = req.body;

  // Map Klaviyo events to GA4
  const eventMapping = {
    'Opened Email': 'email_open',
    'Clicked Email': 'email_click',
    'Received Email': 'email_received',
    'Unsubscribed': 'email_unsubscribe'
  };

  const ga4Event = eventMapping[event.event_name];

  if (ga4Event && event.ga_client_id) {
    await fetch('https://www.google-analytics.com/mp/collect', {
      method: 'POST',
      body: JSON.stringify({
        client_id: event.ga_client_id,
        events: [{
          name: ga4Event,
          params: {
            campaign: event.campaign_name,
            email: event.$email
          }
        }]
      })
    });
  }

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

Klaviyo Flow Integration

Track flow-triggered emails:

{% comment %} In Klaviyo email template {% endcomment %}
<a href="{{ item.url }}?
  utm_source=klaviyo
  &utm_medium=email
  &utm_campaign={{ flow.name|slugify }}
  &utm_content={{ event.name|slugify }}">
  Shop Now
</a>

Pass GA4 Client ID to Klaviyo

Capture GA4 client_id when users subscribe:

// On email signup
document.querySelector('#newsletter-form').addEventListener('submit', function(e) {
  const email = document.querySelector('#email').value;
  const clientId = getGA4ClientId();

  // Send to Klaviyo with GA4 client_id
  _learnq.push(['identify', {
    '$email': email,
    'ga_client_id': clientId
  }]);
});

Mailchimp Integration

UTM Configuration

In Mailchimp campaign settings:

  1. SettingsCampaign defaults
  2. Enable Google Analytics link tracking
  3. Or add manual UTMs in link editor

Custom UTM Tags

utm_source=mailchimp
utm_medium=email
utm_campaign=*|CAMPAIGN_UID|*
utm_content=*|PLACEMENT|*

Mailchimp API Integration

// Sync GA4 events to Mailchimp
const mailchimp = require('@mailchimp/mailchimp_marketing');

mailchimp.setConfig({
  apiKey: 'YOUR_API_KEY',
  server: 'us1'
});

async function updateMemberActivity(email, event) {
  const listId = 'YOUR_LIST_ID';
  const subscriberHash = md5(email.toLowerCase());

  await mailchimp.lists.updateListMemberTags(listId, subscriberHash, {
    tags: [{ name: event, status: 'active' }]
  });
}

// Example: Tag based on purchase behavior
updateMemberActivity('[email protected]', 'purchased_recently');

GA4 Audience to Mailchimp

Using Segment or custom integration:

// Export GA4 BigQuery audience to Mailchimp
async function syncAudienceToMailchimp(audienceMembers) {
  for (const member of audienceMembers) {
    await mailchimp.lists.setListMember('list_id', md5(member.email), {
      email_address: member.email,
      status: 'subscribed',
      merge_fields: {
        SEGMENT: member.segment,
        LTV: member.ltv
      }
    });
  }
}

Email Attribution

Last-Click Attribution

Standard GA4 tracks this automatically with UTMs.

Email-Influenced Revenue

Track users who received email before purchasing:

-- BigQuery: Email-influenced purchases
WITH email_sessions AS (
  SELECT
    user_pseudo_id,
    event_timestamp as email_session_time
  FROM `project.analytics.events_*`
  WHERE traffic_source.medium = 'email'
    AND _TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY))
),
purchases AS (
  SELECT
    user_pseudo_id,
    event_timestamp as purchase_time,
    (SELECT value.double_value FROM UNNEST(event_params) WHERE key = 'value') as revenue
  FROM `project.analytics.events_*`
  WHERE event_name = 'purchase'
    AND _TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY))
)
SELECT
  COUNT(DISTINCT p.user_pseudo_id) as purchasers_with_email_touch,
  SUM(p.revenue) as email_influenced_revenue
FROM purchases p
JOIN email_sessions e ON p.user_pseudo_id = e.user_pseudo_id
  AND e.email_session_time < p.purchase_time
  AND e.email_session_time > TIMESTAMP_SUB(TIMESTAMP_MICROS(p.purchase_time), INTERVAL 7 DAY)

View-Through Attribution

Track email opens → purchases (requires email platform integration):

// Data layer for email open tracking pixel
// In email: <img src="https://yoursite.com/email-open?campaign=xyz&user_id=123">

app.get('/email-open', async (req, res) => {
  const { campaign, user_id } = req.query;

  // Store in database or send to GA4
  await storeEmailOpen(user_id, campaign);

  // Return 1x1 transparent GIF
  res.sendFile('transparent.gif');
});

Segment Sync

GA4 Audiences to Email

Create audience in GA4:

  1. AdminAudiencesNew audience
  2. Define conditions (e.g., purchasers in last 30 days)
  3. Export to BigQuery

Sync to email platform:

// Daily sync job
async function syncAudiences() {
  // Query GA4 BigQuery export for audience members
  const audienceMembers = await bigquery.query(`
    SELECT DISTINCT
      user_id,
      user_properties.email
    FROM \`project.analytics.pseudonymous_users_*\`
    WHERE predicted_purchase_probability > 0.7
  `);

  // Sync to Klaviyo
  for (const member of audienceMembers) {
    await klaviyoClient.profiles.createOrUpdate({
      email: member.email,
      properties: {
        high_purchase_intent: true
      }
    });
  }
}

Email Segments to GA4

Pass email segments as user properties:

// On website load, check for Klaviyo profile
if (window._klOnsite && window._klOnsite.length) {
  const profile = window._klOnsite[0];

  if (profile && profile.segments) {
    dataLayer.push({
      event: 'set_user_properties',
      user_properties: {
        email_segment: profile.segments[0],
        email_subscriber: true,
        klaviyo_id: profile.id
      }
    });
  }
}

Email Campaign Analytics

GA4 Campaign Report

Navigate to ReportsAcquisitionTraffic acquisition

  • Filter: medium = email
  • Breakdown by: campaign, source

Custom Email Dashboard

Key metrics to track:

| Metric | Calculation | |--------|-------------| | Sessions from email | Sessions where medium = email | | Email conversion rate | Purchases / Email sessions | | Revenue per email session | Total revenue / Email sessions | | Email contribution | Email revenue / Total revenue |

BigQuery Email Report

-- Email campaign performance
SELECT
  traffic_source.source,
  traffic_source.medium,
  traffic_source.campaign,
  COUNT(DISTINCT user_pseudo_id) as users,
  COUNT(DISTINCT CONCAT(user_pseudo_id, session_id)) as sessions,
  COUNTIF(event_name = 'purchase') as purchases,
  SUM((SELECT value.double_value FROM UNNEST(event_params) WHERE key = 'value')) as revenue,
  SAFE_DIVIDE(COUNTIF(event_name = 'purchase'), COUNT(DISTINCT CONCAT(user_pseudo_id, session_id))) as conv_rate
FROM `project.analytics.events_*`,
UNNEST([
  (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id')
]) as session_id
WHERE traffic_source.medium = 'email'
  AND _TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY))
GROUP BY source, medium, campaign
ORDER BY revenue DESC

Post-Purchase Email Tracking

Order Confirmation Events

// Track order confirmation email sends
dataLayer.push({
  event: 'email_sent',
  email_type: 'order_confirmation',
  transaction_id: 'T12345',
  email_platform: 'klaviyo'
});

Review Request Attribution

Track if reviews came from email requests:

// On review submission
dataLayer.push({
  event: 'review_submitted',
  source: getUTMParam('utm_source') || 'direct',
  email_requested: sessionStorage.getItem('review_email_sent') === 'true'
});

Best Practices

Link Tracking Checklist

  • [ ] All email links have UTM parameters
  • [ ] Consistent naming convention documented
  • [ ] Dynamic parameters for personalization
  • [ ] Unsubscribe links excluded from tracking
  • [ ] Deep links to product pages work correctly

Privacy Compliance

  • [ ] Honor unsubscribe in analytics segments
  • [ ] Don't track users who opt out
  • [ ] Email hashed if stored in analytics
  • [ ] Respect consent preferences

Previous: CRM Integration Next: Advertising Integration