Is your institution pulling Canvas Data 2? You can find total_activity_time in CD2 Enrollments.
e.g.
WITH enrollment_query as (
SELECT c.course_code,
c.name as course_name,
c.id as course_id,
e.course_section_id,
cs.name AS course_section_name,
u.id AS user_id,
u.sortable_name,
(
(e.last_activity_at AT TIME ZONE 'UTC') AT TIME ZONE 'Australia/Sydney'
) AS last_activity_SYD,
e.total_activity_time
FROM canvas.scores sc
JOIN canvas.enrollments e ON e.id = sc.enrollment_id
JOIN canvas.course_sections cs ON cs.id = e.course_section_id
JOIN canvas.courses c ON e.course_id = c.id
JOIN canvas.users u ON u.id = e.user_id
WHERE c.workflow_state <> 'deleted'
AND e.type = 'StudentEnrollment'
AND e.workflow_state NOT IN ('inactive', 'deleted')
AND c.workflow_state = 'available'
AND sc.course_score = TRUE -- use this just for overall course score
)
SELECT eq.course_code,
eq.course_name,
eq.course_id,
eq.course_section_name,
to_char(
avg(eq.total_activity_time) * interval '1 second',
'HH24:MI:SS'
) as avg_total_activity_time
FROM enrollment_query eq
GROUP BY ROLLUP(
eq.course_code,
eq.course_name,
eq.course_id,
eq.course_section_name
)
ORDER BY eq.course_code,
eq.course_name,
eq.course_id,
eq.course_section_name
The above is a little convoluted as I've just pulled it together from an existing snippet ... you don't need canvas.scores as the starting join point... you could drop the seconds, could add count(*) AS n, stddev_pop(total_activity_time) and calc the 95%CI, drill further into the grade schema/final mark, etc. I've filtered inactive, deleted above, but they are also part of the course population and perhaps 'the story', etc. Anyway, it's a possible solution that doesn't involve APIs or manual entry etc.