How to pull sessions and page views from GA4
Part of GA4 visitors in your MacBook notch
One request, both metrics
The Data API takes a list, so sessions and page views come back together.
{
"dateRanges": [{ "startDate": "2026-10-01", "endDate": "2026-10-07" }],
"dimensions": [{ "name": "date" }],
"metrics": [{ "name": "sessions" }, { "name": "screenPageViews" }]
}
metricValues in each row is positional, matching the order you asked. Build
a lookup from your own request rather than indexing with a literal, because
reordering the metrics array silently reassigns every reader downstream.
const index = Object.fromEntries(query.metrics.map((m, i) => [m.name, i]));
const sessions = Number(row.metricValues[index.sessions].value);
What a GA4 session is
A session starts with a session_start event and ends after thirty minutes
of inactivity, or at midnight in the property's timezone.
That midnight rule is the one that differs from most tools. A visit spanning midnight is two sessions in GA4, not one. On a consumer product with evening traffic this inflates session counts relative to anything that stitches across the boundary.
The thirty-minute timeout is configurable per property. If somebody changed it, your historical series has a step in it that is not behaviour.
engagedSessions is the one people actually want
GA4 added a definition that Universal Analytics did not have.
| Metric | What it counts |
|---|---|
sessions |
Every session |
engagedSessions |
Lasted 10s+, or had 2+ pageviews, or a conversion |
engagementRate |
Engaged over total |
bounceRate |
1 minus engagement rate |
GA4's bounce rate is therefore the inverse of engagement, not Universal Analytics' single-pageview definition. The two numbers are not comparable and a chart that puts them on one axis across the migration date is wrong.
For most purposes engagedSessions is the more honest traffic figure,
because it excludes the accidental arrivals that a raw session count treats
as visits.
screenPageViews counts repeats
Unlike users, page views are not de-duplicated. A visitor loading the same page five times is five page views, which is what a page view is.
That also means summing daily rows is correct for page views, unlike active users. The two metrics in the same response behave differently under addition, which is a genuinely confusing property of GA4 reporting and worth a comment in whatever code does the summing.
Pages, not just totals
Swap the dimension to get the breakdown:
{
"dimensions": [{ "name": "pagePath" }],
"metrics": [{ "name": "screenPageViews" }],
"orderBys": [{ "metric": { "metricName": "screenPageViews" }, "desc": true }],
"limit": 20
}
pagePath excludes the host and the query string. pagePathPlusQueryString
keeps the query, which fragments your top pages across every UTM variant and
is almost never what you want in a ranking.
Timezone
Every date dimension is bucketed in the property's reporting timezone, which is set in GA4 and not derived from your request. A change to it does not restate history, so a property whose timezone was corrected has a seam.
In the notch
Notch Metrics reports GA4 sessions and page views in the MacBook notch, daily, weekly or monthly, with a sparkline and a comparison against the previous window.
Place them beside active users and the three describe the visit rather than just counting it. Everything Google Analytics reports, or download Notch Metrics.
- google-analytics
- ga4
- api