ga4_page_transitions: Build Page-Transition Counts from a GA4 BigQuery Export

View source: R/ga4_page_transitions.R

ga4_page_transitionsR Documentation

Build Page-Transition Counts from a GA4 BigQuery Export

Description

Builds consecutive-page-view **transition counts** from a Google Analytics 4 (GA4) BigQuery event-export data frame. The result is a 'from'/'to' edge list with a count column, in the shape that [pagerank()] accepts (pass the count column via 'weight_col').

This function operates entirely on a data frame **you supply** — it does **not** query BigQuery and adds no database dependencies. Extract the GA4 'events_*' rows you care about (typically 'page_view' events, with the session-identity and ordering fields un-nested from 'event_params' / the 'batch' struct) into a data frame, then pass it here.

Usage

ga4_page_transitions(
  events_df,
  user_id_col = "user_pseudo_id",
  session_id_col = "ga_session_id",
  page_col = "page_location",
  timestamp_col = "event_timestamp",
  batch_page_id_col = "batch_page_id",
  batch_ordering_id_col = "batch_ordering_id",
  batch_event_index_col = "batch_event_index",
  from_col = "from",
  to_col = "to",
  count_col = "n",
  drop_self_transitions = TRUE
)

Arguments

events_df

A data frame of GA4 export rows, one row per event (typically filtered to 'page_view' events upstream). Must contain the session-identity, page, and timestamp columns named below; the 'batch_*' tie-break columns are optional but recommended.

user_id_col

Name of the user-identity column. GA4 default '"user_pseudo_id"'.

session_id_col

Name of the session-identity column (the un-nested 'ga_session_id' event parameter). GA4 default '"ga_session_id"'.

page_col

Name of the page-identity column whose consecutive values form the transitions. GA4 default '"page_location"'.

timestamp_col

Name of the primary ordering column. GA4 default '"event_timestamp"'.

batch_page_id_col, batch_ordering_id_col, batch_event_index_col

Names of the GA4 batch tie-break columns, applied in this order after 'timestamp_col'. GA4 defaults '"batch_page_id"', '"batch_ordering_id"', '"batch_event_index"'. A column that is not present in 'events_df' is skipped.

from_col, to_col

Names of the source/target columns in the returned edge list. Defaults '"from"' / '"to"' (the [pagerank()] defaults).

count_col

Name of the transition-count column in the returned edge list. Default '"n"'. Pass this name to 'pagerank(weight_col = ...)'.

drop_self_transitions

Logical. If 'TRUE' (default), consecutive page views of the **same** page (reloads, SPA re-renders to the same route) are dropped before counting. If 'FALSE', self-transitions are kept and counted.

Value

A data frame with one row per distinct 'from -> to' page transition, carrying the columns named by 'from_col', 'to_col', and 'count_col'. The count column is an integer tally of how many times that consecutive page-view transition was observed across all sessions. Rows are ordered by 'from' then 'to' for stable output. When no transitions exist (e.g. every session has a single page view), an empty data frame with the correct columns is returned.

What this measures (transition, NOT link-click)

The output is a **behavioral navigation signal** — the empirical "where did users go next" sequence of page views within a session. It is **not** a measured link-click probability. GA4 page-view sequences are contaminated by page reloads, browser back/forward navigation, server redirects, single-page-application route changes, dropped/missing events, and off-site returns. A transition 'A -> B' means "a session viewed page A and then viewed page B next", which is **not** the same as "a user clicked a link from A to B." For link-click instrumentation (the actual element clicked), a separate 'ga4_link_clicks()' product is required; do not use this function as a substitute for it.

Session / event ordering contract

Within each session, events are ordered by 'event_timestamp' and then by a deterministic chain of tie-break fields, **in this order**:

  1. 'event_timestamp' (microseconds since epoch),

  2. 'batch_page_id',

  3. 'batch_ordering_id',

  4. 'batch_event_index'.

'event_timestamp' **alone is insufficient**: GA4 batches events and multiple events in a session can share the exact same 'event_timestamp'. When timestamps tie, the 'batch_*' fields (assigned by the GA4 SDK in the order events were recorded on the client) break the tie so the ordering is stable and reproducible. Any tie-break column that is absent from 'events_df' is simply skipped, but supplying all of them is strongly recommended to guarantee a deterministic order. As a final stabilizer the original row order of 'events_df' is used, so the result never depends on the platform's sort implementation.

A *session* is identified by the combination of 'user_id_col' and 'session_id_col' (GA4: 'user_pseudo_id' and the 'ga_session_id' event parameter). Transitions are only formed **within** a single session; consecutive page views that cross a session boundary are never joined.

See Also

[pagerank()] for consuming the result; [transform_weights()] for turning raw transition counts into PageRank edge weights.

Examples

events <- data.frame(
  user_pseudo_id = c("u1", "u1", "u1", "u2", "u2"),
  ga_session_id = c(1, 1, 1, 9, 9),
  page_location = c("/home", "/blog", "/contact", "/home", "/blog"),
  event_timestamp = c(100, 200, 300, 100, 200),
  batch_page_id = c(0, 1, 2, 0, 1),
  batch_ordering_id = c(0, 0, 0, 0, 0),
  batch_event_index = c(0, 1, 2, 0, 1)
)
transitions <- ga4_page_transitions(events)
transitions
# Feed to pagerank() as a behavioral transition model:
# pagerank(transitions, weight_col = "n", clean_edge_urls = FALSE)

pagerankr documentation built on Oct. 1, 2026, 5:09 p.m.