Notifications trends and metrics
Purpose
This document presents the metrics and trends from a large OpenedX instance. To fully understand this document, please go through the overview of the notifications feature here: https://openedx.atlassian.net/wiki/x/BIAmGwE
Data Sources:
Notification events – triggered by user or system activity
Notifications table – raw notification records
Here’s how this analysis informed improvements:
Bug detection
Example 1: A sudden drop in read percentage led us to discover that unintended recipients were receiving
new_discussion_postnotifications.Example 2: We noticed the combined count of
response_endorsedandresponse_endorsed_on_threadnotifications exceeded twice the number of responses endorsed—a clear anomaly. Investigation showed an error in how the recipient list was being generated.
Optimizing defaults
Example: We observed high adoption of the
ora_staff_notificationspreference by course teams, so we set it as default ON.
Feature enhancements
Example: Tray-open events revealed some instructors had exceptionally high unread counts due to large course enrollments and because they opted in
new_discussion_postnotifications. We introduced notification grouping, which improved CTR fornew_discussion_postfrom 8% to 27% and overall CTR from 23% to 30%.
Images and code snippets in this document need to be expanded to be viewed.
Notification Events
Notification events and their triggers are as follows:
edx.notifications.generated: A notification is created in the table.edx.notifications.read: A notification is clicked.edx.notifications.tray_opened: Tray is opened.edx.notifications.preferences.updated: A preference is updated (except cadence change).edx.notifications.app_all_read: Mark all read button in tray is clicked.edx.notifications.email_digest: When a notification email is sent to a user.edx.notifications.preferences.one_click_unsubscribe: One-click unsubscribe is used.
Platform Activities v.s. Notification Types
Notifications are automatically triggered via edX platform activities. Listed below is a mapping between these activities and the type of notifications they CAN trigger.
Platform area | Activity | Notification type |
|---|---|---|
Forum | New response |
|
New comment |
| |
New discussion post |
| |
New question post |
| |
New post with notify all learners option |
| |
Post/response/comment reported |
| |
Response endorsed |
| |
Course update | New course update |
|
Grading | New ORA submission requiring staff grading |
|
Grade assigned to ORA submission |
|
Notifications count
Distribution of all notification types is presented below. Note that these distributions are highly dependent on enrollment counts of courses.
Distribution of only discussions notifications is presented below.
Click-Through Rate (CTR)
Click-through rates (CTRs) are calculated only for tray notifications, not email. They help us monitor engagement, optimize defaults and plan improvements like grouping.
Unlike emails, users can interact with notifications only while they are on the platform. To ensure CTR reflects actual opportunity to click, we exclude any notifications created after the user’s most recent visit, since those were never visible to them.
Here’s is an example query used to calculate CTRs in the table below.
Notification type | CTR (%) last 60 days | Average recipient count per notification | |
|---|---|---|---|
| 1 |
| 36 | 1.00 |
| 2 |
| 25 | 2.07 |
| 3 |
| 30 | 1.00 |
| 4 |
| 40 | 1.00 |
| 5 |
| 29 | 2.2 |
| 6 |
| 27 | 24.92 |
| 7 |
| 7 | 23.49 |
| 8 |
| 15 | 931.44 |
| 9 |
| 12 | 3.71 |
| 10 |
| 52 | 1.00 |
| 11 |
| 43 | 1.00 |
| 12 |
| 7 | 2909.15 |
| 13 |
| 13 | 8.98 |
| 14 |
| 24 | 1.00 |
| 15 | Overall CTR excluding | 30 | 1.19 |
| 16 | Overall seen rate excluding | 59 | 1.19 |
Key Trends and Insights
Presented below are some trends and metrics that help us detect any sudden changes in notifications performance.
Trend | Notes | |
|---|---|---|
| 1 | Notifications clicked (read) and tray opens | Tray open count is almost 4 times the count of notifications clicked likely because users view and interact with notifications one after the other. WITH TrayOpenCount AS (
SELECT DATE(timestamp) AS event_date, COUNT(*) AS tray_open_count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name LIKE 'edx.notifications.tray_opened'
-- AND event_data:unseen_notifications_count>0
AND timestamp > dateadd(day, -60, current_date()) AND timestamp < current_date()
GROUP BY DATE(timestamp)
),
ReadNotifications AS (
SELECT DATE(timestamp) AS event_date, COUNT(*) AS notifications_read
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.read'
AND timestamp > dateadd(day, -60, current_date()) AND timestamp < current_date()
GROUP BY DATE(timestamp)
)
SELECT
rn.event_date,
COALESCE(rn.notifications_read, 0) AS notifications_read,
COALESCE(toc.tray_open_count, 0) AS tray_open_count
FROM ReadNotifications rn
LEFT JOIN TrayOpenCount toc ON rn.event_date = toc.event_date
ORDER BY rn.event_date; |
| 2 | Unseen count vs tray count | Count of tray opens when there are no unseen notifications is slightly higher than when there is 1 unseen notification. SELECT event_data:unseen_notifications_count AS Unseen_count, COUNT(*) AS tray_open_count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name LIKE 'edx.notifications.tray_opened'
-- AND event_data:unseen_notifications_count>0
AND timestamp > dateadd(day, -10, current_date()) AND timestamp < current_date()
GROUP BY Unseen_count
ORDER BY Unseen_count DESC |
| 3 | Notifications read by type | SELECT DATE(timestamp) AS event_date, event_data:notification_type::String AS notification_type, COUNT(*) AS notifications_read
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.read'
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp > dateadd(day, -60, current_date()) AND timestamp < current_date()
GROUP BY DATE(timestamp), notification_type |
| 4 | Notification count from event | Count of notifications created from SELECT DATE(timestamp) AS event_date, event_data:notification_type::String AS notification_type, COUNT(*) AS notifications_read
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.generated'
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp > dateadd(day, -60, current_date()) AND timestamp < current_date()
GROUP BY DATE(timestamp), notification_type |
| 5 | Notifications created from DB | This graph may seem very different from the notification count from event because notifications for new discussion or question post, course updates and notify all learners emit only one event but can have a lot of recipients. And each recipient has their own row in the notifications DB. SELECT DATE(CREATED) as NotificationDate, NOTIFICATION_TYPE, COUNT(*) as TotalCount
FROM lms.notifications_notification
WHERE CREATED > dateadd(day, -60, current_date()) AND CREATED < current_date()
AND COURSE_ID != 'course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(CREATED), NOTIFICATION_TYPE
ORDER BY DATE(CREATED) DESC |
| 6 | Tray preference turned ON | SELECT DATE(TIMESTAMP), CASE
WHEN EVENT_DATA:notification_type::String='core' THEN 'Discussion Activity'
WHEN EVENT_DATA:notification_type::String='new_question_post' THEN 'New Question Post'
WHEN EVENT_DATA:notification_type::String='new_discussion_post' THEN 'New Discussion Post'
WHEN EVENT_DATA:notification_type::String='new_instructor_all_learners_post' THEN 'New posts from instructors'
WHEN EVENT_DATA:notification_type::String='content_reported' THEN 'Content Reported'
WHEN EVENT_DATA:notification_type::String='ora_staff_notifications' THEN 'New ORA submission for staff grading'
WHEN EVENT_DATA:notification_type::String='ora_grade_assigned' THEN 'Essay assignment grade received'
WHEN EVENT_DATA:notification_type::String='course_updates' THEN 'Course Updates'
WHEN EVENT_DATA:notification_type::String='audit_access_expiring_soon' THEN 'Audit access'
ELSE EVENT_DATA:notification_type::String
END AS Preference, COUNT(*)
FROM tracking_events.tracking_events_with_metadata
WHERE event_name LIKE 'edx.notifications.preferences.updated'
AND TIMESTAMP > DATEADD(day, -60, CURRENT_DATE()) AND TIMESTAMP < CURRENT_DATE()
AND EVENT_DATA:notification_channel::String='web'
AND EVENT_DATA:value=TRUE
GROUP BY DATE(TIMESTAMP), Preference |
| 7 | Tray preference turned OFF | Any spikes or new entries in this trend should be investigated. SELECT DATE(TIMESTAMP), CASE
WHEN EVENT_DATA:notification_type::String='core' THEN 'Discussion Activity'
WHEN EVENT_DATA:notification_type::String='new_question_post' THEN 'New Question Post'
WHEN EVENT_DATA:notification_type::String='new_discussion_post' THEN 'New Discussion Post'
WHEN EVENT_DATA:notification_type::String='new_instructor_all_learners_post' THEN 'New posts from instructors'
WHEN EVENT_DATA:notification_type::String='content_reported' THEN 'Content Reported'
WHEN EVENT_DATA:notification_type::String='ora_staff_notifications' THEN 'New ORA submission for staff grading'
WHEN EVENT_DATA:notification_type::String='ora_grade_assigned' THEN 'Essay assignment grade received'
WHEN EVENT_DATA:notification_type::String='course_updates' THEN 'Course Updates'
WHEN EVENT_DATA:notification_type::String='audit_access_expiring_soon' THEN 'Audit access'
ELSE EVENT_DATA:notification_type::String
END AS Preference, COUNT(*)
FROM tracking_events.tracking_events_with_metadata
WHERE event_name LIKE 'edx.notifications.preferences.updated'
AND TIMESTAMP > DATEADD(day, -60, CURRENT_DATE()) AND TIMESTAMP < CURRENT_DATE()
AND EVENT_DATA:notification_channel::String='web'
AND EVENT_DATA:value=FALSE
GROUP BY DATE(TIMESTAMP), Preference |
| 8 | Read & seen % | Any dips in either of these should be investigated. We’ve caught several bugs, especially related to extra audience members using these two trends. Notifications with type WITH TotalNotifications AS (
SELECT DATE(CREATED) as NotificationDate, COUNT(*) as TotalCount
FROM lms.notifications_notification
WHERE CREATED > DATEADD(day, -60, CURRENT_DATE()) AND CREATED < CURRENT_DATE()
AND NOTIFICATION_TYPE NOT IN ('content_reported', 'course_updates', 'new_instructor_all_learners_post')
AND COURSE_ID != 'course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(CREATED)
),
ReadNotifications AS (
SELECT DATE(CREATED) as NotificationDate, COUNT(*) as ReadCount
FROM lms.notifications_notification
WHERE CREATED > DATEADD(day, -60, CURRENT_DATE()) AND CREATED < CURRENT_DATE()
AND LAST_READ IS NOT NULL
AND NOTIFICATION_TYPE NOT IN ('content_reported', 'course_updates', 'new_instructor_all_learners_post')
AND COURSE_ID != 'course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(CREATED)
),
SeenNotifications AS (
SELECT DATE(CREATED) as NotificationDate, COUNT(*) as SeenCount
FROM lms.notifications_notification
WHERE CREATED > DATEADD(day, -60, CURRENT_DATE()) AND CREATED < CURRENT_DATE()
AND LAST_SEEN IS NOT NULL
AND NOTIFICATION_TYPE NOT IN ('content_reported', 'course_updates', 'new_instructor_all_learners_post')
AND COURSE_ID != 'course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(CREATED)
)
SELECT
tn.NotificationDate, tn.TotalCount, rn.ReadCount,
CASE
WHEN tn.TotalCount = 0 THEN 0
ELSE rn.ReadCount::FLOAT / tn.TotalCount *100
END as ReadRatio, sn.SeenCount,
CASE
WHEN tn.TotalCount = 0 THEN 0
ELSE sn.SeenCount::FLOAT / tn.TotalCount *100
END as SeenRatio
FROM TotalNotifications tn
LEFT JOIN ReadNotifications rn ON tn.NotificationDate = rn.NotificationDate
LEFT JOIN SeenNotifications sn ON tn.NotificationDate = sn.NotificationDate; |
User Activity and Notification Volume Trends
These 10 trends compare three distinct counts related to notification activity and function as a sanity-check:
Event count for the source activity: This refers to the number of times a specific activity occurs.
Example: The event
edx.forum.thread.createdis emitted every time a new discussion thread is posted.
Notification event count: This tracks how often the notification system generates a notification in response to those activities.
Example: The event
edx.notifications.generatedis emitted whenever a notification is created. This event includes metadata such as the notification type and associated user IDs.
Notification records in the database: This represents the actual number of user-level notification entries stored in the database.
A single
edx.notifications.generatedevent may result in millions of database entries — one per recipient. For instance, if a course update notification is intended for 500,000 users, the system emits just one event, but inserts 500,000 records into the notifications table (one per user).
Activity/ Trend | Notes | |
|---|---|---|
| 1 | Forum response Notification type: User-level |
SELECT
COALESCE(a.event_date, b.event_date, c.event_date) AS date,
a.count AS Notification_count_from_tracking_event,
b.count AS Notification_count_from_table,
c.count AS Response_count
FROM
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.generated'
AND event_data:notification_type IN ('new_response', 'response_on_followed_post')
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(timestamp)) a
FULL OUTER JOIN
(SELECT DATE(created) AS event_date, COUNT(*) AS count
FROM lms.notifications_notification
WHERE created BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND notification_type IN ('new_response', 'response_on_followed_post')
AND COURSE_ID!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(created)) b
ON a.event_date = b.event_date
FULL OUTER JOIN
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.forum.response.created'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(timestamp)) c
ON COALESCE(a.event_date, b.event_date) = c.event_date
ORDER BY date; |
| 2 | Forum comment Notification type: User-level |
SELECT
COALESCE(a.event_date, b.event_date, c.event_date) AS date,
a.count AS Notification_count_from_tracking_event,
b.count AS Notification_count_from_table,
c.count AS Comment_count
FROM
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.generated'
AND event_data:notification_type IN ('new_comment', 'new_comment_on_response', 'comment_on_followed_post')
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(timestamp)) a
FULL OUTER JOIN
(SELECT DATE(created) AS event_date, COUNT(*) AS count
FROM lms.notifications_notification
WHERE created BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND notification_type IN ('new_comment', 'new_comment_on_response', 'comment_on_followed_post')
AND COURSE_ID!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(created)) b
ON a.event_date = b.event_date
FULL OUTER JOIN
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.forum.comment.created'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(timestamp)) c
ON COALESCE(a.event_date, b.event_date) = c.event_date
ORDER BY date; |
| 3 | Forum question thread Notification type: Course-level |
SELECT
COALESCE(a.event_date, b.event_date, c.event_date) AS date,
a.count AS Notification_count_from_tracking_event,
b.count AS Notification_count_from_table,
c.count AS Question_thread_count
FROM
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.generated'
AND event_data:notification_type = 'new_question_post'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(timestamp)) a
FULL OUTER JOIN
(SELECT DATE(created) AS event_date, COUNT(*) AS count
FROM lms.notifications_notification
WHERE created BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND notification_type = 'new_question_post'
AND COURSE_ID!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(created)) b
ON a.event_date = b.event_date
FULL OUTER JOIN
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.forum.thread.created'
AND event_data:thread_type = 'question'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(timestamp)) c
ON COALESCE(a.event_date, b.event_date) = c.event_date
ORDER BY date; |
| 4 | Forum discussion thread Notification type: Course-level Grouping enabled |
SELECT
COALESCE(a.event_date, b.event_date, c.event_date) AS date,
a.count AS Notification_count_from_tracking_event,
b.count AS Notification_count_from_table,
c.count AS Discussion_thread_count
FROM
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.generated'
AND event_data:notification_type = 'new_discussion_post'
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) a
FULL OUTER JOIN
(SELECT DATE(created) AS event_date, COUNT(*) AS count
FROM lms.notifications_notification
WHERE created BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND notification_type IN ('new_discussion_post', 'new_discussion_posts') -- Name was changed a few months back
AND COURSE_ID!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(created)) b
ON a.event_date = b.event_date
FULL OUTER JOIN
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.forum.thread.created'
AND event_data:thread_type = 'discussion'
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) c
ON COALESCE(a.event_date, b.event_date) = c.event_date
ORDER BY date; |
| 5 | Forum content reported Notification type: Course-level |
SELECT
COALESCE(a.event_date, b.event_date, c.event_date) AS date,
a.count AS Notification_count_from_tracking_event,
b.count AS Notification_count_from_table,
c.count AS Reported_content_count
FROM
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.generated'
AND event_data:notification_type = 'content_reported'
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) a
FULL OUTER JOIN
(SELECT DATE(created) AS event_date, COUNT(*) AS count
FROM lms.notifications_notification
WHERE created BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND notification_type = 'content_reported'
AND COURSE_ID!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(created)) b
ON a.event_date = b.event_date
FULL OUTER JOIN
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name IN ('edx.forum.thread.reported', 'edx.forum.response.reported', 'edx.forum.comment.reported')
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) c
ON COALESCE(a.event_date, b.event_date) = c.event_date
ORDER BY date; |
| 6 | Forum response endorsed Notification type: User-level |
SELECT
COALESCE(a.event_date, b.event_date, c.event_date) AS date,
a.count AS Notification_count_from_tracking_event,
b.count AS Notification_count_from_table,
c.count AS Response_endorsed_count
FROM
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.generated'
AND event_data:notification_type IN ('response_endorsed', 'response_endorsed_on_thread')
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) a
FULL OUTER JOIN
(SELECT DATE(created) AS event_date, COUNT(*) AS count
FROM lms.notifications_notification
WHERE created BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND notification_type IN ('response_endorsed', 'response_endorsed_on_thread')
AND COURSE_ID!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(created)) b
ON a.event_date = b.event_date
FULL OUTER JOIN
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.forum.response.mark'
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) c
ON COALESCE(a.event_date, b.event_date) = c.event_date
ORDER BY date; |
| 7 | Forum notify all learners thread Notification type: Course-level |
SELECT
COALESCE(a.event_date, b.event_date, c.event_date) AS date,
a.count AS Notification_count_from_tracking_event,
b.count AS Notification_count_from_table,
c.count AS Notify_leaners_thread_count
FROM
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.generated'
AND event_data:notification_type = 'new_instructor_all_learners_post'
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) a
FULL OUTER JOIN
(SELECT DATE(created) AS event_date, COUNT(*) AS count
FROM lms.notifications_notification
WHERE created BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND notification_type = 'new_instructor_all_learners_post'
AND COURSE_ID!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(created)) b
ON a.event_date = b.event_date
FULL OUTER JOIN
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name='edx.forum.thread.created'
AND EVENT_DATA:options:notify_all_learners=TRUE
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) c
ON COALESCE(a.event_date, b.event_date) = c.event_date
ORDER BY date; |
| 8 | Course update Notification type: Course-level |
SELECT
COALESCE(a.event_date, b.event_date, c.event_date) AS date,
a.count AS Notification_count_from_tracking_event,
b.count AS Notification_count_from_table,
c.count AS Course_updates_count
FROM
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.generated'
AND event_data:notification_type IN ('course_update', 'course_updates')
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) a
FULL OUTER JOIN
(SELECT DATE(created) AS event_date, COUNT(*) AS count
FROM lms.notifications_notification
WHERE created BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND notification_type IN ('course_update', 'course_updates')
AND COURSE_ID!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(created)) b
ON a.event_date = b.event_date
FULL OUTER JOIN
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name='edx.contentstore.course_update'
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) c
ON COALESCE(a.event_date, b.event_date) = c.event_date
ORDER BY date; |
| 9 | ORA grade assigned Notification type: User-level |
SELECT
COALESCE(a.event_date, b.event_date, c.event_date) AS date,
a.count AS Notification_count_from_tracking_event,
b.count AS Notification_count_from_table,
c.count AS All_ORA_submission_count
FROM
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.generated'
AND event_data:notification_type = 'ora_grade_assigned'
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) a
FULL OUTER JOIN
(SELECT DATE(created) AS event_date, COUNT(*) AS count
FROM lms.notifications_notification
WHERE created BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND notification_type = 'ora_grade_assigned'
AND COURSE_ID!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(created)) b
ON a.event_date = b.event_date
FULL OUTER JOIN
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name='openassessmentblock.create_submission'
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) c
ON COALESCE(a.event_date, b.event_date) = c.event_date
ORDER BY date; |
| 10 | ORA submission for staff grading Notification type: Course-level Grouping enabled |
SELECT
COALESCE(a.event_date, b.event_date, c.event_date) AS date,
a.count AS Notification_count_from_tracking_event,
b.count AS Notification_count_from_table,
c.count AS All_ORA_submission_count
FROM
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name = 'edx.notifications.generated'
AND event_data:notification_type IN ('ora_staff_notification', 'ora_staff_notifications')
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) a
FULL OUTER JOIN
(SELECT DATE(created) AS event_date, COUNT(*) AS count
FROM lms.notifications_notification
WHERE created BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
AND notification_type IN ('ora_staff_notification', 'ora_staff_notifications')
AND COURSE_ID!='course-v1:edX+DemoX.1+2T2019'
GROUP BY DATE(created)) b
ON a.event_date = b.event_date
FULL OUTER JOIN
(SELECT DATE(timestamp) AS event_date, COUNT(*) AS count
FROM tracking_events.tracking_events_with_metadata
WHERE event_name='openassessmentblock.create_submission'
AND COURSERUN_KEY!='course-v1:edX+DemoX.1+2T2019'
AND timestamp BETWEEN DATEADD(day, -59, CURRENT_DATE()) AND CURRENT_DATE()
GROUP BY DATE(timestamp)) c
ON COALESCE(a.event_date, b.event_date) = c.event_date
ORDER BY date; |
Email notifications
Activity/ Trend | Notes | |
|---|---|---|
| 1 | Notification email types |
SELECT DATE(TIMESTAMP), EVENT_DATA:cadence_type::String, COUNT(*)
FROM tracking_events.tracking_events_with_metadata
WHERE event_name ='edx.notifications.email_digest'
AND TIMESTAMP>dateadd(day, -60, current_date()) AND TIMESTAMP < current_date()
GROUP BY DATE(TIMESTAMP), EVENT_DATA:cadence_type::String
ORDER BY DATE(TIMESTAMP), EVENT_DATA:cadence_type::String DESC |
| 2 | One-click unsubscribes |
SELECT TIMESTAMP, EVENT_DATA:is_preference_updated, EVENT_DATA:username::String AS Username, EVENT_DATA:event_type::String AS Event_type
FROM prod.tracking_events.tracking_events_with_metadata
WHERE event_name='edx.notifications.preferences.one_click_unsubscribe'
AND TIMESTAMP>dateadd(day, -60, current_date()) AND TIMESTAMP < current_date()
ORDER BY USERNAME DESC, TIMESTAMP DESC |
| 3 | Email preferences turned OFF | SELECT DATE(TIMESTAMP), CASE
WHEN EVENT_DATA:notification_type::String='core' THEN 'Discussion Activity'
WHEN EVENT_DATA:notification_type::String='new_question_post' THEN 'New Question Post'
WHEN EVENT_DATA:notification_type::String='new_discussion_post' THEN 'New Discussion Post'
WHEN EVENT_DATA:notification_type::String='new_instructor_all_learners_post' THEN 'New posts from instructors'
WHEN EVENT_DATA:notification_type::String='content_reported' THEN 'Content Reported'
WHEN EVENT_DATA:notification_type::String='ora_staff_notifications' THEN 'New ORA submission for staff grading'
WHEN EVENT_DATA:notification_type::String='ora_grade_assigned' THEN 'Essay assignment grade received'
WHEN EVENT_DATA:notification_type::String='course_updates' THEN 'Course Updates'
WHEN EVENT_DATA:notification_type::String='audit_access_expiring_soon' THEN 'Audit access'
ELSE EVENT_DATA:notification_type::String
END AS Preference, COUNT(*)
FROM tracking_events.tracking_events_with_metadata
WHERE event_name LIKE 'edx.notifications.preferences.updated'
AND TIMESTAMP > DATEADD(day, -60, CURRENT_DATE()) AND TIMESTAMP < CURRENT_DATE()
AND EVENT_DATA:notification_channel::String='email'
AND EVENT_DATA:value=FALSE
GROUP BY DATE(TIMESTAMP), Preference
|
| 4 | Email preferences turned ON | SELECT DATE(TIMESTAMP), CASE
WHEN EVENT_DATA:notification_type::String='core' THEN 'Discussion Activity'
WHEN EVENT_DATA:notification_type::String='new_question_post' THEN 'New Question Post'
WHEN EVENT_DATA:notification_type::String='new_discussion_post' THEN 'New Discussion Post'
WHEN EVENT_DATA:notification_type::String='new_instructor_all_learners_post' THEN 'New posts from instructors'
WHEN EVENT_DATA:notification_type::String='content_reported' THEN 'Content Reported'
WHEN EVENT_DATA:notification_type::String='ora_staff_notifications' THEN 'New ORA submission for staff grading'
WHEN EVENT_DATA:notification_type::String='ora_grade_assigned' THEN 'Essay assignment grade received'
WHEN EVENT_DATA:notification_type::String='course_updates' THEN 'Course Updates'
WHEN EVENT_DATA:notification_type::String='audit_access_expiring_soon' THEN 'Audit access'
ELSE EVENT_DATA:notification_type::String
END AS Preference, COUNT(*)
FROM tracking_events.tracking_events_with_metadata
WHERE event_name LIKE 'edx.notifications.preferences.updated'
AND TIMESTAMP > DATEADD(day, -60, CURRENT_DATE()) AND TIMESTAMP < CURRENT_DATE()
AND EVENT_DATA:notification_channel::String='email'
AND EVENT_DATA:value<>FALSE
GROUP BY DATE(TIMESTAMP), Preference |
| 5 | Email cadence preference changed | SELECT DATE(TIMESTAMP), CASE
WHEN EVENT_DATA:notification_type::String='core' THEN 'Discussion Activity'
WHEN EVENT_DATA:notification_type::String='new_question_post' THEN 'New Question Post'
WHEN EVENT_DATA:notification_type::String='new_discussion_post' THEN 'New Discussion Post'
WHEN EVENT_DATA:notification_type::String='new_instructor_all_learners_post' THEN 'New posts from instructors'
WHEN EVENT_DATA:notification_type::String='content_reported' THEN 'Content Reported'
WHEN EVENT_DATA:notification_type::String='ora_staff_notifications' THEN 'New ORA submission for staff grading'
WHEN EVENT_DATA:notification_type::String='ora_grade_assigned' THEN 'Essay assignment grade received'
WHEN EVENT_DATA:notification_type::String='course_updates' THEN 'Course Updates'
WHEN EVENT_DATA:notification_type::String='audit_access_expiring_soon' THEN 'Audit access'
ELSE EVENT_DATA:notification_type::String
END AS Preference, COUNT(*)
FROM tracking_events.tracking_events_with_metadata
WHERE event_name LIKE 'edx.notifications.preferences.updated'
AND TIMESTAMP > DATEADD(day, -60, CURRENT_DATE()) AND TIMESTAMP < CURRENT_DATE()
AND EVENT_DATA:notification_channel::String='email'
AND EVENT_DATA:value<>FALSE
GROUP BY DATE(TIMESTAMP), Preference SELECT DATE(TIMESTAMP), EVENT_DATA:value::String AS Cadence, COUNT(*)
FROM tracking_events.tracking_events_with_metadata
WHERE event_name LIKE 'edx.notifications.preferences.updated'
AND TIMESTAMP > DATEADD(day, -60, CURRENT_DATE()) AND TIMESTAMP < CURRENT_DATE()
AND EVENT_DATA:notification_channel::String='email_cadence'
GROUP BY DATE(TIMESTAMP), Cadence |