xmetric / Use cases

Find the landing pages that waste traffic, from a GA4 export

Divide each page's key events by its sessions, compare that with the rate for the whole site, and multiply the gap by the page's sessions. That number, key events the page would add at your site rate, ranks pages by what fixing them is worth. The site rate is one FIXED expression: { FIXED : SUM([Key events]) } / { FIXED : SUM([Sessions]) }. Drop the CSV you downloaded from Engagement > Landing page below; the # header lines and the totals row are skipped.

Drop your GA4 Landing page CSV

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 pageSessionsKey eventsKey events per sessionRevenue per sessionKey events missed
/blog/how-to-choose-hiking-boots/3,083130.4%0.0342.39
/blog/best-tents-2026/2,596230.9%0.0723.64
/blog/layering-guide/1,32530.2%0.0020.81
/blog/trail-food-ideas/72710.1%0.0112.06
(not set)62800.0%0.0011.28
/4,925811.6%1.337.49
/guides/size-chart/1,209151.2%0.076.72
/guides/returns/43730.7%0.014.85
/stores/denver/34661.7%1.330.22
/shop/hiking-boots/2,817973.4%2.510
/shop/sale/2,044844.1%2.740
/shop/rain-jackets/1,401493.5%3.760
/shop/tents/954272.8%3.130
/stores/portland/27172.6%3.020

By site section

SectionPagesSessionsAvg engagement time (s)Key eventsKey events per sessionRevenue
/blog/47,731111.91400.5%277.93
/shop/47,21691.682573.6%20,919.31
/14,92551.27811.6%6,569.38
/guides/21,64666.2181.1%88.95
(not set)162812.9100.0%0.00
/stores/2617103.4132.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

  1. In Google Analytics, open Reports > Engagement > Landing page.
  2. Pick the date range.
  3. Click Share this report (top right), then Download File > Download CSV. The file holds up to 100,000 rows.
  4. 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

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.