Landing pages ranked by key events missed, and sections compared
A made-up Landing page download for an outdoor shop: 14 pages, with the # comment lines and totals row a typical download starts with. The sample is synthetic and uses the report's documented dimension and metrics. Computed from ga4-landing-page.csv (13 rows of made-up data). The Tableau calculation and the SQL below both produce these numbers.
Landing pages, by key events missed
| Landing page | Sessions | Key events | Key events per session | Revenue per session | Key events missed |
|---|---|---|---|---|---|
| /blog/how-to-choose-hiking-boots/ | 3,083 | 13 | 0.4% | 0.03 | 42.39 |
| /blog/best-tents-2026/ | 2,596 | 23 | 0.9% | 0.07 | 23.64 |
| /blog/layering-guide/ | 1,325 | 3 | 0.2% | 0.00 | 20.81 |
| /blog/trail-food-ideas/ | 727 | 1 | 0.1% | 0.01 | 12.06 |
| (not set) | 628 | 0 | 0.0% | 0.00 | 11.28 |
| / | 4,925 | 81 | 1.6% | 1.33 | 7.49 |
| /guides/size-chart/ | 1,209 | 15 | 1.2% | 0.07 | 6.72 |
| /guides/returns/ | 437 | 3 | 0.7% | 0.01 | 4.85 |
| /stores/denver/ | 346 | 6 | 1.7% | 1.33 | 0.22 |
| /shop/hiking-boots/ | 2,817 | 97 | 3.4% | 2.51 | 0 |
| /shop/sale/ | 2,044 | 84 | 4.1% | 2.74 | 0 |
| /shop/rain-jackets/ | 1,401 | 49 | 3.5% | 3.76 | 0 |
| /shop/tents/ | 954 | 27 | 2.8% | 3.13 | 0 |
| /stores/portland/ | 271 | 7 | 2.6% | 3.02 | 0 |
By site section
| Section | Pages | Sessions | Avg engagement time (s) | Key events | Key events per session | Revenue |
|---|---|---|---|---|---|---|
| /blog/ | 4 | 7,731 | 111.91 | 40 | 0.5% | 277.93 |
| /shop/ | 4 | 7,216 | 91.68 | 257 | 3.6% | 20,919.31 |
| / | 1 | 4,925 | 51.27 | 81 | 1.6% | 6,569.38 |
| /guides/ | 2 | 1,646 | 66.2 | 18 | 1.1% | 88.95 |
| (not set) | 1 | 628 | 12.91 | 0 | 0.0% | 0.00 |
| /stores/ | 2 | 617 | 103.4 | 13 | 2.1% | 1,278.53 |
Recompute it from your CSV
Download the Landing page report as CSV and drop it here. Lines that start with # are skipped, the table ends at the first blank line, and the totals row (an empty or Grand total first cell) is left out so nothing is counted twice. Match the columns if your report uses other names. The file is read in this browser; nothing is uploaded.
No file loaded yet. You can also drop a CSV on this box.
Why rank by key events missed, not by rate
Sorting by key event rate puts a page with 40 sessions and 3 key events at the top and hides a blog post with 3,000 sessions and 13. Key events missed weighs both: a low rate only matters when a lot of sessions land there. Blog and guide pages often rank high because they bring readers who were never going to buy on that visit; that's a reason to add a next step on those pages, not proof they're broken.
The section table adds pages together. Its engagement time is weighted by sessions: averaging the Average engagement time per session column across pages counts a page with 50 sessions the same as one with 5,000.
Download the Landing page report from GA4
- In Google Analytics, open Reports > Engagement > Landing page.
- Pick the date range.
- Click Share this report (top right), then Download File > Download CSV. The file holds up to 100,000 rows.
- Drop it in the box above.
Menu path and row limit from Google's help pages on the Landing page report and downloading report data, checked 2026-10-18. The report's default columns are Landing page, Sessions, Active users, New users, Average engagement time per session, Key events and Total revenue; this page uses five of them.
Google doesn't document the file's layout. A typical download starts with # comment lines (report name, property, date range), then a blank line, the header row and a totals row. The box above skips all of that; if your file has a different layout, the column matching still works once the header row is found.
The Tableau calculation
Landing pages, by key events missed
On Rows: [Landing page]. Each calculation below is one column.
// Site key events per session
{ FIXED : SUM([Key events]) } / { FIXED : SUM([Sessions]) }
// Sessions
SUM([Sessions])
// Key events
SUM([Key events])
// Key events per session
SUM([Key events]) / SUM([Sessions])
// Revenue per session
SUM([Total revenue]) / SUM([Sessions])
// Key events missed: what the page would add at the site rate
IIF(SUM([Sessions]) * MIN([Site key events per session]) > SUM([Key events]), SUM([Sessions]) * MIN([Site key events per session]) - SUM([Key events]), 0)By site section
On Rows: [Section]. Each calculation below is one column.
// Section IF LEFT([Landing page], 1) <> '/' THEN [Landing page] ELSEIF [Landing page] = '/' THEN '/' ELSE '/' + SPLIT([Landing page], '/', 2) + '/' END // Pages COUNTD([Landing page]) // Sessions SUM([Sessions]) // Average engagement time per session, weighted by sessions SUM([Average engagement time per session] * [Sessions]) / SUM([Sessions]) // Key events SUM([Key events]) // Key events per session SUM([Key events]) / SUM([Sessions]) // Revenue SUM([Total revenue])
The equivalent SQL
Landing pages, by key events missed
WITH pages AS (
SELECT * FROM read_csv('ga4-landing-page.csv', comment = '#', header = true)
WHERE "Landing page" IS NOT NULL AND "Landing page" NOT IN ('Grand total', 'Total', 'Totals')
), site AS (
SELECT SUM("Key events") / SUM("Sessions") AS rate FROM pages
)
SELECT "Landing page",
SUM("Sessions") AS sessions,
SUM("Key events") AS key_events,
SUM("Key events") / SUM("Sessions") AS key_events_per_session,
SUM("Total revenue") / SUM("Sessions") AS revenue_per_session,
GREATEST(SUM("Sessions") * MIN(site.rate) - SUM("Key events"), 0) AS key_events_missed
FROM pages, site
GROUP BY "Landing page"
ORDER BY key_events_missed DESC, sessions DESC;By site section
WITH pages AS (
SELECT * FROM read_csv('ga4-landing-page.csv', comment = '#', header = true)
WHERE "Landing page" IS NOT NULL AND "Landing page" NOT IN ('Grand total', 'Total', 'Totals')
)
SELECT CASE WHEN left("Landing page", 1) <> '/' THEN "Landing page"
WHEN "Landing page" = '/' THEN '/'
ELSE '/' || split_part("Landing page", '/', 2) || '/' END AS section,
COUNT(DISTINCT "Landing page") AS pages,
SUM("Sessions") AS sessions,
SUM("Average engagement time per session" * "Sessions") / SUM("Sessions") AS avg_engagement_seconds,
SUM("Key events") AS key_events,
SUM("Key events") / SUM("Sessions") AS key_events_per_session,
SUM("Total revenue") AS revenue
FROM pages
GROUP BY section
ORDER BY sessions DESC;Before you rewrite a page
- (not set) appears when a session has no page view before its other events. Leave it out of decisions about pages; it still counts toward the site rate here, which you can change by filtering it out first.
- Key events are a count of events, not of converting sessions. One session that fires three key events counts three times. GA4's
Session key event ratecounts converting sessions instead; this page doesn't use it because it can't be added up across pages. - Query strings: the Landing page dimension drops them. If you exported
Landing page + query string, the same page appears once per tracking parameter; group them withSPLIT([Landing page + query string], '?', 1).
Google Analytics is a trademark of Google LLC. xmetric is not affiliated with Google. The sample file is synthetic: made-up pages and numbers in the layout of a typical GA4 Landing page download, using the report's dimension and metrics as documented on 2026-10-18.
Questions people ask
Why does adding up the Sessions column give me more than GA4 shows?
A typical download includes a totals row under the header. The box above drops rows whose first cell is empty or reads Grand total, and the SQL keeps only rows with a landing page.
Can I use an Exploration export instead?
Yes, if it has a landing page column, sessions and key events. Match the columns in the box. Explorations can also download as TSV; save it as CSV first.
Is my analytics data uploaded?
No. The CSV is read and calculated in this browser tab; nothing is sent anywhere.
Related: traffic sources from a GA4 export, weighted averages by group, FIXED expressions, SPLIT.