← Back to Metrics

Learner Engagement Time

Also known as: Learning Engagement Time, Active Learning Time, Learner Active Time, Time Engaged, Learning Activity Time, Engaged Learning Duration, Time on Learning Content

EngagementmetricEdTech & E-Learning

Measures the total active time learners spend interacting with eligible learning content and activities during a defined reporting window. It excludes background, idle, duplicate, invalid, and non-learning activity so that the result represents attributable learning engagement rather than elapsed session duration.

Business Use Case

The Chief Product Officer reviews monthly engagement time by course, lesson, content format, and learner cohort to identify high-enrollment content with declining active time. Product and instructional design teams then investigate telemetry-confirmed drop-off points, revise or replace low-engagement activities, and compare post-release engagement time and completion-rate changes against the pre-release baseline.

Business Criticality

High

Journey / Navigation Area

Engagement

Owning Function

Learning Product Management

Scope

User

Formula

SUM_over_learners(DURATION_SECONDS(UNION(CLIP(eligible_active_intervals, window_start, window_end))))

Calculation Notes

1️⃣ Build active intervals from engagement events (start, pause, resume, etc.). 2️⃣ Clip intervals to reporting-window boundaries. 3️⃣ Merge overlapping or adjacent intervals for the same learner. 4️⃣ Count the union once to avoid time duplication across tabs/devices. 5️⃣ Prefer measured foreground-active duration; infer time only between eligible events ≤60 seconds apart. 6️⃣ Pause accumulation when the app is hidden, device is locked, or media is paused/buffering. 7️⃣ For offline activity, use validated client event time after sync under late-arriving-data policy.

Technical Details

Measure Typecount
Aggregation WindowTime based - Daily, with weekly, monthly, term, and annual rollups

Events

PlatformEvent
Google Analytics 4user_engagement
Adobeuser_engagement

Data Mappings

