Engagement Rate is one of GA4's core metrics, but it's calculated differently than you might expect. Understanding what counts as an engaged session—and why some traffic doesn't register—is essential for reading your analytics correctly.
How GA4 Defines Engagement
GA4 considers a session "engaged" when it meets at least one of three criteria. This is fundamentally different from older analytics tools that relied on time-on-page or scroll depth alone.
Understand the Three Engagement Conditions
A session is engaged if it lasts 10 seconds or longer, includes 2 or more events, or triggers 1 or more conversion event. If none of these happen, GA4 marks it as a non-engaged session. This means a 9-second bounce counts as non-engaged, even if the user scrolled or clicked. It also means a single-event session (like viewing a page and leaving) is non-engaged unless you've marked that event as a conversion.
Query Engagement Rate via the Data API
Use the Google Analytics Data API to fetch engagement metrics programmatically. You'll need your GA4 property ID (found in Admin > Property > Property ID) and an OAuth 2.0 access token with analytics reporting permission. This approach lets you pull engagement data into dashboards or applications without logging into GA4 every time.
async function getEngagementRate() {
const response = await fetch('https://analyticsdata.googleapis.com/v1beta/properties/YOUR_PROPERTY_ID:runReport', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
dateRanges: [{ startDate: '30daysAgo', endDate: 'today' }],
metrics: [{ name: 'engagementRate' }],
dimensions: [{ name: 'date' }],
}),
});
const data = await response.json();
return data.rows;
}Segment Engagement by Traffic Source and Device
Compare engagement across traffic sources (organic, paid, direct, social) and devices (mobile, desktop, tablet) to identify which channels drive the most engaged traffic. Add dimensions to your Data API request to break down the metric. For example, if organic search has 65% engagement but paid search has 40%, you know organic traffic is higher quality—or at least more aligned with what your site offers.
const request = {
dateRanges: [{ startDate: '30daysAgo', endDate: 'today' }],
metrics: [
{ name: 'engagementRate' },
{ name: 'engagedSessions' },
{ name: 'sessions' },
],
dimensions: [
{ name: 'sessionSource' },
{ name: 'deviceCategory' },
],
orderBys: [{
metric: { metricName: 'engagementRate' },
desc: true,
}],
};
// Pass this to your runReport request bodyViewing Engagement in the GA4 Console
You don't need an API to find engagement metrics. GA4 provides built-in reports and exploration tools that show engagement data without code.
Check the User Engagement Report
Navigate to Reports > User engagement in the left sidebar. You'll see cards for Engagement rate, Engaged sessions, and Engagement rate by session source. This is the fastest way to see if your site is resonating with visitors. The default view covers the last 28 days, but you can click the date range to adjust.
Build a Custom Engagement Report in Explore
If the built-in reports don't answer your question, use Explore > Blank exploration. Drag Engagement rate into the Metrics area, then add dimensions like Page title, User default channel group, or Country to see where engagement is highest. You can filter by device type or traffic source to dig deeper. This replicates a full Data API query without writing code.
// Programmatic equivalent of a custom Explore report
const exploreRequest = {
dateRanges: [{ startDate: '7daysAgo', endDate: 'today' }],
metrics: [{ name: 'engagementRate' }, { name: 'engagedSessions' }],
dimensions: [{ name: 'pageTitle' }, { name: 'userDefaultChannelGroup' }],
limit: 25,
orderBys: [{
metric: { metricName: 'engagementRate' },
desc: true,
}],
};
// Shows top 25 pages by engagement with channel breakdownCreate a Segment for Engaged Sessions
Use Admin > Custom definitions > Create custom segment to build a segment that isolates engaged sessions. For example, create a segment where session engagement == 1 to see only users in sessions that met at least one engagement threshold. Then compare this segment against non-engaged traffic in your reports to spot behavioral differences.
Tracking Custom Engagement Events
If the default engagement rules don't fit your business model, implement event tracking to define what counts as meaningful engagement for your site.
Log Engagement Events with gtag.js
Use the gtag() function to fire events that signal user engagement. For example, log when users scroll, click a button, or submit a form. GA4 automatically counts any session with 2+ events as engaged (assuming other conditions are met). This gives you finer control over what "engagement" means for your product. Make sure gtag.js is installed in your page header via Google Tag Manager or directly in your HTML.
// Track scroll depth as engagement
gtag('event', 'scroll', {
'percent_scrolled': 75,
});
// Track form submission as engagement
gtag('event', 'form_submit', {
'form_name': 'contact',
'form_id': 'contact-footer',
});
// Track content interaction
gtag('event', 'view_item', {
'item_name': 'Feature Comparison',
'item_category': 'guide',
});
// Log time spent (in milliseconds)
gtag('event', 'engagement', {
'engagement_time_msec': 45000,
});Send Server-Side Events via the Measurement Protocol
If you're tracking engagement from your backend (API interactions, email opens, payment confirmations), use the Measurement Protocol. This lets you send events directly to GA4 without relying on browser-side tracking. You'll need your GA4 measurement ID and API secret, both available in Admin > Data streams.
async function sendEngagementEvent(clientId, eventName) {
const payload = {
api_secret: process.env.GA4_API_SECRET,
measurement_id: process.env.GA4_MEASUREMENT_ID,
client_id: clientId,
events: [{
name: eventName,
params: {
session_id: 'session-123',
engagement_time_msec: 30000,
currency: 'USD',
value: 99.99,
},
}],
};
const response = await fetch('https://www.google-analytics.com/mp/collect', {
method: 'POST',
body: JSON.stringify(payload),
});
return response.ok;
}client_id consistently to ensure events are grouped into the same session. Also, Measurement Protocol events are processed asynchronously—they may appear in GA4 reports with a 24–48 hour delay.Common Pitfalls
- Ignoring non-engaged sessions. These are still real traffic and may indicate content misalignment or poor UX. Don't exclude them from analysis—investigate why they're not meeting engagement thresholds.
- Confusing engagement rate with bounce rate. Bounce rate is 100% - (sessions with 2+ events / all sessions). Engagement rate includes conversion events even if there's only 1 event. The metrics measure different things.
- Relying on pageviews without event tracking. In GA4, pageviews aren't sent automatically—you must configure a page_view event in GTM or manually call gtag('event', 'page_view'). If this is broken, engagement metrics are meaningless.
- Not marking conversion events explicitly. A session with a single purchase has 2+ events only if you've set purchase as a conversion event in GA4. Without conversion tagging, single-event sessions won't be marked as engaged.
Wrapping Up
Engagement Rate in GA4 measures the percentage of sessions that meet at least one engagement threshold: 10+ seconds, 2+ events, or 1+ conversion. Use the Data API to automate reporting, check the User engagement report for quick wins, and implement custom event tracking when the defaults don't match your product. If you want to track this automatically across tools, Product Analyst can help.