Where do people go before they abandon their cart?

Written by
Jules Stuifbergen
Reading progress

Cart abandonment is one of those things everyone knows is a problem and nobody fully understands. The usual dashboard tells you the rate. It doesn’t tell you why.

A CRO manager worth their salt wants to know more than “68% of carts are abandoned.” They want to know: what did those people do right before they left? Was it the shipping page? The login prompt? Some random blog post that distracted them?

Which pages do users visit in a session where they added something to cart but never bought?

That’s the question. And there’s a bonus: if we can attach the net cart value to those sessions, we can prioritise by revenue impact, not just volume.

What you need

Three things:

Abandoned sessions — sessions that contain an add_to_cart event but no purchase. The ga4_sessions table has aggregated event counts per session, but we need to configure those counts first (more on that below).

Last pages visited — for each abandonment session, the page_view events closest to the end of the session, from ga4_events.

Cart value — the sum of ecommerce.value on add_to_cart events. This gives you the (gross) value of what was actually added to the cart when the user disappeared.

Step 1: configure session totals (Premium)

Out of the box, ga4_sessions doesn’t know how many add_to_cart or purchase events happened in a session. You need to tell GA4Dataform to count and sum them.

In includes/custom/modules/ga4/config.js, add this to your config:

CUSTOM_SESSION_TOTALS: {
  eventsToCount: [
    'add_to_cart',
    'remove_from_cart',
    'begin_checkout',
    'purchase',
  ],
  sumFields: [
    { name: 'event_params.value', eventFilter: 'add_to_cart',       renameTo: 'cart_value_added'   },
  ]
}

After a rebuild, ga4_sessions will have:

  • totals.count.add_to_cart — number of add-to-cart events in the session
  • totals.count.purchase — number of purchase events
  • totals.sum.cart_value_added — total value added to cart

The query

WITH abandoned_sessions AS (
    -- sessions with at least one add_to_cart and no purchase
    SELECT
        session_id,
        user_pseudo_id,
        session_date,
        totals.count.add_to_cart AS add_to_cart_count,
        totals.sum.cart_value_added  AS cart_value_added,
        session_source.default_channel_grouping  AS channel,
    FROM `superform_outputs.ga4_sessions`
    WHERE totals.count.add_to_cart > 0
      AND totals.count.purchase = 0
      AND session_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY)
),

last_pages AS (
    -- last 3 page_view events per abandoned session
    SELECT
        e.session_id,
        ARRAY_AGG( e.page.path ORDER BY e.time.event_timestamp_utc DESC LIMIT 3 ) as last_3_pages,
    FROM `superform_outputs.ga4_events` e
    INNER JOIN abandoned_sessions a USING (session_id)
    WHERE e.event_name = 'page_view'
    AND e.event_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY)
    GROUP BY ALL
)


SELECT
    lp.last_3_pages[SAFE_OFFSET(2)] as pre_pre_exit_page,
    lp.last_3_pages[SAFE_OFFSET(1)] as pre_exit_page,
    lp.last_3_pages[SAFE_OFFSET(0)] as exit_page,
    COUNT(DISTINCT lp.session_id)  AS abandoned_sessions,
    ROUND(AVG(a.cart_value_added), 2)  AS avg_abandoned_cart_value,
    ROUND(SUM(a.cart_value_added), 2)  AS sum_abandoned_cart_value
FROM last_pages lp
INNER JOIN abandoned_sessions a USING (session_id)
GROUP BY ALL
ORDER BY abandoned_sessions DESC

Replace superform_outputs with your actual dataset name.

Each row contains 3 page path columsn, indicating the second-to-last, penultimate, and final page path of the session.

Then, aggregated: how many abandonment sessions followed this path, and the total and average cart value walking out the door with them.

Reading the results

Page sequences that appear often are the last route people took before leaving. That’s your friction sequence. Common culprits:

Shipping costs page — if this tops the list, your shipping costs are killing conversions. Test free shipping thresholds.

Login / register page — forced account creation is a classic abandonment trigger. Guest checkout is the fix.

Payment page — if people get this far and still bail, something about the payment experience is wrong. Limited payment methods, trust signals missing, or a confusing form.

You could filter or drill down by channel from the abandoned_sessions CTE to see if paid traffic abandons on different pages than organic. A paid traffic audience hitting the login wall especially hard is worth knowing.

Your turn

Run this against your last 90 days and look at the top paths by total_abandoned_value. That’s the ranked list of pages costing you the most revenue, right now.

If a single page keeps showing up with high abandoned cart values, that’s where your next CRO experiment should be.

Let us know what you find.

Jules Stuifbergen

Published at March 18, 2026

Continue Reading