What goes in a community engagement dashboard?
An engagement dashboard measures whether the community is a conversation or a broadcast: how much gets posted, how much of it gets answered, how fast, and how many people carry the load. The uncomfortable cards — unanswered questions and contributor concentration — are the ones worth building first.
Which cards belong on this dashboard?
- Posts, replies, and reactions per week
- Active member ratio: active members ÷ registered members
- Top contributors by replies, with staff and non-staff separated
- Unanswered questions older than 48 hours
- Median time to first reply, by week
- Replies per topic distribution
- Share of activity from staff vs. community members
- Channels or categories ranked by activity and by unanswered rate
What data does this dashboard need?
- Posts and replies with member ID, topic ID, parent post ID, and timestamps
- A flag distinguishing questions from discussion posts
- A staff or team-member flag on the member record
- Reactions or likes joined to the post they belong to
- Category, channel, or space labels for the breakdowns
How do you build it?
- Land forum, community-platform, and event data in a database and keep member IDs, post timestamps, event IDs, and RSVP status.
- Build models at the grain this dashboard needs, with the active-member window and the check-in rule as explicit columns.
- Create one saved question per card and certify the shared models and definitions.
- Add dashboard filters for Date range, category or channel, staff vs. community, post type, member segment.
- Show data freshness and the definitions in use — community exports run on a schedule, and every viewer should know what "active" means here.
Example card SQL
WITH questions AS (
SELECT
p.post_id,
p.topic_id,
p.created_at
FROM community_posts p
WHERE p.parent_post_id IS NULL
AND p.post_type = 'question'
AND p.created_at >= CURRENT_DATE - INTERVAL '90 days'
), first_reply AS (
-- Only replies from someone other than the asker count as a response.
SELECT
q.post_id,
MIN(r.created_at) AS first_reply_at
FROM questions q
JOIN community_posts r
ON r.topic_id = q.topic_id
AND r.created_at > q.created_at
AND r.member_id <> (
SELECT member_id FROM community_posts WHERE post_id = q.post_id
)
GROUP BY q.post_id
)
SELECT
date_trunc('week', q.created_at)::date AS week,
COUNT(*) AS questions_asked,
COUNT(f.first_reply_at) AS questions_answered,
ROUND(
100.0 * COUNT(f.first_reply_at) / NULLIF(COUNT(*), 0), 1
) AS answered_pct,
ROUND(
EXTRACT(epoch FROM PERCENTILE_CONT(0.5) WITHIN GROUP (
ORDER BY f.first_reply_at - q.created_at
)) / 3600.0, 1
) AS median_hours_to_first_reply
FROM questions q
LEFT JOIN first_reply f USING (post_id)
GROUP BY 1
ORDER BY 1;