GA4 ditched the bounce rate metric from its standard reports — but that doesn't mean you can't calculate it. If you're trying to understand how many visitors leave without engaging, you'll need to build it from session data yourself.
Understanding GA4's Bounce Rate Calculation
GA4 measures engagement differently than Universal Analytics. Bounce rate in GA4 terms is sessions with zero engagement divided by total sessions.
Know what GA4 counts as engaged
A session is "engaged" in GA4 if a user stays longer than 10 seconds, views more than 1 page, or triggers a conversion. Sessions with none of these are bounced sessions. This is different from Universal Analytics, where any pageview counted as non-bounced.
// GA4 counts engagement based on these conditions:
// 1. Session duration > 10 seconds
// 2. 1+ conversion events
// 3. 2+ pages viewed
// If none of these are true = bounced session
const bounceRate = (bouncedSessions / totalSessions) * 100;
// Example: 500 bounced sessions / 2000 total sessions = 25% bounce rateAccess the GA4 Data API
Use the Google Analytics Data API (the modern GA4 API) to pull bounce rate data. You'll need your Property ID from Admin > Property Settings. Set up OAuth credentials or use a service account key.
const { BetaAnalyticsDataClient } = require('google-analytics-data');
const analyticsData = new BetaAnalyticsDataClient({
credentials: require('./service-account-key.json')
});
const request = {
property: `properties/${propertyId}`,
dateRanges: [{
startDate: '2025-01-01',
endDate: '2025-03-26'
}],
dimensions: [{ name: 'date' }],
metrics: [{ name: 'sessions' }, { name: 'engagedSessions' }]
};
const [response] = await analyticsData.runReport(request);sessions and engagedSessions data.Calculate Bounce Rate Using the Reporting API
The GA4 Data API lets you query sessions and engagement data, then compute bounce rate on your end.
Query engaged sessions and total sessions
Request two metrics: sessions (total sessions) and engagedSessions (sessions with engagement). Subtract engaged from total to get bounced sessions, then divide by total for bounce rate percentage.
const request = {
property: `properties/${propertyId}`,
dateRanges: [{
startDate: '2025-01-01',
endDate: '2025-03-26'
}],
dimensions: [],
metrics: [{ name: 'sessions' }, { name: 'engagedSessions' }]
};
const [response] = await analyticsData.runReport(request);
const row = response.rows[0];
const totalSessions = parseInt(row.metricValues[0].value);
const engagedSessions = parseInt(row.metricValues[1].value);
const bouncedSessions = totalSessions - engagedSessions;
const bounceRate = (bouncedSessions / totalSessions) * 100;
console.log(`Bounce rate: ${bounceRate.toFixed(2)}%`);Break it down by landing page and source
Add dimensions like pagePath and sessionSource to see bounce rate per landing page or traffic source. This reveals which pages or channels have the highest abandonment.
const request = {
property: `properties/${propertyId}`,
dateRanges: [{
startDate: '2025-01-01',
endDate: '2025-03-26'
}],
dimensions: [{ name: 'pagePath' }, { name: 'sessionSource' }],
metrics: [{ name: 'sessions' }, { name: 'engagedSessions' }]
};
const [response] = await analyticsData.runReport(request);
response.rows.forEach(row => {
const pagePath = row.dimensionValues[0].value;
const source = row.dimensionValues[1].value;
const total = parseInt(row.metricValues[0].value);
const engaged = parseInt(row.metricValues[1].value);
const bounceRate = ((total - engaged) / total * 100).toFixed(2);
console.log(`${pagePath} (${source}): ${bounceRate}%`);
});Track Custom Bounce Events
If you want GA4 to natively track bounces, fire a custom event when a session meets your bounce criteria.
Implement bounce detection on your frontend
Use the gtag global site tag to fire a custom bounce event when the user leaves without engaging. Define engagement as scroll, click, or staying longer than 10 seconds.
// Detect bounce: user leaves after short visit with no interaction
let isEngaged = false;
const pageLoadTime = Date.now();
// Mark as engaged on user interaction or time threshold
document.addEventListener('scroll', () => { isEngaged = true; }, { once: true });
document.addEventListener('click', () => { isEngaged = true; }, { once: true });
setTimeout(() => { isEngaged = true; }, 10000);
// Fire bounce event via gtag when user leaves without engagement
window.addEventListener('beforeunload', () => {
if (!isEngaged) {
gtag('event', 'user_bounce', {
'event_category': 'engagement',
'session_duration_ms': Date.now() - pageLoadTime
});
}
});Common Pitfalls
- Forgetting that GA4 removed bounce rate as a standard metric — you won't find it in the Explore tab without building it from
sessionsandengagedSessionsdata - Using the old Analytics Reporting API v4 — it doesn't support bounce rate queries. Use the Google Analytics Data API (beta) instead
- Confusing GA4's engagement definition with Universal Analytics — GA4 requires 10+ second session time OR multi-page visit OR conversion to count as non-bounce, not just any pageview
- Not accounting for GA4's 30-minute session timeout — a returning user on the same day counts as a new session, inflating bounce rate
Wrapping Up
GA4's bounce rate isn't baked in anymore, but you can calculate it from engaged and total sessions using the Data API. Track it by page, source, or user segment to identify where visitors are disengaging. If you want to track bounce rate automatically across GA4 and other analytics tools, Product Analyst can help.