W3 Data Layer
{
  "digitalData": {
    "event": [
      {
        "eventInfo": {
          "eventName": "user_engagement",
          "eventType": "engagement",
          "timeStamp": "2025-01-15T10:10:00.000Z",
          "eventAction": "user_engagement"
        },
        "attributes": {
          "app_id": "learning-web",
          "lab_id": "",
          "event_id": "eng-7f47d852-c0c2-4b7e-9098-546da02d57aa",
          "media_id": "",
          "platform": "learning_management_system",
          "course_id": "course-1001",
          "lesson_id": "lesson-4001",
          "module_id": "module-3001",
          "content_id": "content-6001",
          "learner_id": "learner-12345",
          "session_id": "1736935200",
          "activity_id": "activity-5001",
          "app_version": "5.4.1",
          "course_name": "Example Course",
          "device_type": "desktop",
          "anonymous_id": "anon-67890",
          "content_type": "interactive_lesson",
          "activity_type": "lesson",
          "assessment_id": "",
          "content_title": "Example Learning Activity",
          "engagement_id": "engagement-98765",
          "enrollment_id": "enrollment-24680",
          "event_version": "1.0",
          "page_location": "https://learning.example.com/courses/course-1001/lessons/lesson-4001",
          "page_referrer": "https://learning.example.com/courses/course-1001",
          "course_version": "3.2",
          "idle_time_msec": 90000,
          "event_timestamp": "2025-01-15T10:10:00.000Z",
          "active_time_msec": 420000,
          "content_language": "en-US",
          "content_provider": "internal",
          "delivery_channel": "web",
          "interaction_type": "content_interaction",
          "learning_path_id": "path-2001",
          "completion_status": "in_progress",
          "elapsed_time_msec": 600000,
          "invalid_time_msec": 5000,
          "identity_namespace": "LMSID",
          "duplicate_time_msec": 10000,
          "engagement_end_time": "2025-01-15T10:10:00.000Z",
          "identity_auth_state": "authenticated",
          "reporting_window_id": "2025-01-15",
          "attribution_eligible": true,
          "background_time_msec": 30000,
          "engagement_time_msec": 420000,
          "reporting_window_end": "2025-01-15T23:59:59.999Z",
          "engagement_start_time": "2025-01-15T10:00:00.000Z",
          "non_learning_time_msec": 45000,
          "reporting_window_start": "2025-01-15T00:00:00.000Z"
        }
      }
    ]
  }
}
GA4 Data Layer
{
  "event": "user_engagement",
  "app_id": "learning-web",
  "lab_id": "",
  "event_id": "eng-7f47d852-c0c2-4b7e-9098-546da02d57aa",
  "media_id": "",
  "platform": "learning_management_system",
  "course_id": "course-1001",
  "lesson_id": "lesson-4001",
  "module_id": "module-3001",
  "content_id": "content-6001",
  "learner_id": "learner-12345",
  "activity_id": "activity-5001",
  "app_version": "5.4.1",
  "course_name": "Example Course",
  "device_type": "desktop",
  "anonymous_id": "anon-67890",
  "content_type": "interactive_lesson",
  "activity_type": "lesson",
  "assessment_id": "",
  "content_title": "Example Learning Activity",
  "engagement_id": "engagement-98765",
  "enrollment_id": "enrollment-24680",
  "event_version": "1.0",
  "ga_session_id": "1736935200",
  "page_location": "https://learning.example.com/courses/course-1001/lessons/lesson-4001",
  "page_referrer": "https://learning.example.com/courses/course-1001",
  "course_version": "3.2",
  "idle_time_msec": 90000,
  "event_timestamp": "2025-01-15T10:10:00.000Z",
  "active_time_msec": 420000,
  "content_language": "en-US",
  "content_provider": "internal",
  "delivery_channel": "web",
  "interaction_type": "content_interaction",
  "learning_path_id": "path-2001",
  "completion_status": "in_progress",
  "elapsed_time_msec": 600000,
  "invalid_time_msec": 5000,
  "identity_namespace": "LMSID",
  "duplicate_time_msec": 10000,
  "engagement_end_time": "2025-01-15T10:10:00.000Z",
  "identity_auth_state": "authenticated",
  "reporting_window_id": "2025-01-15",
  "attribution_eligible": true,
  "background_time_msec": 30000,
  "engagement_time_msec": 420000,
  "reporting_window_end": "2025-01-15T23:59:59.999Z",
  "engagement_start_time": "2025-01-15T10:00:00.000Z",
  "non_learning_time_msec": 45000,
  "reporting_window_start": "2025-01-15T00:00:00.000Z"
}
Adobe Client Data Layer
{
  "data": {
    "learnerEngagement": {
      "app_id": "learning-web",
      "lab_id": "",
      "event_id": "eng-7f47d852-c0c2-4b7e-9098-546da02d57aa",
      "media_id": "",
      "platform": "learning_management_system",
      "course_id": "course-1001",
      "lesson_id": "lesson-4001",
      "module_id": "module-3001",
      "content_id": "content-6001",
      "learner_id": "learner-12345",
      "session_id": "1736935200",
      "activity_id": "activity-5001",
      "app_version": "5.4.1",
      "course_name": "Example Course",
      "device_type": "desktop",
      "anonymous_id": "anon-67890",
      "content_type": "interactive_lesson",
      "activity_type": "lesson",
      "assessment_id": "",
      "content_title": "Example Learning Activity",
      "engagement_id": "engagement-98765",
      "enrollment_id": "enrollment-24680",
      "event_version": "1.0",
      "page_location": "https://learning.example.com/courses/course-1001/lessons/lesson-4001",
      "page_referrer": "https://learning.example.com/courses/course-1001",
      "course_version": "3.2",
      "idle_time_msec": 90000,
      "event_timestamp": "2025-01-15T10:10:00.000Z",
      "active_time_msec": 420000,
      "content_language": "en-US",
      "content_provider": "internal",
      "delivery_channel": "web",
      "interaction_type": "content_interaction",
      "learning_path_id": "path-2001",
      "completion_status": "in_progress",
      "elapsed_time_msec": 600000,
      "invalid_time_msec": 5000,
      "identity_namespace": "LMSID",
      "duplicate_time_msec": 10000,
      "engagement_end_time": "2025-01-15T10:10:00.000Z",
      "identity_auth_state": "authenticated",
      "reporting_window_id": "2025-01-15",
      "attribution_eligible": true,
      "background_time_msec": 30000,
      "engagement_time_msec": 420000,
      "reporting_window_end": "2025-01-15T23:59:59.999Z",
      "engagement_start_time": "2025-01-15T10:00:00.000Z",
      "non_learning_time_msec": 45000,
      "reporting_window_start": "2025-01-15T00:00:00.000Z"
    }
  },
  "event": "user_engagement"
}
XDM Mapping
{
  "web": {
    "webReferrer": {
      "URL": "https://learning.example.com/courses/course-1001"
    },
    "webPageDetails": {
      "URL": "https://learning.example.com/courses/course-1001/lessons/lesson-4001",
      "name": "Example Learning Activity"
    }
  },
  "device": {
    "type": "desktop"
  },
  "eventID": "eng-7f47d852-c0c2-4b7e-9098-546da02d57aa",
  "_learning": {
    "learnerEngagement": {
      "app_id": "learning-web",
      "lab_id": "",
      "event_id": "eng-7f47d852-c0c2-4b7e-9098-546da02d57aa",
      "media_id": "",
      "platform": "learning_management_system",
      "course_id": "course-1001",
      "lesson_id": "lesson-4001",
      "module_id": "module-3001",
      "content_id": "content-6001",
      "learner_id": "learner-12345",
      "session_id": "1736935200",
      "activity_id": "activity-5001",
      "app_version": "5.4.1",
      "course_name": "Example Course",
      "device_type": "desktop",
      "anonymous_id": "anon-67890",
      "content_type": "interactive_lesson",
      "activity_type": "lesson",
      "assessment_id": "",
      "content_title": "Example Learning Activity",
      "engagement_id": "engagement-98765",
      "enrollment_id": "enrollment-24680",
      "event_version": "1.0",
      "page_location": "https://learning.example.com/courses/course-1001/lessons/lesson-4001",
      "page_referrer": "https://learning.example.com/courses/course-1001",
      "course_version": "3.2",
      "idle_time_msec": 90000,
      "event_timestamp": "2025-01-15T10:10:00.000Z",
      "active_time_msec": 420000,
      "content_language": "en-US",
      "content_provider": "internal",
      "delivery_channel": "web",
      "interaction_type": "content_interaction",
      "learning_path_id": "path-2001",
      "completion_status": "in_progress",
      "elapsed_time_msec": 600000,
      "invalid_time_msec": 5000,
      "identity_namespace": "LMSID",
      "duplicate_time_msec": 10000,
      "engagement_end_time": "2025-01-15T10:10:00.000Z",
      "identity_auth_state": "authenticated",
      "reporting_window_id": "2025-01-15",
      "attribution_eligible": true,
      "background_time_msec": 30000,
      "engagement_time_msec": 420000,
      "reporting_window_end": "2025-01-15T23:59:59.999Z",
      "engagement_start_time": "2025-01-15T10:00:00.000Z",
      "non_learning_time_msec": 45000,
      "reporting_window_start": "2025-01-15T00:00:00.000Z"
    }
  },
  "eventType": "user_engagement",
  "timestamp": "2025-01-15T10:10:00.000Z",
  "producedBy": "system",
  "application": {
    "id": "learning-web",
    "version": "5.4.1"
  },
  "environment": {
    "type": "browser"
  },
  "identityMap": {
    "ECID": [
      {
        "id": "anon-67890",
        "primary": false,
        "authenticatedState": "ambiguous"
      }
    ],
    "LMSID": [
      {
        "id": "learner-12345",
        "primary": true,
        "authenticatedState": "authenticated"
      }
    ]
  }
}

