User Exit Points Analysis on Website
Exit Points are pages or elements after which users leave the site. Exit Rate differs from Bounce Rate: bounce—left on first page without interaction, exit—left on any page after visiting several.
GA4 Exit Rate Analysis
-- BigQuery: top pages by exit rate
WITH page_views AS (
SELECT
user_pseudo_id,
session_id,
event_name,
page_location,
event_timestamp,
LEAD(event_name) OVER (
PARTITION BY user_pseudo_id, session_id
ORDER BY event_timestamp
) AS next_event
FROM `project.analytics.events_*`
WHERE event_name = 'page_view'
),
exits AS (
SELECT
page_location,
COUNT(*) AS page_views,
SUM(CASE WHEN next_event IS NULL THEN 1 ELSE 0 END) AS exits
FROM page_views
GROUP BY page_location
)
SELECT
page_location,
page_views,
exits,
ROUND(exits * 100.0 / page_views, 1) AS exit_rate
FROM exits
WHERE page_views > 100
ORDER BY exit_rate DESC
LIMIT 50;
Normal vs Anomalous Exits
Not every high exit rate is a problem:
-
/thank-you— 95% exit rate = normal (conversion completed) -
/contacts— 70% exit rate = normal (user found contacts) -
/checkout/step-2— 60% exit rate = problem (abandoned checkout) -
/pricing— 50% exit rate = needs analysis
def classify_exit_pages(pages_with_exit_rate):
for page in pages_with_exit_rate:
# Normal end pages
if any(p in page['url'] for p in ['thank-you', 'success', 'confirmation']):
page['exit_expected'] = True
# Content pages needing analysis
elif page['exit_rate'] > 40 and page['is_funnel_page']:
page['exit_priority'] = 'HIGH'
else:
page['exit_expected'] = False
Session Recordings on Exit Pages
// Hotjar/Clarity: filter by exit on specific pages
// Dashboard: Recordings → Filter: Exit page = /checkout
// Microsoft Clarity API for programmatic analysis
fetch('https://api.clarity.ms/export/1.0/sessions', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
body: JSON.stringify({
projectId: 'xxx',
filters: [{
field: 'exitPage',
operator: 'contains',
value: '/checkout'
}],
startDate: '2024-03-01',
endDate: '2024-03-31'
})
})
Scroll Depth on Exit Pages
// Track scroll depth on exit
let maxScroll = 0
let lastScrollTime = Date.now()
window.addEventListener('scroll', () => {
const scrollPercent = Math.round(
(window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100
)
maxScroll = Math.max(maxScroll, scrollPercent)
lastScrollTime = Date.now()
})
window.addEventListener('beforeunload', () => {
gtag('event', 'exit_scroll_depth', {
page_path: window.location.pathname,
max_scroll_percent: maxScroll,
time_on_page: Math.round((Date.now() - pageLoadTime) / 1000)
})
})
Exit Intent Popup
To retain users about to leave:
let exitIntentShown = false
document.addEventListener('mouseleave', (e) => {
if (e.clientY <= 0 && !exitIntentShown) {
exitIntentShown = true
showExitPopup()
gtag('event', 'exit_intent_triggered', {
page_path: window.location.pathname
})
}
})
function showExitPopup() {
document.getElementById('exit-popup').classList.remove('hidden')
}
User Path Before Exit
-- What users visited before exiting from /checkout
SELECT
prev_page,
COUNT(*) as sessions,
ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 1) AS pct
FROM (
SELECT
page_location as exit_page,
LAG(page_location) OVER (
PARTITION BY user_pseudo_id, session_id
ORDER BY event_timestamp
) AS prev_page
FROM page_views
WHERE page_location LIKE '%/checkout%'
)
WHERE exit_page IS NOT NULL AND prev_page IS NOT NULL
GROUP BY prev_page
ORDER BY sessions DESC
LIMIT 20;
Timeline
Exit points analysis with segmentation and recommendations: 2-3 business days.







