Class: Sentiero::Analytics::FrustrationAnalyzer
- Defined in:
- lib/sentiero/analytics/frustration_analyzer.rb
Overview
Cross-session frustration signals per page URL: rage clicks (bursts at the same spot) and dead clicks (clicks the page never responds to), plus top rage-clicked elements and per-incident replay links.
Detection itself lives in Frustration::Detectors (pure Ruby ports of the JS detectors, frontend/src/dashboard/frustration.js, pinned by ported tests so the two can't drift). Over the detectors' raw dead clicks this class layers cross-session aggregation and a de-noising pass: an app-level custom event in the dead window counts as a page response; the final click of a segment navigated away from is withdrawn; an error-coincident dead click is kept and tagged kind: "error".
Constant Summary collapse
- CLICK_TAG =
Custom-event tag carrying the clicked element's CSS selector.
"__click"- INTERNAL_TAG_PREFIX =
Recorder-internal annotation prefix and the browser JS-error tag; neither proves the page responded to a click.
"__"- ERROR_TAG =
"error"- NEAREST_CLICK_TOLERANCE_MS =
Max ms a "__click" annotation may sit from a rage cluster's first click and still be attributed to it.
500- MAX_URLS =
Accumulation caps during the scan (sessions scan newest-first).
200- MAX_SELECTORS_PER_URL =
200- MAX_INCIDENTS_PER_URL =
20- TOP_SELECTORS_LIMIT =
10
Constants included from Events
Events::CUSTOM, Events::INCREMENTAL, Events::META, Events::SOURCE_INPUT, Events::SOURCE_MOUSE_INTERACTION, Events::SOURCE_SCROLL
Instance Attribute Summary
Attributes inherited from Analyzer
Class Method Summary collapse
-
.detect_frustration_events(events) ⇒ Object
Stable entry point for callers outside this class (EngagementAnalyzer, PageReportAnalyzer) that only need raw detection, not the cross-session aggregation below.
Instance Method Summary collapse
-
#analyze(limit: nil, since: nil, until_time: nil) ⇒ Object
Detectors run over the FULL window (their response semantics span page boundaries by design); each incident is then attributed to the page segment its click happened on.
Methods inherited from Analyzer
Methods included from EntryAttribution
#earlier?, #first_meta_href, #same_origin?, #update_entry_candidate
Methods included from Bounded
#bounded_fetch, #bounded_increment
Methods included from Stats
#mean, #offset_ms, #percentile, #top_counts
Constructor Details
This class inherits a constructor from Sentiero::Analytics::Analyzer
Class Method Details
.detect_frustration_events(events) ⇒ Object
Stable entry point for callers outside this class (EngagementAnalyzer, PageReportAnalyzer) that only need raw detection, not the cross-session aggregation below.
41 |
# File 'lib/sentiero/analytics/frustration_analyzer.rb', line 41 def self.detect_frustration_events(events) = Frustration::Detectors.detect_frustration_events(events) |
Instance Method Details
#analyze(limit: nil, since: nil, until_time: nil) ⇒ Object
Detectors run over the FULL window (their response semantics span page boundaries by design); each incident is then attributed to the page segment its click happened on.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/sentiero/analytics/frustration_analyzer.rb', line 46 def analyze(limit: nil, since: nil, until_time: nil) pages = {} accumulation_capped = false _scanned, hit_cap = scan_sessions(limit: limit, since: since, until_time: until_time) do |summary, window_id, events| incidents = Frustration::Detectors.detect_frustration_events(events) next if incidents.empty? segments = page_segments(events) incidents = refine_incidents(incidents, segments) next if incidents.empty? annotations = click_annotations(events) incidents.each do |incident| page = page_for(pages, incident[:url]) unless page accumulation_capped = true next end accumulation_capped = true unless record_incident(page, incident, summary[:session_id], window_id, annotations) page[:session_ids][summary[:session_id]] = true end end { pages: pages.transform_values { |page| summarize(page) }, was_truncated: accumulation_capped || hit_cap } end |