GA4 tracks where your users come from, but the default Acquisition report only shows top-level sources. If you need to visualize acquisition patterns across custom dimensions, track specific onboarding events, or build a real-time acquisition dashboard, you'll need to set up your data collection and then query it strategically.
Ensure acquisition events are firing
GA4 automatically tracks first_visit and session_start events, but you need to make sure you're capturing the right context. The Events > Event name report will show you what's actually being recorded.
Send user context with first-visit events
When a user lands for the first time, send their source info as user properties. GA4 captures traffic_source automatically, but you can add custom properties like signup_source or utm_campaign. Use gtag.set() to attach these before the event fires.
// Set user properties on first visit
gtag('set', {
'user_id': userId,
'user_properties': {
'signup_source': 'email_campaign',
'cohort_month': 'march_2026'
}
});
// Optionally send a custom acquisition event
gtag('event', 'user_signup', {
'campaign': 'spring_promo',
'medium': 'email'
});Use the Measurement Protocol for server-side acquisitions
If users are acquired server-side (API signups, partner integrations), send events via the Google Analytics Measurement Protocol. This bypasses the browser and lets you control exactly what gets recorded.
// Server-side: send acquisition event via Measurement Protocol
const fetch = require('node-fetch');
async function logAcquisition(userId, source) {
await fetch(
`https://www.google-analytics.com/mp/collect?measurement_id=G_XXXXXXXXXX&api_secret=YOUR_API_SECRET`,
{
method: 'POST',
body: JSON.stringify({
client_id: userId,
events: [
{
name: 'acquisition_event',
params: {
engagement_time_msec: '100',
source_type: source,
session_id: Date.now()
}
}
]
})
}
);
}
logAcquisition('user123', 'api_partner');Create visualizations in GA4
Once your data is flowing, use the GA4 interface to build acquisition reports and custom explorations.
View the built-in Acquisition report
Start with Reports > Acquisition > Overview to see traffic source, medium, campaign, and session counts. This gives you a baseline breakdown. If you need more dimensions (like custom user properties), you'll need to build a custom report.
// The Acquisition > Overview report pulls session_start events
// with dimensions: traffic_source.source, traffic_source.medium, traffic_source.campaign
// and metrics: sessions, active_users
//
// You access this data programmatically via the Google Analytics Data API:
const request = {
property: `properties/${propertyId}`,
dateRanges: [{startDate: '2026-03-01', endDate: '2026-03-26'}],
dimensions: [
{name: 'trafficsource_source'},
{name: 'trafficsource_medium'}
],
metrics: [{name: 'sessions'}, {name: 'activeUsers'}]
};Build a custom exploration with dimensions and metrics
Go to Explore (left sidebar) and create a new blank exploration. Add traffic_source.source and traffic_source.campaign as row dimensions, and use Active Users or Sessions as your metric. Drag to a table or chart visualization to compare acquisition sources.
// In a custom GA4 Exploration, combine multiple dimensions and metrics:
const customExploration = {
property: `properties/${propertyId}`,
dateRanges: [{startDate: '2026-03-01', endDate: '2026-03-26'}],
dimensions: [
{name: 'trafficsource_source'},
{name: 'trafficsource_campaign'},
{name: 'deviceCategory'} // Optional: add device dimension
],
metrics: [
{name: 'sessions'},
{name: 'activeUsers'},
{name: 'userConversionRate'}
],
// Filter to only email campaign acquisitions:
dimensionFilter: {
filter: {
fieldName: 'trafficsource_campaign',
stringFilter: {matchType: 'BEGINS_WITH', value: 'email'}
}
}
};Query acquisition data via the Google Analytics Data API
For dashboards, automated reports, or deeper analysis, use the Google Analytics Data API v1. This lets you pull acquisition data into custom tools or BI platforms.
Install the client library and authenticate
Install the Google Analytics Data API client for Node.js, then authenticate with a service account JSON key. Store your Property ID (found in GA4 settings) and API secret securely.
// Install: npm install @google-analytics/data
const {BetaAnalyticsDataClient} = require('@google-analytics/data');
// Authenticate with service account
const analyticsDataClient = new BetaAnalyticsDataClient({
keyFilename: './service-account-key.json'
});
const propertyId = '123456789'; // Your GA4 Property IDQuery acquisition metrics by source and campaign
Use the runReport() method to fetch sessions and users grouped by traffic source and campaign. This is equivalent to the Acquisition report but in JSON format, which you can feed into charts or dashboards.
async function getAcquisitionData() {
const [response] = await analyticsDataClient.runReport({
property: `properties/${propertyId}`,
dateRanges: [
{
startDate: '2026-03-01',
endDate: '2026-03-26'
}
],
dimensions: [
{name: 'trafficsource_source'},
{name: 'trafficsource_campaign'}
],
metrics: [
{name: 'sessions'},
{name: 'activeUsers'},
{name: 'newUsers'}
]
});
response.rows.forEach(row => {
const [source, campaign] = row.dimensions;
const [sessions, users, newUsers] = row.metricValues.map(m => m.value);
console.log(`${source} / ${campaign}: ${sessions} sessions, ${newUsers} new`);
});
}
getAcquisitionData();Filter by custom user properties
Add a dimensionFilter to segment acquisition by custom properties like signup_source. This lets you isolate acquisitions from specific campaigns or partner channels.
async function getEmailCampaignAcquisitions() {
const [response] = await analyticsDataClient.runReport({
property: `properties/${propertyId}`,
dateRanges: [
{startDate: '2026-03-01', endDate: '2026-03-26'}
],
dimensions: [
{name: 'userProperties_signup_source'},
{name: 'trafficsource_medium'}
],
metrics: [{name: 'activeUsers'}],
dimensionFilter: {
filter: {
fieldName: 'userProperties_signup_source',
stringFilter: {
matchType: 'EXACT',
value: 'email_campaign'
}
}
},
orderBys: [{metric: {metricName: 'activeUsers'}, desc: true}]
});
return response;
}
getEmailCampaignAcquisitions();orderBys to sort your results—this shows your top acquisition sources first without manual post-processing.Common Pitfalls
- Custom events take 24–48 hours to appear in standard reports. If they're not showing up immediately, check the Real-time report and the Events > Event name debug view.
- GA4's Acquisition report only shows the first traffic source (session-level attribution). If a user clicked an ad, then returned organic, the session is attributed to the ad. Use custom explorations with multiple dimensions to see the full picture.
- The Measurement Protocol requires your Measurement ID and API Secret. If you get a 400 error, double-check the endpoint URL and that both values are correct. Measurement IDs start with
G_. - GA4 has a 10-dimension limit per report. If you're trying to combine too many dimensions (source, campaign, device, country, custom property), you'll hit this limit. Use filters instead of adding more dimensions.
Wrapping Up
You now have acquisition data flowing into GA4, visualizations built in the interface, and API access for custom dashboards. The Acquisition report gives you the quick view; Explore lets you dig deeper into custom dimensions; the Data API automates reporting. If you want to track acquisition touchpoints across multiple tools and consolidate them into a single view, Product Analyst can help.