SQL Queries

Google Analytics 4 (BigQuery)
-- ==========================================
-- 1. GOOGLE BIGQUERY SQL
-- ==========================================
WITH source_events AS (
  SELECT
    e.*,
    (
      SELECT AS STRUCT
        MAX(IF(key = 'event_id', param_value, NULL)) AS event_id,
        MAX(IF(key = 'event_version', param_value, NULL)) AS event_version,
        MAX(IF(key = 'event_timestamp', param_value, NULL)) AS event_timestamp_value,
        MAX(IF(key = 'reporting_window_id', param_value, NULL)) AS reporting_window_id,
        MAX(IF(key = 'reporting_window_start', param_value, NULL)) AS reporting_window_start,
        MAX(IF(key = 'reporting_window_end', param_value, NULL)) AS reporting_window_end,
        MAX(IF(key = 'learner_id', param_value, NULL)) AS learner_id,
        MAX(IF(key = 'anonymous_id', param_value, NULL)) AS anonymous_id,
        MAX(IF(key = 'identity_namespace', param_value, NULL)) AS identity_namespace,
        MAX(IF(key = 'identity_auth_state', param_value, NULL)) AS identity_auth_state,
        MAX(IF(key IN ('ga_session_id', 'session_id'), param_value, NULL)) AS session_id,
        MAX(IF(key = 'engagement_id', param_value, NULL)) AS engagement_id,
        MAX(IF(key = 'enrollment_id', param_value, NULL)) AS enrollment_id,
        MAX(IF(key = 'course_id', param_value, NULL)) AS course_id,
        MAX(IF(key = 'course_name', param_value, NULL)) AS course_name,
        MAX(IF(key = 'course_version', param_value, NULL)) AS course_version,
        MAX(IF(key = 'learning_path_id', param_value, NULL)) AS learning_path_id,
        MAX(IF(key = 'module_id', param_value, NULL)) AS module_id,
        MAX(IF(key = 'lesson_id', param_value, NULL)) AS lesson_id,
        MAX(IF(key = 'activity_id', param_value, NULL)) AS activity_id,
        MAX(IF(key = 'activity_type', param_value, NULL)) AS activity_type,
        MAX(IF(key = 'content_id', param_value, NULL)) AS content_id,
        MAX(IF(key = 'content_type', param_value, NULL)) AS content_type,
        MAX(IF(key = 'content_title', param_value, NULL)) AS content_title,
        MAX(IF(key = 'content_provider', param_value, NULL)) AS content_provider,
        MAX(IF(key = 'content_language', param_value, NULL)) AS content_language,
        MAX(IF(key = 'delivery_channel', param_value, NULL)) AS delivery_channel,
        MAX(IF(key = 'platform', param_value, NULL)) AS platform,
        MAX(IF(key = 'device_type', param_value, NULL)) AS device_type,
        MAX(IF(key = 'app_id', param_value, NULL)) AS app_id,
        MAX(IF(key = 'app_version', param_value, NULL)) AS app_version,
        MAX(IF(key = 'page_location', param_value, NULL)) AS page_location,
        MAX(IF(key = 'page_referrer', param_value, NULL)) AS page_referrer,
        MAX(IF(key = 'media_id', param_value, NULL)) AS media_id,
        MAX(IF(key = 'assessment_id', param_value, NULL)) AS assessment_id,
        MAX(IF(key = 'lab_id', param_value, NULL)) AS lab_id,
        MAX(IF(key = 'interaction_type', param_value, NULL)) AS interaction_type,
        MAX(IF(key = 'engagement_start_time', param_value, NULL)) AS engagement_start_time,
        MAX(IF(key = 'engagement_end_time', param_value, NULL)) AS engagement_end_time,
        MAX(IF(key = 'active_time_msec', param_value, NULL)) AS active_time_msec,
        MAX(IF(key = 'idle_time_msec', param_value, NULL)) AS idle_time_msec,
        MAX(IF(key = 'background_time_msec', param_value, NULL)) AS background_time_msec,
        MAX(IF(key = 'duplicate_time_msec', param_value, NULL)) AS duplicate_time_msec,
        MAX(IF(key = 'invalid_time_msec', param_value, NULL)) AS invalid_time_msec,
        MAX(IF(key = 'non_learning_time_msec', param_value, NULL)) AS non_learning_time_msec,
        MAX(IF(key = 'elapsed_time_msec', param_value, NULL)) AS elapsed_time_msec,
        MAX(IF(key = 'completion_status', param_value, NULL)) AS completion_status,
        MAX(IF(key = 'attribution_eligible', param_value, NULL)) AS attribution_eligible,
        MAX(IF(key = 'engagement_time_msec', param_value, NULL)) AS reported_engagement_time_msec
      FROM (
        SELECT
          ep.key,
          COALESCE(
            ep.value.string_value,
            CAST(ep.value.int_value AS STRING),
            CAST(ep.value.double_value AS STRING),
            CAST(ep.value.float_value AS STRING)
          ) AS param_value
        FROM UNNEST(e.event_params) AS ep
      )
    ) AS p
  FROM `your-project.analytics_123456789.events_*` AS e
  WHERE _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', @start_date)
                          AND FORMAT_DATE('%Y%m%d', @end_date)
    AND e.event_name = 'user_engagement'
),
normalized AS (
  SELECT
    p.event_id,
    p.event_version,
    COALESCE(SAFE_CAST(p.event_timestamp_value AS TIMESTAMP), TIMESTAMP_MICROS(event_timestamp)) AS event_timestamp,
    COALESCE(p.reporting_window_id, event_date) AS reporting_window_id,
    SAFE_CAST(p.reporting_window_start AS TIMESTAMP) AS reporting_window_start,
    SAFE_CAST(p.reporting_window_end AS TIMESTAMP) AS reporting_window_end,
    COALESCE(NULLIF(p.learner_id, ''), user_id) AS learner_id,
    COALESCE(NULLIF(p.anonymous_id, ''), user_pseudo_id) AS anonymous_id,
    p.identity_namespace,
    p.identity_auth_state,
    p.session_id,
    p.engagement_id,
    p.enrollment_id,
    p.course_id,
    p.course_name,
    p.course_version,
    p.learning_path_id,
    p.module_id,
    p.lesson_id,
    p.activity_id,
    p.activity_type,
    p.content_id,
    p.content_type,
    p.content_title,
    p.content_provider,
    p.content_language,
    p.delivery_channel,
    p.platform,
    COALESCE(NULLIF(p.device_type, ''), device.category) AS device_type,
    COALESCE(NULLIF(p.app_id, ''), app_info.id) AS app_id,
    COALESCE(NULLIF(p.app_version, ''), app_info.version) AS app_version,
    p.page_location,
    p.page_referrer,
    NULLIF(p.media_id, '') AS media_id,
    NULLIF(p.assessment_id, '') AS assessment_id,
    NULLIF(p.lab_id, '') AS lab_id,
    p.interaction_type,
    SAFE_CAST(p.engagement_start_time AS TIMESTAMP) AS engagement_start_time,
    SAFE_CAST(p.engagement_end_time AS TIMESTAMP) AS engagement_end_time,
    SAFE_CAST(p.active_time_msec AS INT64) AS active_time_msec,
    SAFE_CAST(p.idle_time_msec AS INT64) AS idle_time_msec,
    SAFE_CAST(p.background_time_msec AS INT64) AS background_time_msec,
    SAFE_CAST(p.duplicate_time_msec AS INT64) AS duplicate_time_msec,
    SAFE_CAST(p.invalid_time_msec AS INT64) AS invalid_time_msec,
    SAFE_CAST(p.non_learning_time_msec AS INT64) AS non_learning_time_msec,
    SAFE_CAST(p.elapsed_time_msec AS INT64) AS elapsed_time_msec,
    p.completion_status,
    COALESCE(SAFE_CAST(p.attribution_eligible AS BOOL), FALSE) AS attribution_eligible,
    SAFE_CAST(p.reported_engagement_time_msec AS INT64) AS reported_engagement_time_msec,
    event_bundle_sequence_id,
    event_server_timestamp_offset
  FROM source_events
),
deduplicated AS (
  SELECT * EXCEPT(event_bundle_sequence_id, event_server_timestamp_offset)
  FROM normalized
  QUALIFY ROW_NUMBER() OVER (
    PARTITION BY COALESCE(
      NULLIF(event_id, ''),
      CONCAT(
        COALESCE(NULLIF(engagement_id, ''), 'unknown'), '|',
        COALESCE(NULLIF(learner_id, ''), NULLIF(anonymous_id, ''), 'unknown'), '|',
        CAST(event_timestamp AS STRING)
      )
    )
    ORDER BY event_server_timestamp_offset DESC, event_bundle_sequence_id DESC
  ) = 1
),
measured AS (
  SELECT
    *,
    COALESCE(
      reported_engagement_time_msec,
      active_time_msec,
      GREATEST(
        COALESCE(elapsed_time_msec, 0)
          - COALESCE(idle_time_msec, 0)
          - COALESCE(background_time_msec, 0)
          - COALESCE(duplicate_time_msec, 0)
          - COALESCE(invalid_time_msec, 0)
          - COALESCE(non_learning_time_msec, 0),
        0
      )
    ) AS candidate_engagement_time_msec
  FROM deduplicated
)
SELECT
  event_id,
  event_version,
  event_timestamp,
  reporting_window_id,
  reporting_window_start,
  reporting_window_end,
  learner_id,
  anonymous_id,
  identity_namespace,
  identity_auth_state,
  session_id,
  engagement_id,
  enrollment_id,
  course_id,
  course_name,
  course_version,
  learning_path_id,
  module_id,
  lesson_id,
  activity_id,
  activity_type,
  content_id,
  content_type,
  content_title,
  content_provider,
  content_language,
  delivery_channel,
  platform,
  device_type,
  app_id,
  app_version,
  page_location,
  page_referrer,
  media_id,
  assessment_id,
  lab_id,
  interaction_type,
  engagement_start_time,
  engagement_end_time,
  active_time_msec,
  idle_time_msec,
  background_time_msec,
  duplicate_time_msec,
  invalid_time_msec,
  non_learning_time_msec,
  elapsed_time_msec,
  completion_status,
  attribution_eligible,
  CASE
    WHEN attribution_eligible THEN GREATEST(
      LEAST(
        candidate_engagement_time_msec,
        COALESCE(elapsed_time_msec, candidate_engagement_time_msec)
      ),
      0
    )
    ELSE 0
  END AS engagement_time_msec,
  SAFE_DIVIDE(
    CASE WHEN attribution_eligible THEN GREATEST(
      LEAST(candidate_engagement_time_msec, COALESCE(elapsed_time_msec, candidate_engagement_time_msec)), 0
    ) ELSE 0 END,
    1000.0
  ) AS engagement_time_seconds,
  SAFE_DIVIDE(
    CASE WHEN attribution_eligible THEN GREATEST(
      LEAST(candidate_engagement_time_msec, COALESCE(elapsed_time_msec, candidate_engagement_time_msec)), 0
    ) ELSE 0 END,
    60000.0
  ) AS engagement_time_minutes
FROM measured;
Adobe Experience Platform (AEP Query Service)
-- ==========================================
-- 2. ADOBE AEP QUERY SERVICE SQL
-- ==========================================
WITH source_events AS (
  SELECT
    e.eventType,
    e.eventID AS xdm_event_id,
    e.timestamp AS xdm_timestamp,
    e._learning.learnerEngagement AS le
  FROM learner_engagement_events AS e
  WHERE e.timestamp >= CAST('${START_TIMESTAMP}' AS TIMESTAMP)
    AND e.timestamp < CAST('${END_TIMESTAMP}' AS TIMESTAMP)
    AND e.eventType = 'user_engagement'
),
normalized AS (
  SELECT
    COALESCE(NULLIF(le.event_id, ''), xdm_event_id) AS event_id,
    le.event_version AS event_version,
    COALESCE(CAST(le.event_timestamp AS TIMESTAMP), xdm_timestamp) AS event_timestamp,
    le.reporting_window_id AS reporting_window_id,
    CAST(le.reporting_window_start AS TIMESTAMP) AS reporting_window_start,
    CAST(le.reporting_window_end AS TIMESTAMP) AS reporting_window_end,
    le.learner_id AS learner_id,
    le.anonymous_id AS anonymous_id,
    le.identity_namespace AS identity_namespace,
    le.identity_auth_state AS identity_auth_state,
    le.session_id AS session_id,
    le.engagement_id AS engagement_id,
    le.enrollment_id AS enrollment_id,
    le.course_id AS course_id,
    le.course_name AS course_name,
    le.course_version AS course_version,
    le.learning_path_id AS learning_path_id,
    le.module_id AS module_id,
    le.lesson_id AS lesson_id,
    le.activity_id AS activity_id,
    le.activity_type AS activity_type,
    le.content_id AS content_id,
    le.content_type AS content_type,
    le.content_title AS content_title,
    le.content_provider AS content_provider,
    le.content_language AS content_language,
    le.delivery_channel AS delivery_channel,
    le.platform AS platform,
    le.device_type AS device_type,
    le.app_id AS app_id,
    le.app_version AS app_version,
    le.page_location AS page_location,
    le.page_referrer AS page_referrer,
    NULLIF(le.media_id, '') AS media_id,
    NULLIF(le.assessment_id, '') AS assessment_id,
    NULLIF(le.lab_id, '') AS lab_id,
    le.interaction_type AS interaction_type,
    CAST(le.engagement_start_time AS TIMESTAMP) AS engagement_start_time,
    CAST(le.engagement_end_time AS TIMESTAMP) AS engagement_end_time,
    CAST(le.active_time_msec AS BIGINT) AS active_time_msec,
    CAST(le.idle_time_msec AS BIGINT) AS idle_time_msec,
    CAST(le.background_time_msec AS BIGINT) AS background_time_msec,
    CAST(le.duplicate_time_msec AS BIGINT) AS duplicate_time_msec,
    CAST(le.invalid_time_msec AS BIGINT) AS invalid_time_msec,
    CAST(le.non_learning_time_msec AS BIGINT) AS non_learning_time_msec,
    CAST(le.elapsed_time_msec AS BIGINT) AS elapsed_time_msec,
    le.completion_status AS completion_status,
    COALESCE(le.attribution_eligible, FALSE) AS attribution_eligible,
    CAST(le.engagement_time_msec AS BIGINT) AS reported_engagement_time_msec,
    xdm_timestamp AS ingestion_order_timestamp
  FROM source_events
),
ranked AS (
  SELECT
    *,
    ROW_NUMBER() OVER (
      PARTITION BY COALESCE(
        NULLIF(event_id, ''),
        CONCAT(
          COALESCE(NULLIF(engagement_id, ''), 'unknown'), '|',
          COALESCE(NULLIF(learner_id, ''), NULLIF(anonymous_id, ''), 'unknown'), '|',
          CAST(event_timestamp AS VARCHAR)
        )
      )
      ORDER BY ingestion_order_timestamp DESC
    ) AS duplicate_rank
  FROM normalized
),
deduplicated AS (
  SELECT *
  FROM ranked
  WHERE duplicate_rank = 1
),
measured AS (
  SELECT
    *,
    COALESCE(
      reported_engagement_time_msec,
      active_time_msec,
      GREATEST(
        COALESCE(elapsed_time_msec, 0)
          - COALESCE(idle_time_msec, 0)
          - COALESCE(background_time_msec, 0)
          - COALESCE(duplicate_time_msec, 0)
          - COALESCE(invalid_time_msec, 0)
          - COALESCE(non_learning_time_msec, 0),
        0
      )
    ) AS candidate_engagement_time_msec
  FROM deduplicated
)
SELECT
  event_id,
  event_version,
  event_timestamp,
  reporting_window_id,
  reporting_window_start,
  reporting_window_end,
  learner_id,
  anonymous_id,
  identity_namespace,
  identity_auth_state,
  session_id,
  engagement_id,
  enrollment_id,
  course_id,
  course_name,
  course_version,
  learning_path_id,
  module_id,
  lesson_id,
  activity_id,
  activity_type,
  content_id,
  content_type,
  content_title,
  content_provider,
  content_language,
  delivery_channel,
  platform,
  device_type,
  app_id,
  app_version,
  page_location,
  page_referrer,
  media_id,
  assessment_id,
  lab_id,
  interaction_type,
  engagement_start_time,
  engagement_end_time,
  active_time_msec,
  idle_time_msec,
  background_time_msec,
  duplicate_time_msec,
  invalid_time_msec,
  non_learning_time_msec,
  elapsed_time_msec,
  completion_status,
  attribution_eligible,
  CASE
    WHEN attribution_eligible THEN GREATEST(
      LEAST(
        candidate_engagement_time_msec,
        COALESCE(elapsed_time_msec, candidate_engagement_time_msec)
      ),
      0
    )
    ELSE 0
  END AS engagement_time_msec,
  CAST(
    CASE
      WHEN attribution_eligible THEN GREATEST(
        LEAST(candidate_engagement_time_msec, COALESCE(elapsed_time_msec, candidate_engagement_time_msec)),
        0
      )
      ELSE 0
    END AS DOUBLE
  ) / 1000.0 AS engagement_time_seconds,
  CAST(
    CASE
      WHEN attribution_eligible THEN GREATEST(
        LEAST(candidate_engagement_time_msec, COALESCE(elapsed_time_msec, candidate_engagement_time_msec)),
        0
      )
      ELSE 0
    END AS DOUBLE
  ) / 60000.0 AS engagement_time_minutes
FROM measured;

Source Data

Learning Management System event stream, web and mobile Digital Analytics, video and media telemetry, assessment platform events, virtual lab or simulation logs, enrollment records, and identity-resolution services

Dependencies

[ "learner_id", "event_id", "event_type", "event_timestamp", "engagement_interval_start", "engagement_interval_end", "engagement_duration_seconds", "content_id", "course_id", "session_id", "device_id", "application_visibility_state", "media_playback_state", "enrollment_status", "reporting_timezone", "eligible_learning_event" ]

Report Attributes

Course Program Subject Module Lesson Content Item Content Type Learning Activity Type Delivery Mode Learner Cohort Enrollment Status Subscription Plan Institution Instructor Device Type Operating System Application Version Geography Acquisition Channel Session Type Calendar Date Academic Term

Recommended Reporting Views

Views
Executive Learning Engagement DashboardCourse and Content Performance DashboardLearner Activity and Retention DashboardInstructional Design Optimization DashboardProduct Engagement Health DashboardInstitution and Cohort Outcomes DashboardTelemetry Quality Monitoring Dashboard

Segment Eligibility

true

Governance

Data Sensitivityrestricted
Contains PIIYes - This Metric contains Personally Identifiable Information

Derived KPIs

Governance

Created bydevyendarm
Created on9/3/2026
Last modified bydevyendarm
StatusPUBLISHED

GitHub

View File on GitHubcatalog/metrics/learner-engagement-time.yml

Community Discussion