glean_customer_event table to reproduce the metrics shown in the Glean Insights dashboard.
Before running:
- Replace
<glean_customer_event_table>with your company’s actual table name (e.g.,your_project.glean_customer_event.glean_customer_event_external) - Adjust the
start_dateandend_dateDECLARE values as needed
User Activity & Engagement
Usage Timeseries (DAU/WAU/MAU)
Usage Timeseries (DAU/WAU/MAU)
- Output: Daily/Weekly/Monthly active users across Search, Assistant, and Agents
- Grain: One row per day
- Use Case: Track overall platform adoption trends over time
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
all_workflow_executions AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, workflow_execution.workflowid AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, COALESCE(jsonPayload.workflowrun.initiator = 'RECOMMENDATION', FALSE) AS is_proactively_executed
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND (jsonPayload.workflowrun.feature != 'AGENT_LIVE_PREVIEW' OR jsonPayload.workflowrun.feature IS NULL)
AND (
jsonPayload.workflowrun.initiator IN ('USER', 'REST_API', 'AUTOMATION', 'RECOMMENDATION')
OR (
-- Null handling only during buggy period: https://askscio.slack.com/archives/C08BYEY9TC6/p1757033877342169
datepartition >= DATE '2025-08-12'
AND datepartition < DATE '2025-09-22'
AND jsonPayload.workflowrun.initiator IS NULL
)
)
AND workflow_execution.status = 'SUCCESS'
AND workflow_execution.workflowid IS NOT NULL
AND workflow_execution.workflowid NOT LIKE 'UNSAVED_%'
AND workflow_execution.workflowid != 'AGENTIC_WORKFLOW_ID'
),
agent_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, COUNT(DISTINCT run_id) AS num_all_agent_runs
-- Proactively executed agent runs (mostly in gleanbot context) are not DAU worthy
, COUNT(DISTINCT CASE WHEN NOT is_proactively_executed THEN run_id END) AS num_agent_runs
FROM
all_workflow_executions
GROUP BY
1, 2, 3, 4
),
app_usage_from_gleanchat AS (
SELECT
datepartition
, IF(
jsonpayload.chat.workflowrunid IS NOT NULL
AND jsonpayload.chat.workflowrunid != ''
, jsonpayload.chat.workflowrunid
, jsonpayload.chat.qtt
) AS run_id
, jsonpayload.chat.applicationid AS workflow_id
, resource.labels.project_id AS project_id
, MIN_BY(jsonPayload.user.userid, timestamp) AS user_id
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT'
-- Apps always have a 16 letters Id
AND LENGTH(jsonpayload.chat.applicationid) = 16
-- [Shantanu | To Do] Filter to user initiated queries
-- [Shantanu | To Do] Do not read gleanchat data even for backfilling if
-- date is after YYYYMMDD
GROUP BY
1, 2, 3, 4
),
app_usage_from_chat_1_5 AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, jsonPayload.workflowrun.applicationid AS workflow_id
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
and jsonPayload.workflowrun.initiator = 'USER'
AND jsonPayload.workflowrun.applicationid IS NOT NULL
AND jsonPayload.workflowrun.applicationid != ''
AND workflow_execution.status = 'SUCCESS'
),
app_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
-- for ai app usage , num_all_agent_runs and num_agent_runs are same
, COUNT(DISTINCT run_id) AS num_all_agent_runs
, COUNT(DISTINCT run_id) AS num_agent_runs
FROM (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_gleanchat
UNION ALL
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_chat_1_5
)
GROUP BY
1, 2, 3, 4
),
agent_and_app_usage AS (
SELECT
COALESCE(agu.datepartition, apu.datepartition) AS datepartition
, COALESCE(agu.user_id, apu.user_id) AS user_id
, COALESCE(agu.project_id, apu.project_id) AS project_id
, COALESCE(agu.workflow_id, apu.workflow_id) AS workflow_id
-- Only rely on ai apps data if we cant find any agent usage data for it that day
, IF(agu.num_all_agent_runs > 0, agu.num_all_agent_runs, COALESCE(apu.num_all_agent_runs, 0)) AS num_all_agent_runs
, IF(agu.num_agent_runs > 0, agu.num_agent_runs, COALESCE(apu.num_agent_runs, 0)) AS num_agent_runs
FROM
agent_usage AS agu
FULL OUTER JOIN
app_usage AS apu
ON
agu.datepartition = apu.datepartition
AND agu.user_id = apu.user_id
AND agu.project_id = apu.project_id
AND agu.workflow_id = apu.workflow_id
),
agent_feedback AS (
SELECT
datepartition
, project_id
, workflow_id
, user_id
, SUM(CASE WHEN vote = 'UPVOTE' THEN 1 ELSE 0 END) AS num_upvotes
, SUM(CASE WHEN vote = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_downvotes
FROM (
SELECT
datepartition
-- group by message_id to avoid duplicate feedbacks
, jsonPayload.chatfeedback.messageid AS message_id
-- coalesce for backward compatibility with workflowid and agentid
, COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
-- take latest vote. disregard manual feedback
, MAX_BY(jsonPayload.chatfeedback.event, timestamp) AS vote
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
GROUP BY
1, 2, 3, 4, 5
)
GROUP BY
1, 2, 3, 4
),
agent_usage_and_feedback AS (
SELECT
COALESCE(agent_and_app_usage.datepartition, agent_feedback.datepartition) AS datepartition
, COALESCE(agent_and_app_usage.project_id, agent_feedback.project_id) AS project_id
, COALESCE(agent_and_app_usage.user_id, agent_feedback.user_id) AS user_id
, COALESCE(agent_and_app_usage.workflow_id, agent_feedback.workflow_id) AS workflow_id
, COALESCE(agent_and_app_usage.num_all_agent_runs, 0) AS num_all_agent_runs
, COALESCE(agent_and_app_usage.num_agent_runs, 0) AS num_agent_runs
, COALESCE(agent_feedback.num_upvotes, 0) AS num_upvotes
, COALESCE(agent_feedback.num_downvotes, 0) AS num_downvotes
FROM
agent_and_app_usage
FULL OUTER JOIN
agent_feedback
ON
agent_and_app_usage.datepartition = agent_feedback.datepartition
AND agent_and_app_usage.user_id = agent_feedback.user_id
AND agent_and_app_usage.project_id = agent_feedback.project_id
AND agent_and_app_usage.workflow_id = agent_feedback.workflow_id
),
agents_activity_precomputation AS (
SELECT
agent_usage_and_feedback.datepartition
, agent_usage_and_feedback.project_id
, COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, agent_usage_and_feedback.user_id) AS user_id
, agent_usage_and_feedback.workflow_id
, SUM(agent_usage_and_feedback.num_all_agent_runs) AS num_all_agent_runs
, SUM(agent_usage_and_feedback.num_agent_runs) AS num_agent_runs
, SUM(agent_usage_and_feedback.num_upvotes) AS num_upvotes
, SUM(agent_usage_and_feedback.num_downvotes) AS num_downvotes
FROM
agent_usage_and_feedback
LEFT JOIN
id_to_alias
ON
agent_usage_and_feedback.user_id = id_to_alias.aliasid
AND agent_usage_and_feedback.project_id = id_to_alias.project_id
AND agent_usage_and_feedback.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, agent_usage_and_feedback.user_id) = latest_orgchart_data.loggingid
GROUP BY 1, 2, 3, 4
),
all_agents AS (
SELECT
datepartition
, jsonPayload.productsnapshot.workflow.workflowid AS workflow_id
, jsonPayload.productsnapshot.workflow.name
, PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) AS created_at
, IF(PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) = DATE '0001-01-01', NULL, jsonPayload.productsnapshot.workflow.createdby) AS created_by
, jsonPayload.productsnapshot.workflow.namespaceenum AS workflow_type
, jsonPayload.productsnapshot.workflow.namespaceenum = 'AGENT'
AND PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) != DATE '0001-01-01' AS is_agent
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'WORKFLOW'
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
canonicalized_feature_usage AS (
SELECT datepartition,userid,num_searches,num_chats,num_ai_answers,num_summarizations,num_chat_upvotes,num_chat_downvotes,num_client_active_sessions,num_slackbot_useful_responses,num_slackbot_downvotes,num_slackbot_upvotes,num_slackbot_responses,is_active_other FROM canonicalized
),
agents_usage AS (
SELECT
agents_activity_precomputation.datepartition,
agents_activity_precomputation.user_id,
SUM(num_agent_runs) AS num_agent_runs,
SUM(num_all_agent_runs) AS num_all_agent_runs
FROM
agents_activity_precomputation
INNER JOIN
(SELECT DISTINCT workflow_id AS agent_workflow_id FROM all_agents WHERE is_agent) AS a
ON
agents_activity_precomputation.workflow_id = agent_workflow_id
WHERE
(num_agent_runs > 0 OR num_all_agent_runs > 0)
GROUP BY
1, 2
),
combined_usage AS (
SELECT
COALESCE(c.datepartition, a.datepartition) AS datepartition,
COALESCE(c.userid, a.user_id) AS userid,
COALESCE((c.num_searches + c.num_chats + c.num_client_active_sessions + c.num_slackbot_useful_responses + c.num_ai_answers + c.num_summarizations) > 0 OR c.is_active_other, false)
OR COALESCE(a.num_agent_runs > 0, false) AS is_active_overall, -- Deliberately exclude proactive runs (num_all_agent_runs > 0)
COALESCE(c.num_searches, 0) AS num_searches,
COALESCE(c.num_chats, 0) + COALESCE(c.num_ai_answers, 0) + COALESCE(c.num_summarizations, 0) + COALESCE(c.num_slackbot_useful_responses, 0) AS num_assistant_interactions,
COALESCE(a.num_agent_runs, 0) AS num_agent_runs,
COALESCE(a.num_all_agent_runs, 0) AS num_all_agent_runs
FROM
canonicalized_feature_usage c
FULL OUTER JOIN
agents_usage a
ON
c.datepartition = a.datepartition
AND c.userid = a.user_id
)
SELECT
MetricDate,
COUNT(DISTINCT CASE WHEN c.is_active_overall AND DATE(MetricDate) = c.datepartition THEN c.userid END) AS DailyActiveUsers,
COUNT(DISTINCT CASE WHEN c.is_active_overall AND c.datepartition BETWEEN DATE(MetricDate - INTERVAL '6' DAY) AND DATE(MetricDate) THEN c.userid END) AS WeeklyActiveUsers,
COUNT(DISTINCT CASE WHEN c.is_active_overall THEN c.userid END) AS MonthlyActiveUsers,
COUNT(DISTINCT CASE WHEN c.num_searches > 0 AND DATE(MetricDate) = c.datepartition THEN c.userid END) AS SearchDailyActiveUsers,
COUNT(DISTINCT CASE WHEN c.num_searches > 0 AND c.datepartition BETWEEN DATE(MetricDate - INTERVAL '6' DAY) AND DATE(MetricDate) THEN c.userid END) AS SearchWeeklyActiveUsers,
COUNT(DISTINCT CASE WHEN c.num_searches > 0 THEN c.userid END) AS SearchMonthlyActiveUsers,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = c.datepartition THEN num_searches END), 0) AS DailySearchCount,
COUNT(DISTINCT CASE WHEN c.num_assistant_interactions > 0 AND DATE(MetricDate) = c.datepartition THEN c.userid END) AS AssistantDailyActiveUsers,
COUNT(DISTINCT CASE WHEN c.num_assistant_interactions > 0 AND c.datepartition BETWEEN DATE(MetricDate - INTERVAL '6' DAY) AND DATE(MetricDate) THEN c.userid END) AS AssistantWeeklyActiveUsers,
COUNT(DISTINCT CASE WHEN c.num_assistant_interactions > 0 THEN c.userid END) AS AssistantMonthlyActiveUsers,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = c.datepartition THEN num_assistant_interactions END), 0) AS DailyAssistantInteractionsCount,
COUNT(DISTINCT CASE WHEN c.num_agent_runs > 0 AND DATE(MetricDate) = c.datepartition THEN c.userid END) AS AgentsDailyActiveUsers,
COUNT(DISTINCT CASE WHEN c.num_agent_runs > 0 AND c.datepartition BETWEEN DATE(MetricDate - INTERVAL '6' DAY) AND DATE(MetricDate) THEN c.userid END) AS AgentsWeeklyActiveUsers,
COUNT(DISTINCT CASE WHEN c.num_agent_runs > 0 THEN c.userid END) AS AgentsMonthlyActiveUsers,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = c.datepartition THEN num_agent_runs END), 0) AS DailyAgentRunsCount,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = c.datepartition THEN num_all_agent_runs END), 0) AS DailyAllAgentRunsCount
FROM
UNNEST(GENERATE_TIMESTAMP_ARRAY(TIMESTAMP(start_date), TIMESTAMP(end_date), INTERVAL 1 DAY)) AS MetricDate
LEFT JOIN
combined_usage c
ON
c.datepartition BETWEEN DATE(MetricDate - INTERVAL '27' DAY) AND DATE(MetricDate)
-- Do not force Active Users to be present in the Org Chart; include qualifying activity even if not in org chart
LEFT JOIN
glean_customer_event.latest_orgchart_data o
ON
c.userid = o.userid
WHERE
1=1
GROUP BY
1
ORDER BY
1
Department Summary
Department Summary
- Output: Employee count, signup count, and active user counts per department
- Grain: One row per department
- Use Case: Compare adoption and engagement across organizational units
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
all_workflow_executions AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, workflow_execution.workflowid AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, COALESCE(jsonPayload.workflowrun.initiator = 'RECOMMENDATION', FALSE) AS is_proactively_executed
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND (jsonPayload.workflowrun.feature != 'AGENT_LIVE_PREVIEW' OR jsonPayload.workflowrun.feature IS NULL)
AND (
jsonPayload.workflowrun.initiator IN ('USER', 'REST_API', 'AUTOMATION', 'RECOMMENDATION')
OR (
-- Null handling only during buggy period: https://askscio.slack.com/archives/C08BYEY9TC6/p1757033877342169
datepartition >= DATE '2025-08-12'
AND datepartition < DATE '2025-09-22'
AND jsonPayload.workflowrun.initiator IS NULL
)
)
AND workflow_execution.status = 'SUCCESS'
AND workflow_execution.workflowid IS NOT NULL
AND workflow_execution.workflowid NOT LIKE 'UNSAVED_%'
AND workflow_execution.workflowid != 'AGENTIC_WORKFLOW_ID'
),
agent_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, COUNT(DISTINCT run_id) AS num_all_agent_runs
-- Proactively executed agent runs (mostly in gleanbot context) are not DAU worthy
, COUNT(DISTINCT CASE WHEN NOT is_proactively_executed THEN run_id END) AS num_agent_runs
FROM
all_workflow_executions
GROUP BY
1, 2, 3, 4
),
app_usage_from_gleanchat AS (
SELECT
datepartition
, IF(
jsonpayload.chat.workflowrunid IS NOT NULL
AND jsonpayload.chat.workflowrunid != ''
, jsonpayload.chat.workflowrunid
, jsonpayload.chat.qtt
) AS run_id
, jsonpayload.chat.applicationid AS workflow_id
, resource.labels.project_id AS project_id
, MIN_BY(jsonPayload.user.userid, timestamp) AS user_id
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT'
-- Apps always have a 16 letters Id
AND LENGTH(jsonpayload.chat.applicationid) = 16
-- [Shantanu | To Do] Filter to user initiated queries
-- [Shantanu | To Do] Do not read gleanchat data even for backfilling if
-- date is after YYYYMMDD
GROUP BY
1, 2, 3, 4
),
app_usage_from_chat_1_5 AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, jsonPayload.workflowrun.applicationid AS workflow_id
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
and jsonPayload.workflowrun.initiator = 'USER'
AND jsonPayload.workflowrun.applicationid IS NOT NULL
AND jsonPayload.workflowrun.applicationid != ''
AND workflow_execution.status = 'SUCCESS'
),
app_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
-- for ai app usage , num_all_agent_runs and num_agent_runs are same
, COUNT(DISTINCT run_id) AS num_all_agent_runs
, COUNT(DISTINCT run_id) AS num_agent_runs
FROM (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_gleanchat
UNION ALL
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_chat_1_5
)
GROUP BY
1, 2, 3, 4
),
agent_and_app_usage AS (
SELECT
COALESCE(agu.datepartition, apu.datepartition) AS datepartition
, COALESCE(agu.user_id, apu.user_id) AS user_id
, COALESCE(agu.project_id, apu.project_id) AS project_id
, COALESCE(agu.workflow_id, apu.workflow_id) AS workflow_id
-- Only rely on ai apps data if we cant find any agent usage data for it that day
, IF(agu.num_all_agent_runs > 0, agu.num_all_agent_runs, COALESCE(apu.num_all_agent_runs, 0)) AS num_all_agent_runs
, IF(agu.num_agent_runs > 0, agu.num_agent_runs, COALESCE(apu.num_agent_runs, 0)) AS num_agent_runs
FROM
agent_usage AS agu
FULL OUTER JOIN
app_usage AS apu
ON
agu.datepartition = apu.datepartition
AND agu.user_id = apu.user_id
AND agu.project_id = apu.project_id
AND agu.workflow_id = apu.workflow_id
),
agent_feedback AS (
SELECT
datepartition
, project_id
, workflow_id
, user_id
, SUM(CASE WHEN vote = 'UPVOTE' THEN 1 ELSE 0 END) AS num_upvotes
, SUM(CASE WHEN vote = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_downvotes
FROM (
SELECT
datepartition
-- group by message_id to avoid duplicate feedbacks
, jsonPayload.chatfeedback.messageid AS message_id
-- coalesce for backward compatibility with workflowid and agentid
, COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
-- take latest vote. disregard manual feedback
, MAX_BY(jsonPayload.chatfeedback.event, timestamp) AS vote
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
GROUP BY
1, 2, 3, 4, 5
)
GROUP BY
1, 2, 3, 4
),
agent_usage_and_feedback AS (
SELECT
COALESCE(agent_and_app_usage.datepartition, agent_feedback.datepartition) AS datepartition
, COALESCE(agent_and_app_usage.project_id, agent_feedback.project_id) AS project_id
, COALESCE(agent_and_app_usage.user_id, agent_feedback.user_id) AS user_id
, COALESCE(agent_and_app_usage.workflow_id, agent_feedback.workflow_id) AS workflow_id
, COALESCE(agent_and_app_usage.num_all_agent_runs, 0) AS num_all_agent_runs
, COALESCE(agent_and_app_usage.num_agent_runs, 0) AS num_agent_runs
, COALESCE(agent_feedback.num_upvotes, 0) AS num_upvotes
, COALESCE(agent_feedback.num_downvotes, 0) AS num_downvotes
FROM
agent_and_app_usage
FULL OUTER JOIN
agent_feedback
ON
agent_and_app_usage.datepartition = agent_feedback.datepartition
AND agent_and_app_usage.user_id = agent_feedback.user_id
AND agent_and_app_usage.project_id = agent_feedback.project_id
AND agent_and_app_usage.workflow_id = agent_feedback.workflow_id
),
agents_activity_precomputation AS (
SELECT
agent_usage_and_feedback.datepartition
, agent_usage_and_feedback.project_id
, COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, agent_usage_and_feedback.user_id) AS user_id
, agent_usage_and_feedback.workflow_id
, SUM(agent_usage_and_feedback.num_all_agent_runs) AS num_all_agent_runs
, SUM(agent_usage_and_feedback.num_agent_runs) AS num_agent_runs
, SUM(agent_usage_and_feedback.num_upvotes) AS num_upvotes
, SUM(agent_usage_and_feedback.num_downvotes) AS num_downvotes
FROM
agent_usage_and_feedback
LEFT JOIN
id_to_alias
ON
agent_usage_and_feedback.user_id = id_to_alias.aliasid
AND agent_usage_and_feedback.project_id = id_to_alias.project_id
AND agent_usage_and_feedback.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, agent_usage_and_feedback.user_id) = latest_orgchart_data.loggingid
GROUP BY 1, 2, 3, 4
),
all_agents AS (
SELECT
datepartition
, jsonPayload.productsnapshot.workflow.workflowid AS workflow_id
, jsonPayload.productsnapshot.workflow.name
, PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) AS created_at
, IF(PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) = DATE '0001-01-01', NULL, jsonPayload.productsnapshot.workflow.createdby) AS created_by
, jsonPayload.productsnapshot.workflow.namespaceenum AS workflow_type
, jsonPayload.productsnapshot.workflow.namespaceenum = 'AGENT'
AND PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) != DATE '0001-01-01' AS is_agent
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'WORKFLOW'
),
canonicalized_feature_usage AS (
SELECT
*
FROM
canonicalized
WHERE
num_searches > 0 OR num_chats > 0 OR num_client_active_sessions > 0 OR num_slackbot_useful_responses > 0 OR is_active_other
),
agents_usage AS (
SELECT
agents_activity_precomputation.datepartition,
agents_activity_precomputation.user_id,
SUM(num_agent_runs) AS num_agent_runs,
SUM(num_all_agent_runs) AS num_all_agent_runs
FROM
agents_activity_precomputation
INNER JOIN
(SELECT DISTINCT workflow_id AS agent_workflow_id FROM all_agents WHERE is_agent) AS a
ON
agents_activity_precomputation.workflow_id = agent_workflow_id
WHERE
(num_all_agent_runs > 0)
GROUP BY
1, 2
),
orgchart_full_join_feature_usage AS (
SELECT
o.department,
o.userid AS orgchart_userid,
o.signuptime,
COALESCE(c.datepartition, a.datepartition) AS datepartition,
COALESCE(c.userid, CASE WHEN a.num_agent_runs > 0 THEN a.user_id END) AS feature_usage_userid, -- Deliberately exclude proactive runs (num_all_agent_runs > 0)
c.num_searches,
c.num_chats,
a.num_agent_runs,
a.num_all_agent_runs
FROM
glean_customer_event.latest_orgchart_data o
FULL OUTER JOIN
-- Include users in org chart with no activity + users with activity but not in org chart
canonicalized_feature_usage c
ON
c.userid = o.userid
FULL OUTER JOIN
agents_usage a
ON
c.datepartition = a.datepartition
AND c.userid = a.user_id
WHERE
1=1
)
SELECT
department,
COUNT(DISTINCT orgchart_userid) AS NumEmployees,
-- Users in the orgchart with AU-qualifying activity should never be considered not-signed-up.
-- TODO: resolve the KI where users can be active on gleanbot without a signup time
COUNT(DISTINCT CASE WHEN signuptime IS NOT NULL OR feature_usage_userid IS NOT NULL THEN orgchart_userid END) AS NumSignups,
COUNT(DISTINCT CASE WHEN feature_usage_userid IS NOT NULL AND datepartition BETWEEN DATE(end_date) - INTERVAL '27' DAY AND DATE(end_date) THEN feature_usage_userid END) AS MonthlyActiveUsers,
COUNT(DISTINCT CASE WHEN feature_usage_userid IS NOT NULL AND datepartition BETWEEN DATE(end_date) - INTERVAL '6' DAY AND DATE(end_date) THEN feature_usage_userid END) AS WeeklyActiveUsers,
COALESCE(SUM(CASE WHEN datepartition BETWEEN DATE(start_date) AND DATE(end_date) THEN num_searches ELSE 0 END), 0) AS NumSearches,
COUNT(DISTINCT CASE WHEN num_searches > 0 AND datepartition BETWEEN DATE(start_date) AND DATE(end_date) THEN feature_usage_userid END) AS NumSearchUsers,
COALESCE(SUM(CASE WHEN datepartition BETWEEN DATE(start_date) AND DATE(end_date) THEN num_chats ELSE 0 END), 0) AS NumChats,
COUNT(DISTINCT CASE WHEN num_chats > 0 AND datepartition BETWEEN DATE(start_date) AND DATE(end_date) THEN feature_usage_userid END) AS NumChatUsers,
COUNT(DISTINCT CASE WHEN datepartition BETWEEN DATE(end_date) - INTERVAL '27' DAY AND DATE(end_date) AND num_searches > 0 THEN feature_usage_userid END) AS MonthlySearchActiveUsers,
COUNT(DISTINCT CASE WHEN datepartition BETWEEN DATE(end_date) - INTERVAL '6' DAY AND DATE(end_date) AND num_searches > 0 THEN feature_usage_userid END) AS WeeklySearchActiveUsers,
COUNT(DISTINCT CASE WHEN datepartition BETWEEN DATE(end_date) - INTERVAL '27' DAY AND DATE(end_date) AND num_chats > 0 THEN feature_usage_userid END) AS MonthlyChatActiveUsers,
COUNT(DISTINCT CASE WHEN datepartition BETWEEN DATE(end_date) - INTERVAL '6' DAY AND DATE(end_date) AND num_chats > 0 THEN feature_usage_userid END) AS WeeklyChatActiveUsers
FROM
orgchart_full_join_feature_usage
GROUP BY
1
Top Users
Top Users
- Output: Per-user activity counts (searches, chats, sessions, agent runs)
- Grain: One row per user
- Use Case: Identify power users and engagement distribution
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
all_workflow_executions AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, workflow_execution.workflowid AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, COALESCE(jsonPayload.workflowrun.initiator = 'RECOMMENDATION', FALSE) AS is_proactively_executed
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND (jsonPayload.workflowrun.feature != 'AGENT_LIVE_PREVIEW' OR jsonPayload.workflowrun.feature IS NULL)
AND (
jsonPayload.workflowrun.initiator IN ('USER', 'REST_API', 'AUTOMATION', 'RECOMMENDATION')
OR (
-- Null handling only during buggy period: https://askscio.slack.com/archives/C08BYEY9TC6/p1757033877342169
datepartition >= DATE '2025-08-12'
AND datepartition < DATE '2025-09-22'
AND jsonPayload.workflowrun.initiator IS NULL
)
)
AND workflow_execution.status = 'SUCCESS'
AND workflow_execution.workflowid IS NOT NULL
AND workflow_execution.workflowid NOT LIKE 'UNSAVED_%'
AND workflow_execution.workflowid != 'AGENTIC_WORKFLOW_ID'
),
agent_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, COUNT(DISTINCT run_id) AS num_all_agent_runs
-- Proactively executed agent runs (mostly in gleanbot context) are not DAU worthy
, COUNT(DISTINCT CASE WHEN NOT is_proactively_executed THEN run_id END) AS num_agent_runs
FROM
all_workflow_executions
GROUP BY
1, 2, 3, 4
),
app_usage_from_gleanchat AS (
SELECT
datepartition
, IF(
jsonpayload.chat.workflowrunid IS NOT NULL
AND jsonpayload.chat.workflowrunid != ''
, jsonpayload.chat.workflowrunid
, jsonpayload.chat.qtt
) AS run_id
, jsonpayload.chat.applicationid AS workflow_id
, resource.labels.project_id AS project_id
, MIN_BY(jsonPayload.user.userid, timestamp) AS user_id
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT'
-- Apps always have a 16 letters Id
AND LENGTH(jsonpayload.chat.applicationid) = 16
-- [Shantanu | To Do] Filter to user initiated queries
-- [Shantanu | To Do] Do not read gleanchat data even for backfilling if
-- date is after YYYYMMDD
GROUP BY
1, 2, 3, 4
),
app_usage_from_chat_1_5 AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, jsonPayload.workflowrun.applicationid AS workflow_id
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
and jsonPayload.workflowrun.initiator = 'USER'
AND jsonPayload.workflowrun.applicationid IS NOT NULL
AND jsonPayload.workflowrun.applicationid != ''
AND workflow_execution.status = 'SUCCESS'
),
app_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
-- for ai app usage , num_all_agent_runs and num_agent_runs are same
, COUNT(DISTINCT run_id) AS num_all_agent_runs
, COUNT(DISTINCT run_id) AS num_agent_runs
FROM (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_gleanchat
UNION ALL
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_chat_1_5
)
GROUP BY
1, 2, 3, 4
),
agent_and_app_usage AS (
SELECT
COALESCE(agu.datepartition, apu.datepartition) AS datepartition
, COALESCE(agu.user_id, apu.user_id) AS user_id
, COALESCE(agu.project_id, apu.project_id) AS project_id
, COALESCE(agu.workflow_id, apu.workflow_id) AS workflow_id
-- Only rely on ai apps data if we cant find any agent usage data for it that day
, IF(agu.num_all_agent_runs > 0, agu.num_all_agent_runs, COALESCE(apu.num_all_agent_runs, 0)) AS num_all_agent_runs
, IF(agu.num_agent_runs > 0, agu.num_agent_runs, COALESCE(apu.num_agent_runs, 0)) AS num_agent_runs
FROM
agent_usage AS agu
FULL OUTER JOIN
app_usage AS apu
ON
agu.datepartition = apu.datepartition
AND agu.user_id = apu.user_id
AND agu.project_id = apu.project_id
AND agu.workflow_id = apu.workflow_id
),
agent_feedback AS (
SELECT
datepartition
, project_id
, workflow_id
, user_id
, SUM(CASE WHEN vote = 'UPVOTE' THEN 1 ELSE 0 END) AS num_upvotes
, SUM(CASE WHEN vote = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_downvotes
FROM (
SELECT
datepartition
-- group by message_id to avoid duplicate feedbacks
, jsonPayload.chatfeedback.messageid AS message_id
-- coalesce for backward compatibility with workflowid and agentid
, COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
-- take latest vote. disregard manual feedback
, MAX_BY(jsonPayload.chatfeedback.event, timestamp) AS vote
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
GROUP BY
1, 2, 3, 4, 5
)
GROUP BY
1, 2, 3, 4
),
agent_usage_and_feedback AS (
SELECT
COALESCE(agent_and_app_usage.datepartition, agent_feedback.datepartition) AS datepartition
, COALESCE(agent_and_app_usage.project_id, agent_feedback.project_id) AS project_id
, COALESCE(agent_and_app_usage.user_id, agent_feedback.user_id) AS user_id
, COALESCE(agent_and_app_usage.workflow_id, agent_feedback.workflow_id) AS workflow_id
, COALESCE(agent_and_app_usage.num_all_agent_runs, 0) AS num_all_agent_runs
, COALESCE(agent_and_app_usage.num_agent_runs, 0) AS num_agent_runs
, COALESCE(agent_feedback.num_upvotes, 0) AS num_upvotes
, COALESCE(agent_feedback.num_downvotes, 0) AS num_downvotes
FROM
agent_and_app_usage
FULL OUTER JOIN
agent_feedback
ON
agent_and_app_usage.datepartition = agent_feedback.datepartition
AND agent_and_app_usage.user_id = agent_feedback.user_id
AND agent_and_app_usage.project_id = agent_feedback.project_id
AND agent_and_app_usage.workflow_id = agent_feedback.workflow_id
),
agents_activity_precomputation AS (
SELECT
agent_usage_and_feedback.datepartition
, agent_usage_and_feedback.project_id
, COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, agent_usage_and_feedback.user_id) AS user_id
, agent_usage_and_feedback.workflow_id
, SUM(agent_usage_and_feedback.num_all_agent_runs) AS num_all_agent_runs
, SUM(agent_usage_and_feedback.num_agent_runs) AS num_agent_runs
, SUM(agent_usage_and_feedback.num_upvotes) AS num_upvotes
, SUM(agent_usage_and_feedback.num_downvotes) AS num_downvotes
FROM
agent_usage_and_feedback
LEFT JOIN
id_to_alias
ON
agent_usage_and_feedback.user_id = id_to_alias.aliasid
AND agent_usage_and_feedback.project_id = id_to_alias.project_id
AND agent_usage_and_feedback.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, agent_usage_and_feedback.user_id) = latest_orgchart_data.loggingid
GROUP BY 1, 2, 3, 4
),
all_agents AS (
SELECT
datepartition
, jsonPayload.productsnapshot.workflow.workflowid AS workflow_id
, jsonPayload.productsnapshot.workflow.name
, PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) AS created_at
, IF(PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) = DATE '0001-01-01', NULL, jsonPayload.productsnapshot.workflow.createdby) AS created_by
, jsonPayload.productsnapshot.workflow.namespaceenum AS workflow_type
, jsonPayload.productsnapshot.workflow.namespaceenum = 'AGENT'
AND PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) != DATE '0001-01-01' AS is_agent
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'WORKFLOW'
),
canonicalized_feature_usage AS (
SELECT
*
FROM
canonicalized c
WHERE
c.num_searches > 0 OR c.num_chats > 0 OR c.num_client_active_sessions > 0 OR c.num_slackbot_useful_responses > 0 OR c.is_active_other
),
agents_usage AS (
SELECT
agents_activity_precomputation.datepartition,
agents_activity_precomputation.user_id,
SUM(num_agent_runs) AS num_agent_runs,
SUM(num_all_agent_runs) AS num_all_agent_runs
FROM
agents_activity_precomputation
INNER JOIN
(SELECT DISTINCT workflow_id AS agent_workflow_id FROM all_agents WHERE is_agent) AS a
ON
agents_activity_precomputation.workflow_id = agent_workflow_id
WHERE
datepartition BETWEEN DATE(start_date) AND DATE(end_date)
AND (num_agent_runs > 0 OR num_all_agent_runs > 0)
GROUP BY
1, 2
),
combined_usage AS (
SELECT
COALESCE(c.datepartition, a.datepartition) AS datepartition,
COALESCE(c.userid, a.user_id) AS userid,
COALESCE(c.num_searches, 0) AS num_searches,
COALESCE(c.num_chats, 0) AS num_chats,
COALESCE(c.num_client_active_sessions, 0) AS num_client_active_sessions,
COALESCE(c.num_slackbot_useful_responses, 0) AS num_slackbot_useful_responses,
COALESCE(c.is_active_other, false) AS is_active_other,
COALESCE(c.num_ai_answers, 0) AS num_ai_answers,
COALESCE(c.num_summarizations, 0) AS num_summarizations,
COALESCE(a.num_agent_runs, 0) AS num_agent_runs,
COALESCE(a.num_all_agent_runs, 0) AS num_all_agent_runs,
COALESCE(c.num_searches > 0
OR c.num_chats > 0
OR c.num_client_active_sessions > 0
OR c.num_slackbot_useful_responses > 0
OR c.is_active_other
OR c.num_ai_answers > 0
OR c.num_summarizations > 0
OR a.num_agent_runs > 0 -- Deliberately exclude proactive runs (num_all_agent_runs > 0)
, FALSE) AS is_active
FROM
canonicalized_feature_usage c
FULL OUTER JOIN
agents_usage a
ON
c.datepartition = a.datepartition
AND c.userid = a.user_id
)
SELECT
o.userid AS UserId,
COALESCE(COUNT(DISTINCT CASE WHEN is_active THEN datepartition END), 0) AS NumDaysActive,
COALESCE(SUM(num_searches), 0) AS NumSearches,
COALESCE(SUM(num_chats), 0) AS NumChats,
COALESCE(SUM(num_client_active_sessions), 0) AS NumActiveSessions,
COALESCE(SUM(num_slackbot_useful_responses), 0) AS NumGleanbotUsefulResponses,
COALESCE(SUM(num_ai_answers), 0) AS NumAiAnswers,
COALESCE(SUM(num_summarizations), 0) AS NumSummarizations,
COALESCE(SUM(num_agent_runs), 0) AS NumAgentRuns,
COALESCE(SUM(num_all_agent_runs), 0) AS NumAllAgentRuns
FROM
glean_customer_event.latest_orgchart_data o
LEFT JOIN
(SELECT DISTINCT userId FROM combined_usage WHERE is_active) au
ON
au.userid = o.userid
LEFT JOIN
(SELECT * FROM combined_usage WHERE is_active AND datepartition BETWEEN DATE(start_date) AND DATE(end_date)) c
ON
c.userid = o.userid
WHERE
(1=1)
-- Users with AU-qualifying activity should never be considered not-signed-up.
-- TODO: resolve the KI where users can be active on gleanbot without a signup time
AND (o.signuptime IS NOT NULL OR au.userId IS NOT NULL)
GROUP BY
o.userId
ORDER BY
2 DESC, 3 DESC, 4 DESC, 5 DESC, 6 DESC
LIMIT 100
Search
Search Click Datasources
Search Click Datasources
- Output: Number of search result clicks per datasource
- Grain: One row per datasource
- Use Case: Understand which datasources drive the most search engagement
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
search_click_datasources AS (
SELECT
gce.datepartition,
o.department,
gce.jsonPayload.searchclick.datasource,
COALESCE(COUNT(DISTINCT gce.jsonPayload.searchclick.trackingtoken), 0) AS num_clicks
FROM
glean_customer_event AS gce
LEFT JOIN
id_to_alias
ON
gce.jsonPayload.user.userid = id_to_alias.aliasid
AND gce.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS o
ON
COALESCE(id_to_alias.canonicalid, gce.jsonPayload.user.userid) = o.userid
OR COALESCE(id_to_alias.canonicalid, gce.jsonPayload.user.userid) = o.loggingid
WHERE
gce.jsonPayload.type = 'SEARCH_CLICK'
AND COALESCE(gce.jsonPayload.searchclick.datasource, '') != ''
AND LOWER(gce.jsonPayload.searchclick.doctype) != 'golink'
GROUP BY
1, 2, 3
)
SELECT
datasource AS Datasource,
SUM(num_clicks) AS NumUses
FROM
search_click_datasources
WHERE
datepartition BETWEEN DATE(start_date) AND DATE(end_date)
AND (1=1)
GROUP BY
1
ORDER BY
2 DESC
LIMIT 100
Search Satisfaction (SSAT)
Search Satisfaction (SSAT)
- Output: Search session satisfaction rate (clicks / searches)
- Grain: Single aggregate value
- Use Case: Measure search quality via click-through rate
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
search_ssat AS (
SELECT
searches.datepartition,
o.department,
COUNT(DISTINCT IF(search_clicks.qtt IS NOT NULL, searches.stt, NULL)) AS num_searches_with_clicks,
COUNT(DISTINCT searches.stt) AS num_searches
FROM
(
SELECT
DISTINCT jsonPayload.user.userid,
datepartition,
jsonPayload.Search.SessionTrackingToken AS stt,
jsonPayload.Search.TrackingToken AS qtt
FROM
glean_customer_event
WHERE
jsonPayload.Type = 'SEARCH'
AND (
jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD')
AND LOWER(jsonPayload.Search.modality) NOT IN ('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) AS searches
LEFT JOIN
(
SELECT
DISTINCT jsonPayload.SearchClick.TrackingToken AS qtt
FROM
glean_customer_event
WHERE
jsonPayload.Type = 'SEARCH_CLICK'
) AS search_clicks
ON
searches.qtt = search_clicks.qtt
LEFT JOIN
id_to_alias
ON
searches.userid = id_to_alias.aliasid
AND searches.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS o
ON
COALESCE(id_to_alias.canonicalid, searches.userid) = o.userid
OR COALESCE(id_to_alias.canonicalid, searches.userid) = o.loggingid
GROUP BY 1, 2
)
SELECT
1.0 * SUM(num_searches_with_clicks)/GREATEST(SUM(num_searches), 1) AS SearchSSAT
FROM
search_ssat
WHERE
datepartition BETWEEN DATE(start_date) AND DATE(end_date)
AND (1=1)
Assistant
Assistant Timeseries
Assistant Timeseries
- Output: Daily/Weekly/Monthly active Assistant users
- Grain: One row per day
- Use Case: Track Assistant adoption trends over time
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
canonicalized_feature_usage AS (
SELECT datepartition,userid,num_searches,num_chats,num_ai_answers,num_summarizations,num_chat_upvotes,num_chat_downvotes,num_client_active_sessions,num_slackbot_useful_responses,num_slackbot_downvotes,num_slackbot_upvotes,num_slackbot_responses,is_active_other FROM canonicalized
),
canonicalized_active_usage AS (
SELECT
*
FROM
canonicalized_feature_usage c
WHERE
c.num_chats > 0 OR c.num_ai_answers > 0 OR c.num_summarizations > 0 OR c.num_slackbot_useful_responses > 0
)
SELECT
MetricDate,
COUNT(DISTINCT CASE WHEN DATE(MetricDate) = c.datepartition THEN c.userid END) AS DailyActiveUsers,
COUNT(DISTINCT CASE WHEN c.datepartition BETWEEN DATE(MetricDate - INTERVAL '6' DAY) AND DATE(MetricDate) THEN c.userid END) AS WeeklyActiveUsers,
COUNT(DISTINCT c.userid) AS MonthlyActiveUsers
FROM
UNNEST(GENERATE_TIMESTAMP_ARRAY(TIMESTAMP(start_date), TIMESTAMP(end_date), INTERVAL 1 DAY)) AS MetricDate
LEFT JOIN
canonicalized_active_usage c
ON
c.datepartition BETWEEN DATE(MetricDate - INTERVAL '27' DAY) AND DATE(MetricDate)
-- Do not force Active Users to be present in the Org Chart; include qualifying activity even if not in org chart
LEFT JOIN
glean_customer_event.latest_orgchart_data o
ON
c.userid = o.userid
WHERE
1=1
GROUP BY
1
ORDER BY
1
Assistant Event Timeseries
Assistant Event Timeseries
- Output: Daily counts of chat messages, summarizations, AI answers, Gleanbot interactions, and feedback
- Grain: One row per day
- Use Case: Monitor Assistant feature usage volume and feedback trends
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
canonicalized_feature_usage AS (
SELECT datepartition,userid,num_searches,num_chats,num_ai_answers,num_summarizations,num_chat_upvotes,num_chat_downvotes,num_client_active_sessions,num_slackbot_useful_responses,num_slackbot_downvotes,num_slackbot_upvotes,num_slackbot_responses,is_active_other FROM canonicalized
)
SELECT
MetricDate,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = c.datepartition THEN c.num_chats ELSE 0 END), 0) AS ChatMessages,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = c.datepartition THEN c.num_summarizations ELSE 0 END), 0) AS Summarizations,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = c.datepartition THEN c.num_ai_answers ELSE 0 END), 0) AS AiAnswers,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = c.datepartition THEN c.num_slackbot_useful_responses ELSE 0 END), 0) AS GleanbotInteractions,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = c.datepartition THEN (COALESCE(c.num_chat_upvotes,0) + COALESCE(c.num_slackbot_useful_responses,0)) ELSE 0 END), 0) AS Upvotes,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = c.datepartition THEN COALESCE(c.num_chat_downvotes,0) ELSE 0 END), 0) AS Downvotes
FROM
UNNEST(GENERATE_TIMESTAMP_ARRAY(TIMESTAMP(start_date), TIMESTAMP(end_date), INTERVAL 1 DAY)) AS MetricDate
LEFT JOIN
canonicalized_feature_usage c
ON
c.datepartition = DATE(MetricDate)
LEFT JOIN
glean_customer_event.latest_orgchart_data o
ON
c.userid = o.userid
WHERE
1=1
GROUP BY
1
ORDER BY
1
Assistant Summary
Assistant Summary
- Output: Signup count and active Assistant user counts (WAU/MAU)
- Grain: Single aggregate row
- Use Case: Quick snapshot of Assistant reach and engagement
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
canonicalized_feature_usage AS (
SELECT datepartition,userid,num_searches,num_chats,num_ai_answers,num_summarizations,num_chat_upvotes,num_chat_downvotes,num_client_active_sessions,num_slackbot_useful_responses,num_slackbot_downvotes,num_slackbot_upvotes,num_slackbot_responses,is_active_other FROM canonicalized
),
orgchart_full_join_feature_usage AS (
SELECT
o.department,
o.userid AS orgchart_userid,
o.signuptime,
c.datepartition,
c.userid AS feature_usage_userid,
(c.num_chats > 0 OR c.num_ai_answers > 0 OR c.num_summarizations > 0 OR c.num_slackbot_useful_responses > 0) AS is_assistant_active
FROM
glean_customer_event.latest_orgchart_data o
FULL OUTER JOIN
canonicalized_feature_usage c
ON
c.userid = o.userid
WHERE
1=1
)
SELECT
COUNT(DISTINCT CASE WHEN signuptime IS NOT NULL OR feature_usage_userid IS NOT NULL THEN orgchart_userid END) AS NumSignups,
COUNT(DISTINCT CASE WHEN is_assistant_active AND datepartition BETWEEN DATE(end_date) - INTERVAL '27' DAY AND DATE(end_date) THEN feature_usage_userid END) AS MonthlyActiveUsers,
COUNT(DISTINCT CASE WHEN is_assistant_active AND datepartition BETWEEN DATE(end_date) - INTERVAL '6' DAY AND DATE(end_date) THEN feature_usage_userid END) AS WeeklyActiveUsers
FROM
orgchart_full_join_feature_usage
Assistant Top Users
Assistant Top Users
- Output: Per-user Assistant activity counts (chats, AI answers, summarizations, Gleanbot)
- Grain: One row per user
- Use Case: Identify top Assistant users and engagement patterns
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
canonicalized_feature_usage AS (
SELECT datepartition,userid,num_searches,num_chats,num_ai_answers,num_summarizations,num_chat_upvotes,num_chat_downvotes,num_client_active_sessions,num_slackbot_useful_responses,num_slackbot_downvotes,num_slackbot_upvotes,num_slackbot_responses,is_active_other FROM canonicalized
),
canonicalized_assistant_usage AS (
SELECT
*
FROM
canonicalized_feature_usage c
WHERE
c.num_chats > 0 OR c.num_ai_answers > 0 OR c.num_summarizations > 0 OR c.num_slackbot_useful_responses > 0
)
SELECT
o.userid AS UserId,
COALESCE(SUM(num_chats), 0) AS NumChatMessages,
COALESCE(SUM(num_ai_answers), 0) AS NumAiAnswers,
COALESCE(SUM(num_summarizations), 0) AS NumSummarizations,
COALESCE(SUM(num_slackbot_useful_responses), 0) AS NumGleanbotInteractions,
COALESCE(COUNT(DISTINCT
CASE WHEN num_chats > 0 OR num_ai_answers > 0 OR num_summarizations > 0 OR num_slackbot_useful_responses > 0
THEN datepartition END
), 0) AS NumDaysActive
FROM
glean_customer_event.latest_orgchart_data o
LEFT JOIN
(SELECT DISTINCT userId FROM canonicalized_assistant_usage) au
ON
au.userid = o.userid
LEFT JOIN
(SELECT * FROM canonicalized_assistant_usage WHERE datepartition BETWEEN DATE(start_date) AND DATE(end_date)) c
ON
c.userid = o.userid
WHERE
(1=1)
-- Users with AU-qualifying activity should never be considered not-signed-up.
-- TODO: resolve the KI where users can be active on gleanbot without a signup time
AND (o.signuptime IS NOT NULL OR au.userId IS NOT NULL)
GROUP BY
o.userId
ORDER BY
SUM(num_chats) + SUM(num_ai_answers) + SUM(num_summarizations) + SUM(num_slackbot_useful_responses) DESC
LIMIT 100
Agents
Agents Timeseries
Agents Timeseries
- Output: Daily/Weekly/Monthly active Agent users and run counts
- Grain: One row per day
- Use Case: Track Agent adoption and execution trends over time
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
all_workflow_executions AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, workflow_execution.workflowid AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, COALESCE(jsonPayload.workflowrun.initiator = 'RECOMMENDATION', FALSE) AS is_proactively_executed
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND (jsonPayload.workflowrun.feature != 'AGENT_LIVE_PREVIEW' OR jsonPayload.workflowrun.feature IS NULL)
AND (
jsonPayload.workflowrun.initiator IN ('USER', 'REST_API', 'AUTOMATION', 'RECOMMENDATION')
OR (
-- Null handling only during buggy period: https://askscio.slack.com/archives/C08BYEY9TC6/p1757033877342169
datepartition >= DATE '2025-08-12'
AND datepartition < DATE '2025-09-22'
AND jsonPayload.workflowrun.initiator IS NULL
)
)
AND workflow_execution.status = 'SUCCESS'
AND workflow_execution.workflowid IS NOT NULL
AND workflow_execution.workflowid NOT LIKE 'UNSAVED_%'
AND workflow_execution.workflowid != 'AGENTIC_WORKFLOW_ID'
),
agent_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, COUNT(DISTINCT run_id) AS num_all_agent_runs
-- Proactively executed agent runs (mostly in gleanbot context) are not DAU worthy
, COUNT(DISTINCT CASE WHEN NOT is_proactively_executed THEN run_id END) AS num_agent_runs
FROM
all_workflow_executions
GROUP BY
1, 2, 3, 4
),
app_usage_from_gleanchat AS (
SELECT
datepartition
, IF(
jsonpayload.chat.workflowrunid IS NOT NULL
AND jsonpayload.chat.workflowrunid != ''
, jsonpayload.chat.workflowrunid
, jsonpayload.chat.qtt
) AS run_id
, jsonpayload.chat.applicationid AS workflow_id
, resource.labels.project_id AS project_id
, MIN_BY(jsonPayload.user.userid, timestamp) AS user_id
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT'
-- Apps always have a 16 letters Id
AND LENGTH(jsonpayload.chat.applicationid) = 16
-- [Shantanu | To Do] Filter to user initiated queries
-- [Shantanu | To Do] Do not read gleanchat data even for backfilling if
-- date is after YYYYMMDD
GROUP BY
1, 2, 3, 4
),
app_usage_from_chat_1_5 AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, jsonPayload.workflowrun.applicationid AS workflow_id
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
and jsonPayload.workflowrun.initiator = 'USER'
AND jsonPayload.workflowrun.applicationid IS NOT NULL
AND jsonPayload.workflowrun.applicationid != ''
AND workflow_execution.status = 'SUCCESS'
),
app_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
-- for ai app usage , num_all_agent_runs and num_agent_runs are same
, COUNT(DISTINCT run_id) AS num_all_agent_runs
, COUNT(DISTINCT run_id) AS num_agent_runs
FROM (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_gleanchat
UNION ALL
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_chat_1_5
)
GROUP BY
1, 2, 3, 4
),
agent_and_app_usage AS (
SELECT
COALESCE(agu.datepartition, apu.datepartition) AS datepartition
, COALESCE(agu.user_id, apu.user_id) AS user_id
, COALESCE(agu.project_id, apu.project_id) AS project_id
, COALESCE(agu.workflow_id, apu.workflow_id) AS workflow_id
-- Only rely on ai apps data if we cant find any agent usage data for it that day
, IF(agu.num_all_agent_runs > 0, agu.num_all_agent_runs, COALESCE(apu.num_all_agent_runs, 0)) AS num_all_agent_runs
, IF(agu.num_agent_runs > 0, agu.num_agent_runs, COALESCE(apu.num_agent_runs, 0)) AS num_agent_runs
FROM
agent_usage AS agu
FULL OUTER JOIN
app_usage AS apu
ON
agu.datepartition = apu.datepartition
AND agu.user_id = apu.user_id
AND agu.project_id = apu.project_id
AND agu.workflow_id = apu.workflow_id
),
agent_feedback AS (
SELECT
datepartition
, project_id
, workflow_id
, user_id
, SUM(CASE WHEN vote = 'UPVOTE' THEN 1 ELSE 0 END) AS num_upvotes
, SUM(CASE WHEN vote = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_downvotes
FROM (
SELECT
datepartition
-- group by message_id to avoid duplicate feedbacks
, jsonPayload.chatfeedback.messageid AS message_id
-- coalesce for backward compatibility with workflowid and agentid
, COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
-- take latest vote. disregard manual feedback
, MAX_BY(jsonPayload.chatfeedback.event, timestamp) AS vote
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
GROUP BY
1, 2, 3, 4, 5
)
GROUP BY
1, 2, 3, 4
),
agent_usage_and_feedback AS (
SELECT
COALESCE(agent_and_app_usage.datepartition, agent_feedback.datepartition) AS datepartition
, COALESCE(agent_and_app_usage.project_id, agent_feedback.project_id) AS project_id
, COALESCE(agent_and_app_usage.user_id, agent_feedback.user_id) AS user_id
, COALESCE(agent_and_app_usage.workflow_id, agent_feedback.workflow_id) AS workflow_id
, COALESCE(agent_and_app_usage.num_all_agent_runs, 0) AS num_all_agent_runs
, COALESCE(agent_and_app_usage.num_agent_runs, 0) AS num_agent_runs
, COALESCE(agent_feedback.num_upvotes, 0) AS num_upvotes
, COALESCE(agent_feedback.num_downvotes, 0) AS num_downvotes
FROM
agent_and_app_usage
FULL OUTER JOIN
agent_feedback
ON
agent_and_app_usage.datepartition = agent_feedback.datepartition
AND agent_and_app_usage.user_id = agent_feedback.user_id
AND agent_and_app_usage.project_id = agent_feedback.project_id
AND agent_and_app_usage.workflow_id = agent_feedback.workflow_id
),
_precomp_agents_activity_precomputation AS (
SELECT
agent_usage_and_feedback.datepartition
, agent_usage_and_feedback.project_id
, COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, agent_usage_and_feedback.user_id) AS user_id
, agent_usage_and_feedback.workflow_id
, SUM(agent_usage_and_feedback.num_all_agent_runs) AS num_all_agent_runs
, SUM(agent_usage_and_feedback.num_agent_runs) AS num_agent_runs
, SUM(agent_usage_and_feedback.num_upvotes) AS num_upvotes
, SUM(agent_usage_and_feedback.num_downvotes) AS num_downvotes
FROM
agent_usage_and_feedback
LEFT JOIN
id_to_alias
ON
agent_usage_and_feedback.user_id = id_to_alias.aliasid
AND agent_usage_and_feedback.project_id = id_to_alias.project_id
AND agent_usage_and_feedback.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, agent_usage_and_feedback.user_id) = latest_orgchart_data.loggingid
GROUP BY 1, 2, 3, 4
),
all_agents AS (
SELECT
datepartition
, jsonPayload.productsnapshot.workflow.workflowid AS workflow_id
, jsonPayload.productsnapshot.workflow.name
, PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) AS created_at
, IF(PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) = DATE '0001-01-01', NULL, jsonPayload.productsnapshot.workflow.createdby) AS created_by
, jsonPayload.productsnapshot.workflow.namespaceenum AS workflow_type
, jsonPayload.productsnapshot.workflow.namespaceenum = 'AGENT'
AND PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) != DATE '0001-01-01' AS is_agent
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'WORKFLOW'
),
agents_activity_precomputation AS (
SELECT
aap.*,
o.department
FROM
_precomp_agents_activity_precomputation aap
INNER JOIN
(SELECT DISTINCT workflow_id AS agent_workflow_id FROM all_agents WHERE is_agent) AS a
ON
aap.workflow_id = agent_workflow_id
LEFT JOIN
glean_customer_event.latest_orgchart_data o
ON
aap.user_id = o.userid
WHERE
num_agent_runs > 0 -- Deliberately exclude proactive runs (num_all_agent_runs > 0)
AND 1=1
AND 1=1
)
SELECT
MetricDate,
COUNT(DISTINCT CASE WHEN DATE(MetricDate) = aap.datepartition THEN aap.user_id END) AS DailyActiveUsers,
COUNT(DISTINCT CASE WHEN aap.datepartition BETWEEN DATE(MetricDate - INTERVAL '6' DAY) AND DATE(MetricDate) THEN aap.user_id END) AS WeeklyActiveUsers,
COUNT(DISTINCT aap.user_id) AS MonthlyActiveUsers
FROM
-- Equivalent to the following when running on BQ console
-- UNNEST(GENERATE_TIMESTAMP_ARRAY(TIMESTAMP '2025-07-21', TIMESTAMP '2025-07-28', INTERVAL '1' DAY)) AS MetricDate
UNNEST(GENERATE_TIMESTAMP_ARRAY(TIMESTAMP(start_date), TIMESTAMP(end_date), INTERVAL 1 DAY)) AS MetricDate
LEFT JOIN
agents_activity_precomputation aap
ON
aap.datepartition BETWEEN DATE(MetricDate - INTERVAL '27' DAY) AND DATE(MetricDate)
GROUP BY
1
ORDER BY
1
Agents Feedback Timeseries
Agents Feedback Timeseries
- Output: Daily Agent upvote and downvote counts
- Grain: One row per day
- Use Case: Monitor Agent quality via user feedback trends
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
all_workflow_executions AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, workflow_execution.workflowid AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, COALESCE(jsonPayload.workflowrun.initiator = 'RECOMMENDATION', FALSE) AS is_proactively_executed
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND (jsonPayload.workflowrun.feature != 'AGENT_LIVE_PREVIEW' OR jsonPayload.workflowrun.feature IS NULL)
AND (
jsonPayload.workflowrun.initiator IN ('USER', 'REST_API', 'AUTOMATION', 'RECOMMENDATION')
OR (
-- Null handling only during buggy period: https://askscio.slack.com/archives/C08BYEY9TC6/p1757033877342169
datepartition >= DATE '2025-08-12'
AND datepartition < DATE '2025-09-22'
AND jsonPayload.workflowrun.initiator IS NULL
)
)
AND workflow_execution.status = 'SUCCESS'
AND workflow_execution.workflowid IS NOT NULL
AND workflow_execution.workflowid NOT LIKE 'UNSAVED_%'
AND workflow_execution.workflowid != 'AGENTIC_WORKFLOW_ID'
),
agent_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, COUNT(DISTINCT run_id) AS num_all_agent_runs
-- Proactively executed agent runs (mostly in gleanbot context) are not DAU worthy
, COUNT(DISTINCT CASE WHEN NOT is_proactively_executed THEN run_id END) AS num_agent_runs
FROM
all_workflow_executions
GROUP BY
1, 2, 3, 4
),
app_usage_from_gleanchat AS (
SELECT
datepartition
, IF(
jsonpayload.chat.workflowrunid IS NOT NULL
AND jsonpayload.chat.workflowrunid != ''
, jsonpayload.chat.workflowrunid
, jsonpayload.chat.qtt
) AS run_id
, jsonpayload.chat.applicationid AS workflow_id
, resource.labels.project_id AS project_id
, MIN_BY(jsonPayload.user.userid, timestamp) AS user_id
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT'
-- Apps always have a 16 letters Id
AND LENGTH(jsonpayload.chat.applicationid) = 16
-- [Shantanu | To Do] Filter to user initiated queries
-- [Shantanu | To Do] Do not read gleanchat data even for backfilling if
-- date is after YYYYMMDD
GROUP BY
1, 2, 3, 4
),
app_usage_from_chat_1_5 AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, jsonPayload.workflowrun.applicationid AS workflow_id
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
and jsonPayload.workflowrun.initiator = 'USER'
AND jsonPayload.workflowrun.applicationid IS NOT NULL
AND jsonPayload.workflowrun.applicationid != ''
AND workflow_execution.status = 'SUCCESS'
),
app_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
-- for ai app usage , num_all_agent_runs and num_agent_runs are same
, COUNT(DISTINCT run_id) AS num_all_agent_runs
, COUNT(DISTINCT run_id) AS num_agent_runs
FROM (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_gleanchat
UNION ALL
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_chat_1_5
)
GROUP BY
1, 2, 3, 4
),
agent_and_app_usage AS (
SELECT
COALESCE(agu.datepartition, apu.datepartition) AS datepartition
, COALESCE(agu.user_id, apu.user_id) AS user_id
, COALESCE(agu.project_id, apu.project_id) AS project_id
, COALESCE(agu.workflow_id, apu.workflow_id) AS workflow_id
-- Only rely on ai apps data if we cant find any agent usage data for it that day
, IF(agu.num_all_agent_runs > 0, agu.num_all_agent_runs, COALESCE(apu.num_all_agent_runs, 0)) AS num_all_agent_runs
, IF(agu.num_agent_runs > 0, agu.num_agent_runs, COALESCE(apu.num_agent_runs, 0)) AS num_agent_runs
FROM
agent_usage AS agu
FULL OUTER JOIN
app_usage AS apu
ON
agu.datepartition = apu.datepartition
AND agu.user_id = apu.user_id
AND agu.project_id = apu.project_id
AND agu.workflow_id = apu.workflow_id
),
agent_feedback AS (
SELECT
datepartition
, project_id
, workflow_id
, user_id
, SUM(CASE WHEN vote = 'UPVOTE' THEN 1 ELSE 0 END) AS num_upvotes
, SUM(CASE WHEN vote = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_downvotes
FROM (
SELECT
datepartition
-- group by message_id to avoid duplicate feedbacks
, jsonPayload.chatfeedback.messageid AS message_id
-- coalesce for backward compatibility with workflowid and agentid
, COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
-- take latest vote. disregard manual feedback
, MAX_BY(jsonPayload.chatfeedback.event, timestamp) AS vote
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
GROUP BY
1, 2, 3, 4, 5
)
GROUP BY
1, 2, 3, 4
),
agent_usage_and_feedback AS (
SELECT
COALESCE(agent_and_app_usage.datepartition, agent_feedback.datepartition) AS datepartition
, COALESCE(agent_and_app_usage.project_id, agent_feedback.project_id) AS project_id
, COALESCE(agent_and_app_usage.user_id, agent_feedback.user_id) AS user_id
, COALESCE(agent_and_app_usage.workflow_id, agent_feedback.workflow_id) AS workflow_id
, COALESCE(agent_and_app_usage.num_all_agent_runs, 0) AS num_all_agent_runs
, COALESCE(agent_and_app_usage.num_agent_runs, 0) AS num_agent_runs
, COALESCE(agent_feedback.num_upvotes, 0) AS num_upvotes
, COALESCE(agent_feedback.num_downvotes, 0) AS num_downvotes
FROM
agent_and_app_usage
FULL OUTER JOIN
agent_feedback
ON
agent_and_app_usage.datepartition = agent_feedback.datepartition
AND agent_and_app_usage.user_id = agent_feedback.user_id
AND agent_and_app_usage.project_id = agent_feedback.project_id
AND agent_and_app_usage.workflow_id = agent_feedback.workflow_id
),
_precomp_agents_activity_precomputation AS (
SELECT
agent_usage_and_feedback.datepartition
, agent_usage_and_feedback.project_id
, COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, agent_usage_and_feedback.user_id) AS user_id
, agent_usage_and_feedback.workflow_id
, SUM(agent_usage_and_feedback.num_all_agent_runs) AS num_all_agent_runs
, SUM(agent_usage_and_feedback.num_agent_runs) AS num_agent_runs
, SUM(agent_usage_and_feedback.num_upvotes) AS num_upvotes
, SUM(agent_usage_and_feedback.num_downvotes) AS num_downvotes
FROM
agent_usage_and_feedback
LEFT JOIN
id_to_alias
ON
agent_usage_and_feedback.user_id = id_to_alias.aliasid
AND agent_usage_and_feedback.project_id = id_to_alias.project_id
AND agent_usage_and_feedback.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, agent_usage_and_feedback.user_id) = latest_orgchart_data.loggingid
GROUP BY 1, 2, 3, 4
),
all_agents AS (
SELECT
datepartition
, jsonPayload.productsnapshot.workflow.workflowid AS workflow_id
, jsonPayload.productsnapshot.workflow.name
, PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) AS created_at
, IF(PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) = DATE '0001-01-01', NULL, jsonPayload.productsnapshot.workflow.createdby) AS created_by
, jsonPayload.productsnapshot.workflow.namespaceenum AS workflow_type
, jsonPayload.productsnapshot.workflow.namespaceenum = 'AGENT'
AND PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) != DATE '0001-01-01' AS is_agent
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'WORKFLOW'
),
agents_activity_precomputation AS (
SELECT
_precomp_agents_activity_precomputation.*
FROM
_precomp_agents_activity_precomputation
INNER JOIN
(SELECT DISTINCT workflow_id AS agent_workflow_id FROM all_agents WHERE is_agent) AS a
ON
_precomp_agents_activity_precomputation.workflow_id = agent_workflow_id
WHERE
(num_upvotes > 0 OR num_downvotes > 0)
)
SELECT
MetricDate,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = aap.datepartition THEN aap.num_upvotes END), 0) AS Upvotes,
COALESCE(SUM(CASE WHEN DATE(MetricDate) = aap.datepartition THEN aap.num_downvotes END), 0) AS Downvotes
FROM
UNNEST(GENERATE_TIMESTAMP_ARRAY(TIMESTAMP(start_date), TIMESTAMP(end_date), INTERVAL 1 DAY)) AS MetricDate
LEFT JOIN
agents_activity_precomputation aap
ON
aap.datepartition = DATE(MetricDate)
LEFT JOIN
glean_customer_event.latest_orgchart_data o
ON
aap.user_id = o.userid
WHERE
1=1
AND 1=1
GROUP BY
1
ORDER BY
1
Agents Usage by Department
Agents Usage by Department
- Output: Agent run counts, user counts, and top agent per department
- Grain: One row per department
- Use Case: Compare Agent adoption across organizational units
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
all_agents AS (
SELECT
datepartition
, jsonPayload.productsnapshot.workflow.workflowid AS workflow_id
, jsonPayload.productsnapshot.workflow.name
, PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) AS created_at
, IF(PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) = DATE '0001-01-01', NULL, jsonPayload.productsnapshot.workflow.createdby) AS created_by
, jsonPayload.productsnapshot.workflow.namespaceenum AS workflow_type
, jsonPayload.productsnapshot.workflow.namespaceenum = 'AGENT'
AND PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) != DATE '0001-01-01' AS is_agent
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'WORKFLOW'
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
all_workflow_executions AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, workflow_execution.workflowid AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, COALESCE(jsonPayload.workflowrun.initiator = 'RECOMMENDATION', FALSE) AS is_proactively_executed
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND (jsonPayload.workflowrun.feature != 'AGENT_LIVE_PREVIEW' OR jsonPayload.workflowrun.feature IS NULL)
AND (
jsonPayload.workflowrun.initiator IN ('USER', 'REST_API', 'AUTOMATION', 'RECOMMENDATION')
OR (
-- Null handling only during buggy period: https://askscio.slack.com/archives/C08BYEY9TC6/p1757033877342169
datepartition >= DATE '2025-08-12'
AND datepartition < DATE '2025-09-22'
AND jsonPayload.workflowrun.initiator IS NULL
)
)
AND workflow_execution.status = 'SUCCESS'
AND workflow_execution.workflowid IS NOT NULL
AND workflow_execution.workflowid NOT LIKE 'UNSAVED_%'
AND workflow_execution.workflowid != 'AGENTIC_WORKFLOW_ID'
),
agent_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, COUNT(DISTINCT run_id) AS num_all_agent_runs
-- Proactively executed agent runs (mostly in gleanbot context) are not DAU worthy
, COUNT(DISTINCT CASE WHEN NOT is_proactively_executed THEN run_id END) AS num_agent_runs
FROM
all_workflow_executions
GROUP BY
1, 2, 3, 4
),
app_usage_from_gleanchat AS (
SELECT
datepartition
, IF(
jsonpayload.chat.workflowrunid IS NOT NULL
AND jsonpayload.chat.workflowrunid != ''
, jsonpayload.chat.workflowrunid
, jsonpayload.chat.qtt
) AS run_id
, jsonpayload.chat.applicationid AS workflow_id
, resource.labels.project_id AS project_id
, MIN_BY(jsonPayload.user.userid, timestamp) AS user_id
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT'
-- Apps always have a 16 letters Id
AND LENGTH(jsonpayload.chat.applicationid) = 16
-- [Shantanu | To Do] Filter to user initiated queries
-- [Shantanu | To Do] Do not read gleanchat data even for backfilling if
-- date is after YYYYMMDD
GROUP BY
1, 2, 3, 4
),
app_usage_from_chat_1_5 AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, jsonPayload.workflowrun.applicationid AS workflow_id
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
and jsonPayload.workflowrun.initiator = 'USER'
AND jsonPayload.workflowrun.applicationid IS NOT NULL
AND jsonPayload.workflowrun.applicationid != ''
AND workflow_execution.status = 'SUCCESS'
),
app_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
-- for ai app usage , num_all_agent_runs and num_agent_runs are same
, COUNT(DISTINCT run_id) AS num_all_agent_runs
, COUNT(DISTINCT run_id) AS num_agent_runs
FROM (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_gleanchat
UNION ALL
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_chat_1_5
)
GROUP BY
1, 2, 3, 4
),
agent_and_app_usage AS (
SELECT
COALESCE(agu.datepartition, apu.datepartition) AS datepartition
, COALESCE(agu.user_id, apu.user_id) AS user_id
, COALESCE(agu.project_id, apu.project_id) AS project_id
, COALESCE(agu.workflow_id, apu.workflow_id) AS workflow_id
-- Only rely on ai apps data if we cant find any agent usage data for it that day
, IF(agu.num_all_agent_runs > 0, agu.num_all_agent_runs, COALESCE(apu.num_all_agent_runs, 0)) AS num_all_agent_runs
, IF(agu.num_agent_runs > 0, agu.num_agent_runs, COALESCE(apu.num_agent_runs, 0)) AS num_agent_runs
FROM
agent_usage AS agu
FULL OUTER JOIN
app_usage AS apu
ON
agu.datepartition = apu.datepartition
AND agu.user_id = apu.user_id
AND agu.project_id = apu.project_id
AND agu.workflow_id = apu.workflow_id
),
agent_feedback AS (
SELECT
datepartition
, project_id
, workflow_id
, user_id
, SUM(CASE WHEN vote = 'UPVOTE' THEN 1 ELSE 0 END) AS num_upvotes
, SUM(CASE WHEN vote = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_downvotes
FROM (
SELECT
datepartition
-- group by message_id to avoid duplicate feedbacks
, jsonPayload.chatfeedback.messageid AS message_id
-- coalesce for backward compatibility with workflowid and agentid
, COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
-- take latest vote. disregard manual feedback
, MAX_BY(jsonPayload.chatfeedback.event, timestamp) AS vote
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
GROUP BY
1, 2, 3, 4, 5
)
GROUP BY
1, 2, 3, 4
),
agent_usage_and_feedback AS (
SELECT
COALESCE(agent_and_app_usage.datepartition, agent_feedback.datepartition) AS datepartition
, COALESCE(agent_and_app_usage.project_id, agent_feedback.project_id) AS project_id
, COALESCE(agent_and_app_usage.user_id, agent_feedback.user_id) AS user_id
, COALESCE(agent_and_app_usage.workflow_id, agent_feedback.workflow_id) AS workflow_id
, COALESCE(agent_and_app_usage.num_all_agent_runs, 0) AS num_all_agent_runs
, COALESCE(agent_and_app_usage.num_agent_runs, 0) AS num_agent_runs
, COALESCE(agent_feedback.num_upvotes, 0) AS num_upvotes
, COALESCE(agent_feedback.num_downvotes, 0) AS num_downvotes
FROM
agent_and_app_usage
FULL OUTER JOIN
agent_feedback
ON
agent_and_app_usage.datepartition = agent_feedback.datepartition
AND agent_and_app_usage.user_id = agent_feedback.user_id
AND agent_and_app_usage.project_id = agent_feedback.project_id
AND agent_and_app_usage.workflow_id = agent_feedback.workflow_id
),
agents_activity_precomputation AS (
SELECT
agent_usage_and_feedback.datepartition
, agent_usage_and_feedback.project_id
, COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, agent_usage_and_feedback.user_id) AS user_id
, agent_usage_and_feedback.workflow_id
, SUM(agent_usage_and_feedback.num_all_agent_runs) AS num_all_agent_runs
, SUM(agent_usage_and_feedback.num_agent_runs) AS num_agent_runs
, SUM(agent_usage_and_feedback.num_upvotes) AS num_upvotes
, SUM(agent_usage_and_feedback.num_downvotes) AS num_downvotes
FROM
agent_usage_and_feedback
LEFT JOIN
id_to_alias
ON
agent_usage_and_feedback.user_id = id_to_alias.aliasid
AND agent_usage_and_feedback.project_id = id_to_alias.project_id
AND agent_usage_and_feedback.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, agent_usage_and_feedback.user_id) = latest_orgchart_data.loggingid
GROUP BY 1, 2, 3, 4
),
agents_info AS (
SELECT
DISTINCT workflow_id
, MAX_BY(name, datepartition) AS AgentName
FROM
all_agents
WHERE is_agent
GROUP BY
1
),
department_agent_user_run_counts AS (
SELECT
latest_orgchart_data.department
, agents_activity_precomputation.user_id
, agents_activity_precomputation.workflow_id
, ai.AgentName
, SUM(agents_activity_precomputation.num_agent_runs) AS num_agent_runs
, SUM(agents_activity_precomputation.num_all_agent_runs) AS num_all_agent_runs
FROM
agents_activity_precomputation
INNER JOIN
agents_info AS ai
ON
agents_activity_precomputation.workflow_id = ai.workflow_id
LEFT JOIN
glean_customer_event.latest_orgchart_data
ON
agents_activity_precomputation.user_id = latest_orgchart_data.userid
WHERE
1=1
AND latest_orgchart_data.department IS NOT NULL
AND agents_activity_precomputation.datepartition BETWEEN DATE(start_date) AND DATE(end_date)
AND (agents_activity_precomputation.num_agent_runs > 0 OR agents_activity_precomputation.num_all_agent_runs > 0)
GROUP BY
1, 2, 3, 4
),
department_run_counts AS (
SELECT
department
, SUM(num_agent_runs) AS num_agent_runs
, SUM(num_all_agent_runs) AS num_all_agent_runs
, COUNT(DISTINCT user_id) AS num_agent_runners
FROM
department_agent_user_run_counts
GROUP BY
1
),
department_top_agents AS (
SELECT
department
, MAX_BY(workflow_id, num_agent_runners) AS top_agent_id
, MAX_BY(AgentName, num_agent_runners) AS top_agent_name
FROM (
SELECT
department
, workflow_id
, AgentName
, COUNT(DISTINCT user_id) AS num_agent_runners
FROM
department_agent_user_run_counts
GROUP BY
1, 2, 3
)
GROUP BY
1
),
department_sizes AS (
SELECT
department
, COUNT(DISTINCT userid) AS total_employees
FROM
glean_customer_event.latest_orgchart_data
GROUP BY
1
)
SELECT
COALESCE(department_run_counts.department, department_sizes.department) AS Department
, COALESCE(department_top_agents.top_agent_id, '') AS TopAgentId
, COALESCE(department_top_agents.top_agent_name, '') AS TopAgentName
, COALESCE(department_run_counts.num_agent_runs, 0) AS RunCount
, COALESCE(department_run_counts.num_all_agent_runs, 0) AS AllRunCount
, COALESCE(department_run_counts.num_agent_runners, 0) AS UserCount
, COALESCE(department_sizes.total_employees, 0) AS TotalEmployees
FROM
department_run_counts
LEFT JOIN
department_top_agents
ON
department_run_counts.department = department_top_agents.department
LEFT JOIN
department_sizes
ON
department_run_counts.department = department_sizes.department
Agent Runs
Agent Runs
- Output: Per-day agent run counts with department breakdown
- Grain: One row per day
- Use Case: Track Agent execution volume and identify peak usage
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
all_workflow_executions AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, workflow_execution.workflowid AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, COALESCE(jsonPayload.workflowrun.initiator = 'RECOMMENDATION', FALSE) AS is_proactively_executed
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND (jsonPayload.workflowrun.feature != 'AGENT_LIVE_PREVIEW' OR jsonPayload.workflowrun.feature IS NULL)
AND (
jsonPayload.workflowrun.initiator IN ('USER', 'REST_API', 'AUTOMATION', 'RECOMMENDATION')
OR (
-- Null handling only during buggy period: https://askscio.slack.com/archives/C08BYEY9TC6/p1757033877342169
datepartition >= DATE '2025-08-12'
AND datepartition < DATE '2025-09-22'
AND jsonPayload.workflowrun.initiator IS NULL
)
)
AND workflow_execution.status = 'SUCCESS'
AND workflow_execution.workflowid IS NOT NULL
AND workflow_execution.workflowid NOT LIKE 'UNSAVED_%'
AND workflow_execution.workflowid != 'AGENTIC_WORKFLOW_ID'
),
agent_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, COUNT(DISTINCT run_id) AS num_all_agent_runs
-- Proactively executed agent runs (mostly in gleanbot context) are not DAU worthy
, COUNT(DISTINCT CASE WHEN NOT is_proactively_executed THEN run_id END) AS num_agent_runs
FROM
all_workflow_executions
GROUP BY
1, 2, 3, 4
),
app_usage_from_gleanchat AS (
SELECT
datepartition
, IF(
jsonpayload.chat.workflowrunid IS NOT NULL
AND jsonpayload.chat.workflowrunid != ''
, jsonpayload.chat.workflowrunid
, jsonpayload.chat.qtt
) AS run_id
, jsonpayload.chat.applicationid AS workflow_id
, resource.labels.project_id AS project_id
, MIN_BY(jsonPayload.user.userid, timestamp) AS user_id
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT'
-- Apps always have a 16 letters Id
AND LENGTH(jsonpayload.chat.applicationid) = 16
-- [Shantanu | To Do] Filter to user initiated queries
-- [Shantanu | To Do] Do not read gleanchat data even for backfilling if
-- date is after YYYYMMDD
GROUP BY
1, 2, 3, 4
),
app_usage_from_chat_1_5 AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, jsonPayload.workflowrun.applicationid AS workflow_id
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
and jsonPayload.workflowrun.initiator = 'USER'
AND jsonPayload.workflowrun.applicationid IS NOT NULL
AND jsonPayload.workflowrun.applicationid != ''
AND workflow_execution.status = 'SUCCESS'
),
app_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
-- for ai app usage , num_all_agent_runs and num_agent_runs are same
, COUNT(DISTINCT run_id) AS num_all_agent_runs
, COUNT(DISTINCT run_id) AS num_agent_runs
FROM (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_gleanchat
UNION ALL
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_chat_1_5
)
GROUP BY
1, 2, 3, 4
),
agent_and_app_usage AS (
SELECT
COALESCE(agu.datepartition, apu.datepartition) AS datepartition
, COALESCE(agu.user_id, apu.user_id) AS user_id
, COALESCE(agu.project_id, apu.project_id) AS project_id
, COALESCE(agu.workflow_id, apu.workflow_id) AS workflow_id
-- Only rely on ai apps data if we cant find any agent usage data for it that day
, IF(agu.num_all_agent_runs > 0, agu.num_all_agent_runs, COALESCE(apu.num_all_agent_runs, 0)) AS num_all_agent_runs
, IF(agu.num_agent_runs > 0, agu.num_agent_runs, COALESCE(apu.num_agent_runs, 0)) AS num_agent_runs
FROM
agent_usage AS agu
FULL OUTER JOIN
app_usage AS apu
ON
agu.datepartition = apu.datepartition
AND agu.user_id = apu.user_id
AND agu.project_id = apu.project_id
AND agu.workflow_id = apu.workflow_id
),
agent_feedback AS (
SELECT
datepartition
, project_id
, workflow_id
, user_id
, SUM(CASE WHEN vote = 'UPVOTE' THEN 1 ELSE 0 END) AS num_upvotes
, SUM(CASE WHEN vote = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_downvotes
FROM (
SELECT
datepartition
-- group by message_id to avoid duplicate feedbacks
, jsonPayload.chatfeedback.messageid AS message_id
-- coalesce for backward compatibility with workflowid and agentid
, COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
-- take latest vote. disregard manual feedback
, MAX_BY(jsonPayload.chatfeedback.event, timestamp) AS vote
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
GROUP BY
1, 2, 3, 4, 5
)
GROUP BY
1, 2, 3, 4
),
agent_usage_and_feedback AS (
SELECT
COALESCE(agent_and_app_usage.datepartition, agent_feedback.datepartition) AS datepartition
, COALESCE(agent_and_app_usage.project_id, agent_feedback.project_id) AS project_id
, COALESCE(agent_and_app_usage.user_id, agent_feedback.user_id) AS user_id
, COALESCE(agent_and_app_usage.workflow_id, agent_feedback.workflow_id) AS workflow_id
, COALESCE(agent_and_app_usage.num_all_agent_runs, 0) AS num_all_agent_runs
, COALESCE(agent_and_app_usage.num_agent_runs, 0) AS num_agent_runs
, COALESCE(agent_feedback.num_upvotes, 0) AS num_upvotes
, COALESCE(agent_feedback.num_downvotes, 0) AS num_downvotes
FROM
agent_and_app_usage
FULL OUTER JOIN
agent_feedback
ON
agent_and_app_usage.datepartition = agent_feedback.datepartition
AND agent_and_app_usage.user_id = agent_feedback.user_id
AND agent_and_app_usage.project_id = agent_feedback.project_id
AND agent_and_app_usage.workflow_id = agent_feedback.workflow_id
),
_precomp_agents_activity_precomputation AS (
SELECT
agent_usage_and_feedback.datepartition
, agent_usage_and_feedback.project_id
, COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, agent_usage_and_feedback.user_id) AS user_id
, agent_usage_and_feedback.workflow_id
, SUM(agent_usage_and_feedback.num_all_agent_runs) AS num_all_agent_runs
, SUM(agent_usage_and_feedback.num_agent_runs) AS num_agent_runs
, SUM(agent_usage_and_feedback.num_upvotes) AS num_upvotes
, SUM(agent_usage_and_feedback.num_downvotes) AS num_downvotes
FROM
agent_usage_and_feedback
LEFT JOIN
id_to_alias
ON
agent_usage_and_feedback.user_id = id_to_alias.aliasid
AND agent_usage_and_feedback.project_id = id_to_alias.project_id
AND agent_usage_and_feedback.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, agent_usage_and_feedback.user_id) = latest_orgchart_data.loggingid
GROUP BY 1, 2, 3, 4
),
all_agents AS (
SELECT
datepartition
, jsonPayload.productsnapshot.workflow.workflowid AS workflow_id
, jsonPayload.productsnapshot.workflow.name
, PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) AS created_at
, IF(PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) = DATE '0001-01-01', NULL, jsonPayload.productsnapshot.workflow.createdby) AS created_by
, jsonPayload.productsnapshot.workflow.namespaceenum AS workflow_type
, jsonPayload.productsnapshot.workflow.namespaceenum = 'AGENT'
AND PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) != DATE '0001-01-01' AS is_agent
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'WORKFLOW'
),
agents_activity_precomputation AS (
SELECT
aap.*,
o.department
FROM
_precomp_agents_activity_precomputation aap
INNER JOIN
(SELECT DISTINCT workflow_id AS agent_workflow_id FROM all_agents WHERE is_agent) AS a
ON
aap.workflow_id = agent_workflow_id
LEFT JOIN
glean_customer_event.latest_orgchart_data o
ON
aap.user_id = o.userid
WHERE
(num_agent_runs > 0 OR num_all_agent_runs > 0)
AND 1=1
AND 1=1
),
-- Ensures that there is a date available even when no user used agent on that day
all_dates AS (
SELECT
MetricDate
FROM
UNNEST(
GENERATE_TIMESTAMP_ARRAY(TIMESTAMP(start_date), TIMESTAMP(end_date), INTERVAL 1 DAY)
) AS MetricDate
)
SELECT
MetricDate
, COALESCE(SUM(aap.num_agent_runs),0) AS NumAgentRuns
, COALESCE(SUM(aap.num_all_agent_runs),0) AS NumAllAgentRuns
FROM
all_dates
LEFT JOIN
agents_activity_precomputation AS aap
ON
MetricDate = CAST(aap.datepartition AS TIMESTAMP)
GROUP BY
1
ORDER BY 1
Agent Runs by User and Day
Agent Runs by User and Day
- Output: Agent run counts per user per agent per day
- Grain: One row per (agent, day, user)
- Use Case: Detailed Agent usage breakdown for specific users or agents
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
all_workflow_executions AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, workflow_execution.workflowid AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, COALESCE(jsonPayload.workflowrun.initiator = 'RECOMMENDATION', FALSE) AS is_proactively_executed
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND (jsonPayload.workflowrun.feature != 'AGENT_LIVE_PREVIEW' OR jsonPayload.workflowrun.feature IS NULL)
AND (
jsonPayload.workflowrun.initiator IN ('USER', 'REST_API', 'AUTOMATION', 'RECOMMENDATION')
OR (
-- Null handling only during buggy period: https://askscio.slack.com/archives/C08BYEY9TC6/p1757033877342169
datepartition >= DATE '2025-08-12'
AND datepartition < DATE '2025-09-22'
AND jsonPayload.workflowrun.initiator IS NULL
)
)
AND workflow_execution.status = 'SUCCESS'
AND workflow_execution.workflowid IS NOT NULL
AND workflow_execution.workflowid NOT LIKE 'UNSAVED_%'
AND workflow_execution.workflowid != 'AGENTIC_WORKFLOW_ID'
),
agent_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, COUNT(DISTINCT run_id) AS num_all_agent_runs
-- Proactively executed agent runs (mostly in gleanbot context) are not DAU worthy
, COUNT(DISTINCT CASE WHEN NOT is_proactively_executed THEN run_id END) AS num_agent_runs
FROM
all_workflow_executions
GROUP BY
1, 2, 3, 4
),
app_usage_from_gleanchat AS (
SELECT
datepartition
, IF(
jsonpayload.chat.workflowrunid IS NOT NULL
AND jsonpayload.chat.workflowrunid != ''
, jsonpayload.chat.workflowrunid
, jsonpayload.chat.qtt
) AS run_id
, jsonpayload.chat.applicationid AS workflow_id
, resource.labels.project_id AS project_id
, MIN_BY(jsonPayload.user.userid, timestamp) AS user_id
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT'
-- Apps always have a 16 letters Id
AND LENGTH(jsonpayload.chat.applicationid) = 16
-- [Shantanu | To Do] Filter to user initiated queries
-- [Shantanu | To Do] Do not read gleanchat data even for backfilling if
-- date is after YYYYMMDD
GROUP BY
1, 2, 3, 4
),
app_usage_from_chat_1_5 AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, jsonPayload.workflowrun.applicationid AS workflow_id
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
and jsonPayload.workflowrun.initiator = 'USER'
AND jsonPayload.workflowrun.applicationid IS NOT NULL
AND jsonPayload.workflowrun.applicationid != ''
AND workflow_execution.status = 'SUCCESS'
),
app_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
-- for ai app usage , num_all_agent_runs and num_agent_runs are same
, COUNT(DISTINCT run_id) AS num_all_agent_runs
, COUNT(DISTINCT run_id) AS num_agent_runs
FROM (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_gleanchat
UNION ALL
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_chat_1_5
)
GROUP BY
1, 2, 3, 4
),
agent_and_app_usage AS (
SELECT
COALESCE(agu.datepartition, apu.datepartition) AS datepartition
, COALESCE(agu.user_id, apu.user_id) AS user_id
, COALESCE(agu.project_id, apu.project_id) AS project_id
, COALESCE(agu.workflow_id, apu.workflow_id) AS workflow_id
-- Only rely on ai apps data if we cant find any agent usage data for it that day
, IF(agu.num_all_agent_runs > 0, agu.num_all_agent_runs, COALESCE(apu.num_all_agent_runs, 0)) AS num_all_agent_runs
, IF(agu.num_agent_runs > 0, agu.num_agent_runs, COALESCE(apu.num_agent_runs, 0)) AS num_agent_runs
FROM
agent_usage AS agu
FULL OUTER JOIN
app_usage AS apu
ON
agu.datepartition = apu.datepartition
AND agu.user_id = apu.user_id
AND agu.project_id = apu.project_id
AND agu.workflow_id = apu.workflow_id
),
agent_feedback AS (
SELECT
datepartition
, project_id
, workflow_id
, user_id
, SUM(CASE WHEN vote = 'UPVOTE' THEN 1 ELSE 0 END) AS num_upvotes
, SUM(CASE WHEN vote = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_downvotes
FROM (
SELECT
datepartition
-- group by message_id to avoid duplicate feedbacks
, jsonPayload.chatfeedback.messageid AS message_id
-- coalesce for backward compatibility with workflowid and agentid
, COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
-- take latest vote. disregard manual feedback
, MAX_BY(jsonPayload.chatfeedback.event, timestamp) AS vote
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
GROUP BY
1, 2, 3, 4, 5
)
GROUP BY
1, 2, 3, 4
),
agent_usage_and_feedback AS (
SELECT
COALESCE(agent_and_app_usage.datepartition, agent_feedback.datepartition) AS datepartition
, COALESCE(agent_and_app_usage.project_id, agent_feedback.project_id) AS project_id
, COALESCE(agent_and_app_usage.user_id, agent_feedback.user_id) AS user_id
, COALESCE(agent_and_app_usage.workflow_id, agent_feedback.workflow_id) AS workflow_id
, COALESCE(agent_and_app_usage.num_all_agent_runs, 0) AS num_all_agent_runs
, COALESCE(agent_and_app_usage.num_agent_runs, 0) AS num_agent_runs
, COALESCE(agent_feedback.num_upvotes, 0) AS num_upvotes
, COALESCE(agent_feedback.num_downvotes, 0) AS num_downvotes
FROM
agent_and_app_usage
FULL OUTER JOIN
agent_feedback
ON
agent_and_app_usage.datepartition = agent_feedback.datepartition
AND agent_and_app_usage.user_id = agent_feedback.user_id
AND agent_and_app_usage.project_id = agent_feedback.project_id
AND agent_and_app_usage.workflow_id = agent_feedback.workflow_id
),
agents_activity_precomputation AS (
SELECT
agent_usage_and_feedback.datepartition
, agent_usage_and_feedback.project_id
, COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, agent_usage_and_feedback.user_id) AS user_id
, agent_usage_and_feedback.workflow_id
, SUM(agent_usage_and_feedback.num_all_agent_runs) AS num_all_agent_runs
, SUM(agent_usage_and_feedback.num_agent_runs) AS num_agent_runs
, SUM(agent_usage_and_feedback.num_upvotes) AS num_upvotes
, SUM(agent_usage_and_feedback.num_downvotes) AS num_downvotes
FROM
agent_usage_and_feedback
LEFT JOIN
id_to_alias
ON
agent_usage_and_feedback.user_id = id_to_alias.aliasid
AND agent_usage_and_feedback.project_id = id_to_alias.project_id
AND agent_usage_and_feedback.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, agent_usage_and_feedback.user_id) = latest_orgchart_data.loggingid
GROUP BY 1, 2, 3, 4
),
all_agents AS (
SELECT
datepartition
, jsonPayload.productsnapshot.workflow.workflowid AS workflow_id
, jsonPayload.productsnapshot.workflow.name
, PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) AS created_at
, IF(PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) = DATE '0001-01-01', NULL, jsonPayload.productsnapshot.workflow.createdby) AS created_by
, jsonPayload.productsnapshot.workflow.namespaceenum AS workflow_type
, jsonPayload.productsnapshot.workflow.namespaceenum = 'AGENT'
AND PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) != DATE '0001-01-01' AS is_agent
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'WORKFLOW'
)
SELECT
agents_activity_precomputation.workflow_id AS AgentId
, CAST(datepartition AS TIMESTAMP) AS DatePartition
, user_id AS UserId
, SUM(num_agent_runs) AS RunCount
, SUM(num_all_agent_runs) AS AllRunCount
FROM
agents_activity_precomputation
INNER JOIN
(SELECT DISTINCT workflow_id AS agent_workflow_id FROM all_agents WHERE is_agent) AS a
ON
agents_activity_precomputation.workflow_id = agent_workflow_id
WHERE
datepartition BETWEEN DATE(start_date) AND DATE(end_date)
AND (num_agent_runs > 0 OR num_all_agent_runs > 0)
GROUP BY
1, 2, 3
ORDER BY
4 DESC
Active Agent Users
Active Agent Users
- Output: Weekly and Monthly active Agent user counts
- Grain: Single aggregate row
- Use Case: Quick snapshot of Agent user engagement
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
all_workflow_executions AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, workflow_execution.workflowid AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, COALESCE(jsonPayload.workflowrun.initiator = 'RECOMMENDATION', FALSE) AS is_proactively_executed
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND (jsonPayload.workflowrun.feature != 'AGENT_LIVE_PREVIEW' OR jsonPayload.workflowrun.feature IS NULL)
AND (
jsonPayload.workflowrun.initiator IN ('USER', 'REST_API', 'AUTOMATION', 'RECOMMENDATION')
OR (
-- Null handling only during buggy period: https://askscio.slack.com/archives/C08BYEY9TC6/p1757033877342169
datepartition >= DATE '2025-08-12'
AND datepartition < DATE '2025-09-22'
AND jsonPayload.workflowrun.initiator IS NULL
)
)
AND workflow_execution.status = 'SUCCESS'
AND workflow_execution.workflowid IS NOT NULL
AND workflow_execution.workflowid NOT LIKE 'UNSAVED_%'
AND workflow_execution.workflowid != 'AGENTIC_WORKFLOW_ID'
),
agent_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, COUNT(DISTINCT run_id) AS num_all_agent_runs
-- Proactively executed agent runs (mostly in gleanbot context) are not DAU worthy
, COUNT(DISTINCT CASE WHEN NOT is_proactively_executed THEN run_id END) AS num_agent_runs
FROM
all_workflow_executions
GROUP BY
1, 2, 3, 4
),
app_usage_from_gleanchat AS (
SELECT
datepartition
, IF(
jsonpayload.chat.workflowrunid IS NOT NULL
AND jsonpayload.chat.workflowrunid != ''
, jsonpayload.chat.workflowrunid
, jsonpayload.chat.qtt
) AS run_id
, jsonpayload.chat.applicationid AS workflow_id
, resource.labels.project_id AS project_id
, MIN_BY(jsonPayload.user.userid, timestamp) AS user_id
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT'
-- Apps always have a 16 letters Id
AND LENGTH(jsonpayload.chat.applicationid) = 16
-- [Shantanu | To Do] Filter to user initiated queries
-- [Shantanu | To Do] Do not read gleanchat data even for backfilling if
-- date is after YYYYMMDD
GROUP BY
1, 2, 3, 4
),
app_usage_from_chat_1_5 AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, jsonPayload.workflowrun.applicationid AS workflow_id
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
and jsonPayload.workflowrun.initiator = 'USER'
AND jsonPayload.workflowrun.applicationid IS NOT NULL
AND jsonPayload.workflowrun.applicationid != ''
AND workflow_execution.status = 'SUCCESS'
),
app_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
-- for ai app usage , num_all_agent_runs and num_agent_runs are same
, COUNT(DISTINCT run_id) AS num_all_agent_runs
, COUNT(DISTINCT run_id) AS num_agent_runs
FROM (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_gleanchat
UNION ALL
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_chat_1_5
)
GROUP BY
1, 2, 3, 4
),
agent_and_app_usage AS (
SELECT
COALESCE(agu.datepartition, apu.datepartition) AS datepartition
, COALESCE(agu.user_id, apu.user_id) AS user_id
, COALESCE(agu.project_id, apu.project_id) AS project_id
, COALESCE(agu.workflow_id, apu.workflow_id) AS workflow_id
-- Only rely on ai apps data if we cant find any agent usage data for it that day
, IF(agu.num_all_agent_runs > 0, agu.num_all_agent_runs, COALESCE(apu.num_all_agent_runs, 0)) AS num_all_agent_runs
, IF(agu.num_agent_runs > 0, agu.num_agent_runs, COALESCE(apu.num_agent_runs, 0)) AS num_agent_runs
FROM
agent_usage AS agu
FULL OUTER JOIN
app_usage AS apu
ON
agu.datepartition = apu.datepartition
AND agu.user_id = apu.user_id
AND agu.project_id = apu.project_id
AND agu.workflow_id = apu.workflow_id
),
agent_feedback AS (
SELECT
datepartition
, project_id
, workflow_id
, user_id
, SUM(CASE WHEN vote = 'UPVOTE' THEN 1 ELSE 0 END) AS num_upvotes
, SUM(CASE WHEN vote = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_downvotes
FROM (
SELECT
datepartition
-- group by message_id to avoid duplicate feedbacks
, jsonPayload.chatfeedback.messageid AS message_id
-- coalesce for backward compatibility with workflowid and agentid
, COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
-- take latest vote. disregard manual feedback
, MAX_BY(jsonPayload.chatfeedback.event, timestamp) AS vote
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
GROUP BY
1, 2, 3, 4, 5
)
GROUP BY
1, 2, 3, 4
),
agent_usage_and_feedback AS (
SELECT
COALESCE(agent_and_app_usage.datepartition, agent_feedback.datepartition) AS datepartition
, COALESCE(agent_and_app_usage.project_id, agent_feedback.project_id) AS project_id
, COALESCE(agent_and_app_usage.user_id, agent_feedback.user_id) AS user_id
, COALESCE(agent_and_app_usage.workflow_id, agent_feedback.workflow_id) AS workflow_id
, COALESCE(agent_and_app_usage.num_all_agent_runs, 0) AS num_all_agent_runs
, COALESCE(agent_and_app_usage.num_agent_runs, 0) AS num_agent_runs
, COALESCE(agent_feedback.num_upvotes, 0) AS num_upvotes
, COALESCE(agent_feedback.num_downvotes, 0) AS num_downvotes
FROM
agent_and_app_usage
FULL OUTER JOIN
agent_feedback
ON
agent_and_app_usage.datepartition = agent_feedback.datepartition
AND agent_and_app_usage.user_id = agent_feedback.user_id
AND agent_and_app_usage.project_id = agent_feedback.project_id
AND agent_and_app_usage.workflow_id = agent_feedback.workflow_id
),
_precomp_agents_activity_precomputation AS (
SELECT
agent_usage_and_feedback.datepartition
, agent_usage_and_feedback.project_id
, COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, agent_usage_and_feedback.user_id) AS user_id
, agent_usage_and_feedback.workflow_id
, SUM(agent_usage_and_feedback.num_all_agent_runs) AS num_all_agent_runs
, SUM(agent_usage_and_feedback.num_agent_runs) AS num_agent_runs
, SUM(agent_usage_and_feedback.num_upvotes) AS num_upvotes
, SUM(agent_usage_and_feedback.num_downvotes) AS num_downvotes
FROM
agent_usage_and_feedback
LEFT JOIN
id_to_alias
ON
agent_usage_and_feedback.user_id = id_to_alias.aliasid
AND agent_usage_and_feedback.project_id = id_to_alias.project_id
AND agent_usage_and_feedback.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, agent_usage_and_feedback.user_id) = latest_orgchart_data.loggingid
GROUP BY 1, 2, 3, 4
),
all_agents AS (
SELECT
datepartition
, jsonPayload.productsnapshot.workflow.workflowid AS workflow_id
, jsonPayload.productsnapshot.workflow.name
, PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) AS created_at
, IF(PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) = DATE '0001-01-01', NULL, jsonPayload.productsnapshot.workflow.createdby) AS created_by
, jsonPayload.productsnapshot.workflow.namespaceenum AS workflow_type
, jsonPayload.productsnapshot.workflow.namespaceenum = 'AGENT'
AND PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) != DATE '0001-01-01' AS is_agent
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'WORKFLOW'
),
agents_activity_precomputation AS (
SELECT
_precomp_agents_activity_precomputation.*
FROM
_precomp_agents_activity_precomputation
INNER JOIN
(SELECT DISTINCT workflow_id AS agent_workflow_id FROM all_agents WHERE is_agent) AS a
ON
_precomp_agents_activity_precomputation.workflow_id = agent_workflow_id
WHERE
num_agent_runs > 0 -- Deliberately exclude proactive runs (num_all_agent_runs > 0)
)
SELECT
COUNT(DISTINCT CASE
WHEN aap.datepartition BETWEEN DATE(end_date) - INTERVAL '6' DAY AND DATE(end_date)
THEN aap.user_id
END) AS WeeklyActiveAgentUsers,
COUNT(DISTINCT CASE
WHEN aap.datepartition BETWEEN DATE(end_date) - INTERVAL '27' DAY AND DATE(end_date)
THEN aap.user_id
END) AS MonthlyActiveAgentUsers
FROM
agents_activity_precomputation aap
LEFT JOIN
glean_customer_event.latest_orgchart_data o
ON
aap.user_id = o.userid
WHERE
aap.datepartition BETWEEN DATE(end_date) - INTERVAL '27' DAY AND DATE(end_date)
AND 1=1
AND 1=1
Top Agents
Top Agents
- Output: Per-agent user count, run count, and feedback counts
- Grain: One row per agent
- Use Case: Identify most popular and highest-quality agents
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
all_agents AS (
SELECT
datepartition
, jsonPayload.productsnapshot.workflow.workflowid AS workflow_id
, jsonPayload.productsnapshot.workflow.name
, PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) AS created_at
, IF(PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) = DATE '0001-01-01', NULL, jsonPayload.productsnapshot.workflow.createdby) AS created_by
, jsonPayload.productsnapshot.workflow.namespaceenum AS workflow_type
, jsonPayload.productsnapshot.workflow.namespaceenum = 'AGENT'
AND PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) != DATE '0001-01-01' AS is_agent
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'WORKFLOW'
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
all_workflow_executions AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, workflow_execution.workflowid AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, COALESCE(jsonPayload.workflowrun.initiator = 'RECOMMENDATION', FALSE) AS is_proactively_executed
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND (jsonPayload.workflowrun.feature != 'AGENT_LIVE_PREVIEW' OR jsonPayload.workflowrun.feature IS NULL)
AND (
jsonPayload.workflowrun.initiator IN ('USER', 'REST_API', 'AUTOMATION', 'RECOMMENDATION')
OR (
-- Null handling only during buggy period: https://askscio.slack.com/archives/C08BYEY9TC6/p1757033877342169
datepartition >= DATE '2025-08-12'
AND datepartition < DATE '2025-09-22'
AND jsonPayload.workflowrun.initiator IS NULL
)
)
AND workflow_execution.status = 'SUCCESS'
AND workflow_execution.workflowid IS NOT NULL
AND workflow_execution.workflowid NOT LIKE 'UNSAVED_%'
AND workflow_execution.workflowid != 'AGENTIC_WORKFLOW_ID'
),
agent_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, COUNT(DISTINCT run_id) AS num_all_agent_runs
-- Proactively executed agent runs (mostly in gleanbot context) are not DAU worthy
, COUNT(DISTINCT CASE WHEN NOT is_proactively_executed THEN run_id END) AS num_agent_runs
FROM
all_workflow_executions
GROUP BY
1, 2, 3, 4
),
app_usage_from_gleanchat AS (
SELECT
datepartition
, IF(
jsonpayload.chat.workflowrunid IS NOT NULL
AND jsonpayload.chat.workflowrunid != ''
, jsonpayload.chat.workflowrunid
, jsonpayload.chat.qtt
) AS run_id
, jsonpayload.chat.applicationid AS workflow_id
, resource.labels.project_id AS project_id
, MIN_BY(jsonPayload.user.userid, timestamp) AS user_id
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT'
-- Apps always have a 16 letters Id
AND LENGTH(jsonpayload.chat.applicationid) = 16
-- [Shantanu | To Do] Filter to user initiated queries
-- [Shantanu | To Do] Do not read gleanchat data even for backfilling if
-- date is after YYYYMMDD
GROUP BY
1, 2, 3, 4
),
app_usage_from_chat_1_5 AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, jsonPayload.workflowrun.applicationid AS workflow_id
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
and jsonPayload.workflowrun.initiator = 'USER'
AND jsonPayload.workflowrun.applicationid IS NOT NULL
AND jsonPayload.workflowrun.applicationid != ''
AND workflow_execution.status = 'SUCCESS'
),
app_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
-- for ai app usage , num_all_agent_runs and num_agent_runs are same
, COUNT(DISTINCT run_id) AS num_all_agent_runs
, COUNT(DISTINCT run_id) AS num_agent_runs
FROM (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_gleanchat
UNION ALL
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_chat_1_5
)
GROUP BY
1, 2, 3, 4
),
agent_and_app_usage AS (
SELECT
COALESCE(agu.datepartition, apu.datepartition) AS datepartition
, COALESCE(agu.user_id, apu.user_id) AS user_id
, COALESCE(agu.project_id, apu.project_id) AS project_id
, COALESCE(agu.workflow_id, apu.workflow_id) AS workflow_id
-- Only rely on ai apps data if we cant find any agent usage data for it that day
, IF(agu.num_all_agent_runs > 0, agu.num_all_agent_runs, COALESCE(apu.num_all_agent_runs, 0)) AS num_all_agent_runs
, IF(agu.num_agent_runs > 0, agu.num_agent_runs, COALESCE(apu.num_agent_runs, 0)) AS num_agent_runs
FROM
agent_usage AS agu
FULL OUTER JOIN
app_usage AS apu
ON
agu.datepartition = apu.datepartition
AND agu.user_id = apu.user_id
AND agu.project_id = apu.project_id
AND agu.workflow_id = apu.workflow_id
),
agent_feedback AS (
SELECT
datepartition
, project_id
, workflow_id
, user_id
, SUM(CASE WHEN vote = 'UPVOTE' THEN 1 ELSE 0 END) AS num_upvotes
, SUM(CASE WHEN vote = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_downvotes
FROM (
SELECT
datepartition
-- group by message_id to avoid duplicate feedbacks
, jsonPayload.chatfeedback.messageid AS message_id
-- coalesce for backward compatibility with workflowid and agentid
, COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
-- take latest vote. disregard manual feedback
, MAX_BY(jsonPayload.chatfeedback.event, timestamp) AS vote
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
GROUP BY
1, 2, 3, 4, 5
)
GROUP BY
1, 2, 3, 4
),
agent_usage_and_feedback AS (
SELECT
COALESCE(agent_and_app_usage.datepartition, agent_feedback.datepartition) AS datepartition
, COALESCE(agent_and_app_usage.project_id, agent_feedback.project_id) AS project_id
, COALESCE(agent_and_app_usage.user_id, agent_feedback.user_id) AS user_id
, COALESCE(agent_and_app_usage.workflow_id, agent_feedback.workflow_id) AS workflow_id
, COALESCE(agent_and_app_usage.num_all_agent_runs, 0) AS num_all_agent_runs
, COALESCE(agent_and_app_usage.num_agent_runs, 0) AS num_agent_runs
, COALESCE(agent_feedback.num_upvotes, 0) AS num_upvotes
, COALESCE(agent_feedback.num_downvotes, 0) AS num_downvotes
FROM
agent_and_app_usage
FULL OUTER JOIN
agent_feedback
ON
agent_and_app_usage.datepartition = agent_feedback.datepartition
AND agent_and_app_usage.user_id = agent_feedback.user_id
AND agent_and_app_usage.project_id = agent_feedback.project_id
AND agent_and_app_usage.workflow_id = agent_feedback.workflow_id
),
agents_activity_precomputation AS (
SELECT
agent_usage_and_feedback.datepartition
, agent_usage_and_feedback.project_id
, COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, agent_usage_and_feedback.user_id) AS user_id
, agent_usage_and_feedback.workflow_id
, SUM(agent_usage_and_feedback.num_all_agent_runs) AS num_all_agent_runs
, SUM(agent_usage_and_feedback.num_agent_runs) AS num_agent_runs
, SUM(agent_usage_and_feedback.num_upvotes) AS num_upvotes
, SUM(agent_usage_and_feedback.num_downvotes) AS num_downvotes
FROM
agent_usage_and_feedback
LEFT JOIN
id_to_alias
ON
agent_usage_and_feedback.user_id = id_to_alias.aliasid
AND agent_usage_and_feedback.project_id = id_to_alias.project_id
AND agent_usage_and_feedback.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, agent_usage_and_feedback.user_id) = latest_orgchart_data.loggingid
GROUP BY 1, 2, 3, 4
),
agents_info AS (
SELECT
DISTINCT workflow_id
, MAX_BY(name, datepartition) AS AgentName
FROM
all_agents
WHERE is_agent
GROUP BY
1
)
SELECT
aap.workflow_id as AgentId
, COALESCE(ai.AgentName, '') AS AgentName
, COUNT(DISTINCT aap.user_id) AS UserCount
, COALESCE(SUM(aap.num_agent_runs), 0) AS RunCount
, COALESCE(SUM(aap.num_all_agent_runs), 0) AS AllRunCount
, COALESCE(SUM(aap.num_upvotes), 0) AS UpvoteCount
, COALESCE(SUM(aap.num_downvotes), 0) AS DownvoteCount
FROM
agents_activity_precomputation aap
INNER JOIN
agents_info AS ai
ON
aap.workflow_id = ai.workflow_id
LEFT JOIN
glean_customer_event.latest_orgchart_data ocd
ON
aap.user_id = ocd.userid
WHERE
aap.datepartition BETWEEN DATE(start_date) AND DATE(end_date)
AND (aap.num_agent_runs > 0 OR aap.num_all_agent_runs > 0 OR aap.num_upvotes > 0 OR aap.num_downvotes > 0)
AND aap.workflow_id IS NOT NULL
AND ai.AgentName IS NOT NULL
AND 1=1
GROUP BY
1,2
ORDER BY
3 DESC
Top Agent Users
Top Agent Users
- Output: Per-user agent usage counts (agents used, runs, creations)
- Grain: One row per user
- Use Case: Identify power users of the Agents platform
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
canonicalized_feature_usage AS (
SELECT datepartition,userid,num_searches,num_chats,num_ai_answers,num_summarizations,num_chat_upvotes,num_chat_downvotes,num_client_active_sessions,num_slackbot_useful_responses,num_slackbot_downvotes,num_slackbot_upvotes,num_slackbot_responses,is_active_other FROM canonicalized
),
all_workflow_executions AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, workflow_execution.workflowid AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, COALESCE(jsonPayload.workflowrun.initiator = 'RECOMMENDATION', FALSE) AS is_proactively_executed
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND (jsonPayload.workflowrun.feature != 'AGENT_LIVE_PREVIEW' OR jsonPayload.workflowrun.feature IS NULL)
AND (
jsonPayload.workflowrun.initiator IN ('USER', 'REST_API', 'AUTOMATION', 'RECOMMENDATION')
OR (
-- Null handling only during buggy period: https://askscio.slack.com/archives/C08BYEY9TC6/p1757033877342169
datepartition >= DATE '2025-08-12'
AND datepartition < DATE '2025-09-22'
AND jsonPayload.workflowrun.initiator IS NULL
)
)
AND workflow_execution.status = 'SUCCESS'
AND workflow_execution.workflowid IS NOT NULL
AND workflow_execution.workflowid NOT LIKE 'UNSAVED_%'
AND workflow_execution.workflowid != 'AGENTIC_WORKFLOW_ID'
),
agent_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, COUNT(DISTINCT run_id) AS num_all_agent_runs
-- Proactively executed agent runs (mostly in gleanbot context) are not DAU worthy
, COUNT(DISTINCT CASE WHEN NOT is_proactively_executed THEN run_id END) AS num_agent_runs
FROM
all_workflow_executions
GROUP BY
1, 2, 3, 4
),
app_usage_from_gleanchat AS (
SELECT
datepartition
, IF(
jsonpayload.chat.workflowrunid IS NOT NULL
AND jsonpayload.chat.workflowrunid != ''
, jsonpayload.chat.workflowrunid
, jsonpayload.chat.qtt
) AS run_id
, jsonpayload.chat.applicationid AS workflow_id
, resource.labels.project_id AS project_id
, MIN_BY(jsonPayload.user.userid, timestamp) AS user_id
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT'
-- Apps always have a 16 letters Id
AND LENGTH(jsonpayload.chat.applicationid) = 16
-- [Shantanu | To Do] Filter to user initiated queries
-- [Shantanu | To Do] Do not read gleanchat data even for backfilling if
-- date is after YYYYMMDD
GROUP BY
1, 2, 3, 4
),
app_usage_from_chat_1_5 AS (
SELECT DISTINCT
datepartition
, jsonpayload.workflowrun.runid AS run_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
, jsonPayload.workflowrun.applicationid AS workflow_id
FROM
glean_customer_event
, UNNEST(jsonpayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
and jsonPayload.workflowrun.initiator = 'USER'
AND jsonPayload.workflowrun.applicationid IS NOT NULL
AND jsonPayload.workflowrun.applicationid != ''
AND workflow_execution.status = 'SUCCESS'
),
app_usage AS (
SELECT
datepartition
, project_id
, user_id
, workflow_id
-- for ai app usage , num_all_agent_runs and num_agent_runs are same
, COUNT(DISTINCT run_id) AS num_all_agent_runs
, COUNT(DISTINCT run_id) AS num_agent_runs
FROM (
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_gleanchat
UNION ALL
SELECT
datepartition
, project_id
, user_id
, workflow_id
, run_id
FROM
app_usage_from_chat_1_5
)
GROUP BY
1, 2, 3, 4
),
agent_and_app_usage AS (
SELECT
COALESCE(agu.datepartition, apu.datepartition) AS datepartition
, COALESCE(agu.user_id, apu.user_id) AS user_id
, COALESCE(agu.project_id, apu.project_id) AS project_id
, COALESCE(agu.workflow_id, apu.workflow_id) AS workflow_id
-- Only rely on ai apps data if we cant find any agent usage data for it that day
, IF(agu.num_all_agent_runs > 0, agu.num_all_agent_runs, COALESCE(apu.num_all_agent_runs, 0)) AS num_all_agent_runs
, IF(agu.num_agent_runs > 0, agu.num_agent_runs, COALESCE(apu.num_agent_runs, 0)) AS num_agent_runs
FROM
agent_usage AS agu
FULL OUTER JOIN
app_usage AS apu
ON
agu.datepartition = apu.datepartition
AND agu.user_id = apu.user_id
AND agu.project_id = apu.project_id
AND agu.workflow_id = apu.workflow_id
),
agent_feedback AS (
SELECT
datepartition
, project_id
, workflow_id
, user_id
, SUM(CASE WHEN vote = 'UPVOTE' THEN 1 ELSE 0 END) AS num_upvotes
, SUM(CASE WHEN vote = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_downvotes
FROM (
SELECT
datepartition
-- group by message_id to avoid duplicate feedbacks
, jsonPayload.chatfeedback.messageid AS message_id
-- coalesce for backward compatibility with workflowid and agentid
, COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) AS workflow_id
, resource.labels.project_id AS project_id
, jsonPayload.user.userid AS user_id
-- take latest vote. disregard manual feedback
, MAX_BY(jsonPayload.chatfeedback.event, timestamp) AS vote
FROM
glean_customer_event
WHERE
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
GROUP BY
1, 2, 3, 4, 5
)
GROUP BY
1, 2, 3, 4
),
agent_usage_and_feedback AS (
SELECT
COALESCE(agent_and_app_usage.datepartition, agent_feedback.datepartition) AS datepartition
, COALESCE(agent_and_app_usage.project_id, agent_feedback.project_id) AS project_id
, COALESCE(agent_and_app_usage.user_id, agent_feedback.user_id) AS user_id
, COALESCE(agent_and_app_usage.workflow_id, agent_feedback.workflow_id) AS workflow_id
, COALESCE(agent_and_app_usage.num_all_agent_runs, 0) AS num_all_agent_runs
, COALESCE(agent_and_app_usage.num_agent_runs, 0) AS num_agent_runs
, COALESCE(agent_feedback.num_upvotes, 0) AS num_upvotes
, COALESCE(agent_feedback.num_downvotes, 0) AS num_downvotes
FROM
agent_and_app_usage
FULL OUTER JOIN
agent_feedback
ON
agent_and_app_usage.datepartition = agent_feedback.datepartition
AND agent_and_app_usage.user_id = agent_feedback.user_id
AND agent_and_app_usage.project_id = agent_feedback.project_id
AND agent_and_app_usage.workflow_id = agent_feedback.workflow_id
),
_precomp_agents_activity_precomputation AS (
SELECT
agent_usage_and_feedback.datepartition
, agent_usage_and_feedback.project_id
, COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, agent_usage_and_feedback.user_id) AS user_id
, agent_usage_and_feedback.workflow_id
, SUM(agent_usage_and_feedback.num_all_agent_runs) AS num_all_agent_runs
, SUM(agent_usage_and_feedback.num_agent_runs) AS num_agent_runs
, SUM(agent_usage_and_feedback.num_upvotes) AS num_upvotes
, SUM(agent_usage_and_feedback.num_downvotes) AS num_downvotes
FROM
agent_usage_and_feedback
LEFT JOIN
id_to_alias
ON
agent_usage_and_feedback.user_id = id_to_alias.aliasid
AND agent_usage_and_feedback.project_id = id_to_alias.project_id
AND agent_usage_and_feedback.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, agent_usage_and_feedback.user_id) = latest_orgchart_data.loggingid
GROUP BY 1, 2, 3, 4
),
all_agents AS (
SELECT
datepartition
, jsonPayload.productsnapshot.workflow.workflowid AS workflow_id
, jsonPayload.productsnapshot.workflow.name
, PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) AS created_at
, IF(PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) = DATE '0001-01-01', NULL, jsonPayload.productsnapshot.workflow.createdby) AS created_by
, jsonPayload.productsnapshot.workflow.namespaceenum AS workflow_type
, jsonPayload.productsnapshot.workflow.namespaceenum = 'AGENT'
AND PARSE_DATE('%Y-%m-%d', SUBSTR(jsonPayload.productsnapshot.workflow.createdat, 1, 10)) != DATE '0001-01-01' AS is_agent
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'WORKFLOW'
),
canonicalized_active_usage AS (
SELECT
*
FROM
canonicalized_feature_usage c
WHERE
c.num_searches > 0 OR c.num_chats > 0 OR c.num_client_active_sessions > 0 OR c.num_slackbot_useful_responses > 0 OR c.is_active_other
),
agents_activity_precomputation AS (
SELECT
_precomp_agents_activity_precomputation.*
FROM
_precomp_agents_activity_precomputation
INNER JOIN
(SELECT DISTINCT workflow_id AS agent_workflow_id FROM all_agents WHERE is_agent) AS a
ON
_precomp_agents_activity_precomputation.workflow_id = agent_workflow_id
WHERE
datepartition BETWEEN DATE(start_date) AND DATE(end_date)
AND (num_agent_runs > 0 OR num_all_agent_runs > 0)
AND 1=1
),
agent_runs AS (
SELECT
user_id
, COUNT(DISTINCT CASE WHEN num_agent_runs > 0 THEN workflow_id END) AS AgentsUsedCount
, COUNT(DISTINCT CASE WHEN num_agent_runs > 0 THEN datepartition END) AS AgentRunDaysCount
, SUM(num_agent_runs) AS RunCount
, SUM(num_all_agent_runs) AS AllRunCount
FROM
agents_activity_precomputation
GROUP BY
1
),
agent_creations AS (
SELECT
created_by AS user_id
, COUNT(DISTINCT workflow_id) AS AgentsCreatedCount
FROM (
SELECT
workflow_id
, MIN(created_at) AS created_at
, MIN(created_by) AS created_by
FROM
all_agents
WHERE
is_agent
GROUP BY
1
)
WHERE
created_at BETWEEN DATE(start_date) AND DATE(end_date)
AND 1=1
GROUP BY
1
)
SELECT
o.userid AS UserId
, o.department AS DepartmentName
, COALESCE(ar.AgentsUsedCount, 0) AS AgentsUsedCount
, COALESCE(ar.AgentRunDaysCount, 0) AS AgentRunDaysCount
, COALESCE(ar.RunCount, 0) AS RunCount
, COALESCE(ar.AllRunCount, 0) AS AllRunCount
, COALESCE(ac.AgentsCreatedCount, 0) AS AgentsCreatedCount
FROM
glean_customer_event.latest_orgchart_data o
LEFT JOIN
(SELECT DISTINCT userid FROM canonicalized_active_usage) au
ON
au.userid = o.userid
LEFT JOIN
agent_runs ar
ON
o.userid = ar.user_id
LEFT JOIN
agent_creations ac
ON
o.userid = ac.user_id
WHERE
1=1
-- Users with AU-qualifying activity should never be considered not-signed-up.
-- TODO: resolve the KI where users can be active on gleanbot without a signup time
-- Also include users that have run agents as AU-qualifying activity.
AND (o.signuptime IS NOT NULL OR au.userid IS NOT NULL OR ar.RunCount > 0)
ORDER BY
3 DESC
Chat Datasources
Chat Datasources
Chat Datasources
- Output: Number of chat citations per datasource
- Grain: One row per datasource
- Use Case: Understand which datasources are most cited in chat responses
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
chat_datasources AS (
SELECT
citations.datepartition,
o.department,
citations.datasource,
COUNT(DISTINCT CONCAT(citations.chatsessionid, '|', citations.docid)) AS num_citations
FROM (
SELECT
COALESCE(c.datepartition, w.datepartition) AS datepartition,
COALESCE(c.userid, w.userid) AS userid,
COALESCE(c.chatsessionid, w.chatsessionid) AS chatsessionid,
COALESCE(c.docid, w.docid) AS docid,
COALESCE(c.datasource, w.datasource) AS datasource
FROM
(
SELECT
datepartition,
jsonPayload.user.userid,
jsonPayload.chatcitations.chatsessionid,
chat_citation.sourcedocument.id AS docid,
chat_citation.sourcedocument.datasource
FROM
glean_customer_event
CROSS JOIN
UNNEST(jsonPayload.chatcitations.citations) AS chat_citation
WHERE
jsonPayload.type = 'CHAT_CITATIONS'
AND jsonPayload.chatcitations.chatsessionid IS NOT NULL
AND chat_citation.sourcedocument.id IS NOT NULL
AND chat_citation.sourcedocument.datasource IS NOT NULL
) c
FULL OUTER JOIN
(
SELECT
DISTINCT datepartition,
userid,
chatsessionid,
docid,
datasource
FROM (
SELECT
datepartition,
jsonPayload.user.userid,
jsonPayload.workflow.chatsessionid,
workflow_citation.sourcedocument.id AS docid,
workflow_citation.sourcedocument.datasource
FROM
glean_customer_event, UNNEST(jsonPayload.workflow.citations) AS workflow_citation
WHERE
jsonPayload.workflow.workflowid IN ('DOC_CONTEXT_READER', 'ORIGINAL_MESSAGE_SEARCH', 'DIRECT_LLM_RESPONSE', 'REACT_TOOLS_2_HOPS','DEFAULT_CHAT','WORLD_MODE_V2','DEEP_RESEARCH_PYAGENT','DEEP_RESEARCH_PREVIEW')
AND jsonPayload.workflow.initiator = 'USER'
AND jsonPayload.workflow.chatsessionid IS NOT NULL
AND workflow_citation.sourcedocument.id IS NOT NULL
AND workflow_citation.sourcedocument.datasource IS NOT NULL
UNION ALL
SELECT
datepartition,
jsonPayload.user.userid,
jsonPayload.workflowrun.chatsessionid,
step_citation.sourcedocument.id AS docid,
step_citation.sourcedocument.datasource
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS step_execution,
UNNEST(step_execution.citations) AS step_citation
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN ('DOC_CONTEXT_READER', 'ORIGINAL_MESSAGE_SEARCH', 'DIRECT_LLM_RESPONSE', 'REACT_TOOLS_2_HOPS','DEFAULT_CHAT','WORLD_MODE_V2','DEEP_RESEARCH_PYAGENT','DEEP_RESEARCH_PREVIEW')
)
) w
ON
c.datepartition = w.datepartition
AND c.userid = w.userid
AND c.chatsessionid = w.chatsessionid
AND c.docid = w.docid
AND c.datasource = w.datasource
) AS citations
LEFT JOIN
id_to_alias
ON
citations.userid = id_to_alias.aliasid
AND citations.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS o
ON
COALESCE(id_to_alias.canonicalid, citations.userid) = o.userid
OR COALESCE(id_to_alias.canonicalid, citations.userid) = o.loggingid
WHERE
COALESCE(citations.datasource, '') != ''
GROUP BY
1, 2, 3
)
SELECT
datasource AS Datasource,
SUM(num_citations) AS NumUses
FROM
chat_datasources
WHERE
datepartition BETWEEN DATE(start_date) AND DATE(end_date)
AND (1=1)
GROUP BY
1
ORDER BY
2 DESC
LIMIT 100
Shortcuts
Shortcut Insights
Shortcut Insights
- Output: Visit count and unique visitor count per shortcut
- Grain: One row per shortcut
- Use Case: Measure shortcut engagement and identify popular shortcuts
Copy
DECLARE start_date DATE DEFAULT DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY);
DECLARE end_date DATE DEFAULT CURRENT_DATE();
WITH
glean_customer_event AS (
SELECT
resource,
DATE(DATE_TRUNC(timestamp, DAY)) AS datepartition,
jsonPayload,
timestamp,
FROM `<glean_customer_event_table>`
-- This filter is not strictly necessary - the external table enforces partition filtering via URI definitions.
WHERE DATE(DATE_TRUNC(timestamp, DAY)) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 270 DAY) AND CURRENT_DATE()
),
id_to_alias AS (
SELECT DISTINCT
datepartition,
project_id,
aliasid,
userid AS canonicalid
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.productsnapshot.user.id AS userid,
jsonPayload.productsnapshot.user.aliasids
FROM
glean_customer_event
WHERE
jsonPayload.type = 'PRODUCT_SNAPSHOT'
AND jsonPayload.productsnapshot.type = 'USER'
), UNNEST(aliasids) AS aliasid
),
chat_usage AS (
SELECT
COALESCE(wf.datepartition, chat.datepartition) AS datepartition,
COALESCE(wf.project_id, chat.project_id) AS project_id,
COALESCE(wf.userid, chat.userid) AS userid,
COUNT(DISTINCT wf.run_id) + COUNT(DISTINCT CASE WHEN wf.run_id IS NULL THEN chat.qtt END) AS num_chat_queries
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
MIN(datepartition) AS datepartition
FROM glean_customer_event
WHERE jsonPayload.workflow.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
AND jsonPayload.workflow.initiator = 'USER'
GROUP BY 1, 2, 3
UNION ALL
SELECT
DISTINCT jsonPayload.workflowrun.runid AS run_id,
jsonPayload.user.userid,
resource.labels.project_id,
datepartition
FROM glean_customer_event, UNNEST(jsonPayload.workflowrun.workflowexecutions) AS workflow_execution
WHERE jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator = 'USER'
AND workflow_execution.workflowid IN (
'DOC_CONTEXT_READER',
'ORIGINAL_MESSAGE_SEARCH',
'DIRECT_LLM_RESPONSE',
'REACT_TOOLS_2_HOPS',
'DEFAULT_CHAT',
'WORLD_MODE_V2',
'DEEP_RESEARCH_PYAGENT',
'DEEP_RESEARCH_PREVIEW'
)
) wf
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.chat.qtt AS qtt,
jsonPayload.chat.workflowrunid AS workflowrunid
FROM glean_customer_event
WHERE jsonPayload.type = 'CHAT'
AND jsonPayload.chat.initiator = 'USER'
) chat
ON wf.run_id = chat.workflowrunid
GROUP BY 1, 2, 3
),
other_feature_usage AS (
SELECT
gce.datepartition,
gce.resource.labels.project_id,
gce.jsonPayload.user.userid,
COUNT(
DISTINCT CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND (
gce.jsonPayload.search.initiator IN ('USER', 'PAGE_LOAD', 'ONBOARDING')
AND LOWER(gce.jsonPayload.Search.modality) NOT IN
('gleanbot', 'slackbot_command', 'slackbot_leaderboard', 'slackbot_retry', '')
)
) THEN gce.jsonPayload.search.trackingtoken END
) + COUNT(
CASE WHEN (
gce.jsonPayload.type = 'SEARCH'
AND gce.jsonPayload.search.isrestclientapi
) THEN 1 END
) AS num_searches,
COUNT(
DISTINCT CASE WHEN (
-- Depending on category, opening links/documents counts towards DAU
gce.jsonPayload.clientevent.event IN ('OpenDocument', 'OpenLink')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Search Result'
, 'Autocomplete'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
, 'New Tab Page'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
, 'Featured Question and Answer'
, 'Generated Question and Answer'
, 'Pins'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Verification'
, 'Datasource Auth'
, 'Insights'
-- Feature related interactions count towards DAU
, 'Chat'
, 'Result Preview'
, 'App Card'
, 'Customer Card'
, 'Search'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
OR (
-- Depending on category, certain feature related clicks count towards DAU
gce.jsonPayload.clientevent.event IN ('Click')
AND gce.jsonPayload.clientevent.category IN (
-- Autocomplete and Search interactions count towards DAU
'Autocomplete'
, 'Search Result'
, 'Datasource Filter'
, 'Facets'
-- New tab page(NTP) and Homepage interactions count towards DAU
, 'Feed'
, 'Calendar'
-- Directory tab interactions count towards DAU
, 'Org Chart'
, 'Person Card'
, 'Teams'
, 'Profile'
, 'People Celebrations'
, 'Person Attribution'
-- Sidebar interactions count towards DAU
, 'Sidebar Tabs'
-- User Generated Content(UGC) interactions count towards DAU
, 'Announcements'
, 'Answers'
, 'Collections'
-- Golinks interactions counts towards DAU
, 'Shortcuts'
-- Admin and Setup page interactions count towards DAU
, 'Datasource Auth'
, 'User Menu'
, 'Admin Console'
-- Other tangible user interactions that count towards DAU
, 'Feedback'
)
)
-- CRUD operations on User Generated Content(UGC) always count always count towards DAU
OR (
gce.jsonPayload.clientevent.event IN ('Add', 'Create', 'Delete')
AND gce.jsonPayload.clientevent.category IN ('Announcements', 'Answers', 'Collections')
)
OR (
gce.jsonPayload.clientevent.event IN ('View')
AND gce.jsonPayload.clientevent.category IN (
-- User Generated Content(UGC) interactions count towards DAU
'Announcements'
,'Answers'
,'Collections'
-- Directory tab interactions count towards DAU
,'Person Card'
,'Team Card'
,'Org Chart'
)
AND gce.jsonPayload.clientevent.pagepath NOT IN ('/', '/ntp', '/search')
)
/* Summarization expansion */
OR (gce.jsonPayload.clientevent.event = 'Expand' AND gce.jsonPayload.clientevent.category = 'Summary' AND jsonPayload.clientevent.uielement = 'summarize-card')
/* Counts Start events (user chat message in Chat tab) and Expand events (prompt expansion in Discover tab) from Sidebar V2 */
OR (gce.jsonPayload.clientevent.event in ('Start', 'Expand') AND gce.jsonPayload.clientevent.category = 'Sidebar V2')
/* Counts Start events (user query or preset click) from Inline Menu */
OR (gce.jsonPayload.clientevent.event = 'Start' AND gce.jsonPayload.clientevent.category = 'Inline Menu')
/* Counts visits to past chats via GleanChat Conversation History */
OR (gce.jsonPayload.clientevent.event = 'Click' AND gce.jsonPayload.clientevent.category = 'Chat' AND jsonPayload.clientevent.uielement = 'chats-menu')
THEN gce.jsonPayload.clientevent.SessionTrackingToken END
) AS num_client_active_sessions,
COUNT(
CASE WHEN (
gce.jsonPayload.Type IN ('SEARCH_CLICK','CHAT_FEEDBACK','SEARCH_FEEDBACK')
OR gce.jsonPayload.Type IN ('SHORTCUT')
AND gce.jsonPayload.shortcut.event IN ('REDIRECT', 'CREATE', 'DELETE', 'UPDATE')
) THEN 1 END
) >= 1 AS is_active_other
FROM
glean_customer_event gce
WHERE
gce.jsonPayload.type NOT IN ('CHAT','WORKFLOW')
GROUP BY
1, 2, 3
),
slackbot_usage AS (
WITH event_traces AS (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.gleanbotactivity.eventtrackingtoken,
jsonPayload.gleanbotactivity.responseevents,
jsonPayload.gleanbotactivity.eventtype,
jsonPayload.gleanbotactivity.workflowexecutionpoints,
jsonPayload.gleanbotactivity.stt
FROM
glean_customer_event
WHERE
jsonPayload.type = 'GLEAN_BOT_ACTIVITY'
AND LOWER(jsonPayload.gleanbotactivity.source) = 'slack'
),
slack_reactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN bot_responded THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_reactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
'REACTIVE_ACT_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that got a successful response from the bot should be counted
OR 'REACTIVE_GENERATION_RESPONSE_MODAL' IN UNNEST(message_data.responseevents) -- Gleanbot added value to users other than the question asker by generating responses for them
OR 'COMMAND_SEARCH_RESULTS_MESSAGE' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response
OR 'COMMAND_SEARCH_UPDATE_MODAL_WITH_RESULTS' IN UNNEST(message_data.responseevents) -- Messages that were triggered through a /glean command and got results as response on retry
OR 'COMMAND_WORKFLOW_SUCCESS' IN UNNEST(message_data.responseevents) -- Response was successfully generated after user queried through glean console
OR 'DISCUSSION_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a thread discussion was successfully sent through glean DM
OR 'SINGLE_CHANNEL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a channel discussion was successfully sent through glean DM
OR 'DOC_URL_SUMMARY_SENT' IN UNNEST(message_data.responseevents) -- [Slack Compete] Response to summarize a uploaded doc discussion was successfully sent through glean DM
AS bot_responded,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints) AS response_downvoted, -- Response was dismissed by the user
'SHOW_SOURCES_CLICK_SUCCESS' IN UNNEST(interaction_data.workflowexecutionpoints) AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful -- Response was voted as not helpful
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack reactive bot workflow starting points that could potentitally contribute to active users definition
(
'REACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow started successfully
OR 'REACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for assistant type started
OR 'REACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where reactive workflow for search type started
OR 'COMMAND_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where /glean command was used to initiate a reactive search
OR 'COMMAND_DISCUSSION_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a discussion/query
OR 'COMMAND_CHANNEL_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize a channel
OR 'COMMAND_DOC_SUMMARIZE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where glean console was used to summarize an attached/shared doc
OR eventtype IN (
'TAGGED_MESSAGE' -- Identify messages where @glean was mentioned
, 'GENERATE_ANSWER' -- Identify messages where someone clicked on generate answer button
, 'COMMAND' -- Identify messages where /glean was mentioned
, 'DM_TO_GLEANBOT_MESSAGE' -- [Slack Compete] Identify messages where user sent DM to glean bot with a query
)
)
AND NOT 'REACTIVE_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'REACTIVE_DISABLED_FAILURE_FOR_USER' IN UNNEST(workflowexecutionpoints) -- Remove the events where reactive workflow cannont be triggered for the user Eg: Insufficient permissions
AND NOT 'COMMAND_BAD_REQUEST' IN UNNEST(workflowexecutionpoints) -- Remove the event where /glean command was triggered in an invalid channel/by invalid user
AND NOT 'COMMAND_SEARCH_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to load results
AND NOT 'COMMAND_SEARCH_NO_RESULTS_MODAL_UPDATE_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove cases where /glean command failed to update and dispaly results
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition,
project_id,
userid
),
slack_proactive_bot_activity AS (
SELECT
datepartition,
project_id,
userid,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses,
COUNT(DISTINCT CASE
WHEN response_downvoted THEN NULL
WHEN voted_helpful THEN eventtrackingtoken
WHEN citations_shown THEN eventtrackingtoken
WHEN response_shared THEN eventtrackingtoken
WHEN bot_responded_on_users_request AND NOT voted_not_helpful AND NOT digest_consumed THEN eventtrackingtoken
ELSE NULL END) AS num_useful_responses_without_digest,
COUNT(DISTINCT CASE
WHEN voted_not_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_downvotes,
COUNT(DISTINCT CASE
WHEN voted_helpful THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_upvotes,
COUNT(DISTINCT CASE
WHEN bot_responded THEN eventtrackingtoken
ELSE NULL END) AS num_slack_proactive_bot_responses
FROM (
SELECT
message_data.datepartition,
message_data.project_id,
message_data.userid,
message_data.eventtrackingtoken,
message_data.eventtype IN ('NON_TAGGED_MESSAGE', 'PROACTIVE_DISCUSSION_SUMMARIZER') AS workflow_started,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'PROACTIVE_MESSAGE' IN UNNEST(message_data.responseevents)
AS bot_responded,
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
OR 'VIEW_DIGEST' IN UNNEST(message_data.responseevents)
AS bot_responded_on_users_request,
interaction_data.eventtype = 'SHARE_CLICK' AS response_shared, -- Response was shared by the user
'SUBMIT_FEEDBACK_WORKFLOW_DOWNVOTE' IN UNNEST(interaction_data.workflowexecutionpoints)
OR interaction_data.eventtype = 'DISMISS_SUGGESTION'
AS response_downvoted, -- Response was dismissed by the user
interaction_data.eventtype = 'SHOW_SOURCES' AS citations_shown, -- Response was checked for its citation source
'SHARE_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_helpful, -- Response was voted as helpful
'SHARE_NOT_HELPFUL' IN UNNEST(interaction_data.responseevents) AS voted_not_helpful, -- Response was voted as not helpful
'DAILY_DIGEST_REMINDER_SENT' IN UNNEST(message_data.responseevents) AS digest_sent, -- Bot sent user daily digest over DM
'VIEW_DIGEST' IN UNNEST(message_data.responseevents) AS digest_consumed, -- Digest was opened and viewed by the user
'DISCUSSION_SUMMARY_THREAD_SUMMARY_SENT' IN UNNEST(message_data.responseevents)
OR 'DISCUSSION_SUMMARY_DM_RESPONSE_SENT' IN UNNEST(message_data.responseevents)
AS proactive_summary_sent
FROM (
SELECT
*
FROM
event_traces
WHERE
-- Identify the set of valid slack proactive bot workflow starting points that could potentitally contribute to active users definition
(
'PROACTIVE_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow started
OR 'PROACTIVE_CHAT_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for assistant type started
OR 'PROACTIVE_SEARCH_WORKFLOW_START' IN UNNEST(workflowexecutionpoints) -- Identify messages where proactive workflow for search type started
OR eventtype IN (
'NON_TAGGED_MESSAGE' -- All messages that were not DMs and did not mention @Glean or \glean fall in this category
, 'PROACTIVE_DISCUSSION_SUMMARIZER' -- All events for which proactive thread summarizer workflow is initiated
, 'VIEW_DIGEST_CLICK' -- All events where proactive digest was clicked
, 'DAILY_DIGEST_REMINDER' -- All events where digest was subscribed to and thus proactively sent over DM
)
)
AND NOT 'PROACTIVE_BOT_DISABLED_FAILURE' IN UNNEST(workflowexecutionpoints) -- Remove the events where proactive workflow cannont be triggered. Eg: Invalid Channel
AND NOT 'DROP_BOT_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events which represent messages sent by other bots, so we dont converse with slack automations
AND NOT 'DROP_EXTERNAL_CHANNEL_MESSAGE' IN UNNEST(workflowexecutionpoints) -- Remove the events that correspond to messages sent on external channels.
) AS message_data
LEFT JOIN (
SELECT
*
FROM
event_traces
WHERE
eventtype IN (
'SHOW_SOURCES' -- All events where a user clicked on show sources modal
, 'SHARE_HELPFULNESS' -- All events for which helpful/not helpful buttons click was initiated
, 'SHARE_CLICK' -- All events for which sharing workflow was started
, 'SUBMIT_FEEDBACK' -- All events for which manual feedback workflow was started
, 'DISMISS_SUGGESTION' -- All events for which dismiss suggestion workflow was initiated
)
) AS interaction_data
ON
message_data.project_id = interaction_data.project_id
AND message_data.eventtrackingtoken = interaction_data.stt
)
GROUP BY
datepartition, project_id, userid
)
SELECT
COALESCE(p.datepartition, r.datepartition) AS datepartition,
COALESCE(p.project_id, r.project_id) AS project_id,
COALESCE(p.userid, r.userid) AS userid,
COALESCE(r.num_useful_responses, 0) AS reactive_num_useful_responses,
COALESCE(p.num_useful_responses, 0) AS proactive_num_useful_responses,
COALESCE(p.num_useful_responses_without_digest, 0) AS proactive_num_useful_responses_without_digest,
COALESCE(r.num_useful_responses, 0) + COALESCE(p.num_useful_responses, 0) AS total_num_useful_responses,
COALESCE(r.num_slack_reactive_bot_downvotes, 0)+ COALESCE(p.num_slack_proactive_bot_downvotes, 0) AS total_num_slackbot_downvotes,
COALESCE(r.num_slack_reactive_bot_upvotes, 0)+ COALESCE(p.num_slack_proactive_bot_upvotes, 0) AS total_num_slackbot_upvotes,
COALESCE(r.num_slack_reactive_bot_responses, 0)+ COALESCE(p.num_slack_proactive_bot_responses, 0) AS total_num_slackbot_responses
FROM slack_proactive_bot_activity p
FULL OUTER JOIN slack_reactive_bot_activity r
ON p.datepartition = r.datepartition
AND p.project_id = r.project_id
AND p.userid = r.userid
),
ai_summarizations AS (
SELECT
summ_runs.datepartition,
summ_runs.project_id,
summ_runs.userid,
COUNT(DISTINCT summ_runs.run_id) AS num_summarizations
FROM (
SELECT
jsonPayload.workflow.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
MIN(datepartition) AS datepartition
FROM
glean_customer_event
WHERE
jsonPayload.workflow.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
AND jsonPayload.workflow.initiator IN ('USER', 'SUMMARIZE')
GROUP BY
1, 2, 3
UNION ALL
SELECT DISTINCT
jsonPayload.workflowrun.runid AS run_id,
resource.labels.project_id,
jsonPayload.user.userid,
datepartition
FROM
glean_customer_event,
UNNEST(jsonPayload.workflowrun.stepexecutions) AS stepexecutions
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.initiator IN ('USER', 'SUMMARIZE')
AND stepexecutions.workflowid IN (
'SUMMARIZE',
'MEETING_SUMMARIZER',
'DISCUSSION_SUMMARIZER',
'MULTI_QUERY_SUMMARIZER'
)
) summ_runs
GROUP BY
1, 2, 3
),
ai_answers AS (
SELECT
COALESCE(waa.datepartition, aa.datepartition) AS datepartition,
COALESCE(waa.project_id, aa.project_id) AS project_id,
COALESCE(waa.userid, aa.userid) AS userid,
COUNT(DISTINCT waa.runid) + COUNT(DISTINCT CASE WHEN waa.runid IS NULL THEN aa.trackingtoken END) AS num_ai_answers
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.workflowrun.runid,
jsonPayload.workflowrun.sourcetrackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'WORKFLOW_RUN'
AND jsonPayload.workflowrun.feature = 'AI_ANSWER'
AND jsonPayload.workflowrun.platform = 'WEB'
AND jsonPayload.workflowrun.initiator = 'GLEAN'
) waa
FULL OUTER JOIN (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
jsonPayload.aianswer.trackingtoken
FROM
glean_customer_event
WHERE
jsonPayload.type = 'AI_ANSWER'
AND COALESCE(jsonPayload.aianswer.trackingtoken, '') != ''
) aa
ON
waa.project_id = aa.project_id
AND waa.userid = aa.userid
AND waa.sourcetrackingtoken = aa.trackingtoken
AND waa.datepartition = aa.datepartition
GROUP BY
1, 2, 3
),
chat_feedback AS (
SELECT
datepartition,
project_id,
userid,
SUM(CASE WHEN event = 'UPVOTE' THEN 1 ELSE 0 END) AS num_chat_upvotes,
SUM(CASE WHEN event = 'DOWNVOTE' THEN 1 ELSE 0 END) AS num_chat_downvotes
FROM (
SELECT
datepartition,
resource.labels.project_id,
jsonPayload.user.userid,
COALESCE(
jsonPayload.chatfeedback.runid,
jsonPayload.chatfeedback.messageid,
jsonPayload.aianswervote.trackingtoken,
jsonPayload.aisummaryvote.trackingtoken
) AS requestid,
-- take latest vote. disregard manual feedback
MAX_BY(
COALESCE(
jsonPayload.chatfeedback.event,
jsonPayload.aianswervote.vote,
jsonPayload.aisummaryvote.vote
),
timestamp
) AS event
FROM
glean_customer_event
WHERE
(
jsonPayload.type = 'CHAT_FEEDBACK'
AND jsonPayload.chatfeedback.event IN ('UPVOTE', 'DOWNVOTE')
-- coalesce for backward compatibility with workflowid and agentid
AND COALESCE(jsonPayload.chatfeedback.agentid, jsonPayload.chatfeedback.workflowid) is NULL -- ignore feedback from agent workflows
) OR (
jsonPayload.type = 'AI_ANSWER_VOTE'
AND jsonPayload.aianswervote.vote IN ('UPVOTE', 'DOWNVOTE')
) OR (
jsonPayload.type = 'AI_SUMMARY_VOTE'
AND jsonPayload.aisummaryvote.vote IN ('UPVOTE', 'DOWNVOTE')
)
GROUP BY
1, 2, 3, 4
)
GROUP BY
1, 2, 3
),
feature_usage AS (
WITH join_0 AS (
SELECT
COALESCE(other_feature_usage.datepartition, chat_usage.datepartition) AS datepartition,
COALESCE(other_feature_usage.project_id, chat_usage.project_id) AS project_id,
COALESCE(other_feature_usage.userid, chat_usage.userid) AS userid,
COALESCE(other_feature_usage.num_searches, 0) AS _num_searches,
COALESCE(other_feature_usage.num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(other_feature_usage.is_active_other, FALSE) AS _is_active_other,
COALESCE(chat_usage.num_chat_queries, 0) AS _num_chats
FROM
other_feature_usage
FULL OUTER JOIN
chat_usage
ON
other_feature_usage.datepartition = chat_usage.datepartition
AND other_feature_usage.project_id = chat_usage.project_id
AND other_feature_usage.userid = chat_usage.userid
),
join_1 AS (
SELECT
COALESCE(join_0.datepartition, slackbot_usage.datepartition) AS datepartition,
COALESCE(join_0.project_id, slackbot_usage.project_id) AS project_id,
COALESCE(join_0.userid, slackbot_usage.userid) AS userid,
COALESCE(join_0._num_searches, 0) AS _num_searches,
COALESCE(join_0._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_0._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_0._num_chats, 0) AS _num_chats,
COALESCE(slackbot_usage.total_num_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(slackbot_usage.total_num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(slackbot_usage.total_num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(slackbot_usage.total_num_slackbot_responses, 0) AS _num_slackbot_responses
FROM
join_0
FULL OUTER JOIN
slackbot_usage
ON
join_0.datepartition = slackbot_usage.datepartition
AND join_0.project_id = slackbot_usage.project_id
AND join_0.userid = slackbot_usage.userid
),
join_2 AS (
SELECT
COALESCE(join_1.datepartition, ai_summarizations.datepartition) AS datepartition,
COALESCE(join_1.project_id, ai_summarizations.project_id) AS project_id,
COALESCE(join_1.userid, ai_summarizations.userid) AS userid,
COALESCE(join_1._num_searches, 0) AS _num_searches,
COALESCE(join_1._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_1._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_1._num_chats, 0) AS _num_chats,
COALESCE(join_1._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_1._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_1._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_1._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(ai_summarizations.num_summarizations, 0) AS _num_summarizations
FROM
join_1
FULL OUTER JOIN
ai_summarizations
ON
join_1.datepartition = ai_summarizations.datepartition
AND join_1.project_id = ai_summarizations.project_id
AND join_1.userid = ai_summarizations.userid
),
join_3 AS (
SELECT
COALESCE(join_2.datepartition, ai_answers.datepartition) AS datepartition,
COALESCE(join_2.project_id, ai_answers.project_id) AS project_id,
COALESCE(join_2.userid, ai_answers.userid) AS userid,
COALESCE(join_2._num_searches, 0) AS _num_searches,
COALESCE(join_2._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_2._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_2._num_chats, 0) AS _num_chats,
COALESCE(join_2._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_2._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_2._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_2._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_2._num_summarizations, 0) AS _num_summarizations,
COALESCE(ai_answers.num_ai_answers, 0) AS _num_ai_answers
FROM
join_2
FULL OUTER JOIN
ai_answers
ON
join_2.datepartition = ai_answers.datepartition
AND join_2.project_id = ai_answers.project_id
AND join_2.userid = ai_answers.userid
)
SELECT
COALESCE(join_3.datepartition, chat_feedback.datepartition) AS datepartition,
COALESCE(join_3.project_id, chat_feedback.project_id) AS project_id,
COALESCE(join_3.userid, chat_feedback.userid) AS userid,
COALESCE(join_3._num_searches, 0) AS _num_searches,
COALESCE(join_3._num_ai_answers, 0) AS _num_ai_answers,
COALESCE(join_3._num_client_active_sessions, 0) AS _num_client_active_sessions,
COALESCE(join_3._is_active_other, FALSE) AS _is_active_other,
COALESCE(join_3._num_chats, 0) AS _num_chats,
COALESCE(join_3._num_slackbot_useful_responses, 0) AS _num_slackbot_useful_responses,
COALESCE(join_3._num_slackbot_downvotes, 0) AS _num_slackbot_downvotes,
COALESCE(join_3._num_slackbot_upvotes, 0) AS _num_slackbot_upvotes,
COALESCE(join_3._num_slackbot_responses, 0) AS _num_slackbot_responses,
COALESCE(join_3._num_summarizations, 0) AS _num_summarizations,
COALESCE(chat_feedback.num_chat_upvotes, 0) AS _num_chat_upvotes,
COALESCE(chat_feedback.num_chat_downvotes, 0) AS _num_chat_downvotes
FROM
join_3
FULL OUTER JOIN
chat_feedback
ON
join_3.datepartition = chat_feedback.datepartition
AND join_3.project_id = chat_feedback.project_id
AND join_3.userid = chat_feedback.userid
),
canonicalized AS (
SELECT
feature_usage.datepartition,
feature_usage.project_id,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, feature_usage.userid) AS userid,
COALESCE(SUM(_num_searches), 0) AS num_searches,
COALESCE(SUM(_num_chats), 0) AS num_chats,
COALESCE(SUM(_num_ai_answers), 0) AS num_ai_answers,
COALESCE(SUM(_num_summarizations), 0) AS num_summarizations,
COALESCE(SUM(_num_chat_upvotes), 0) AS num_chat_upvotes,
COALESCE(SUM(_num_chat_downvotes), 0) AS num_chat_downvotes,
COALESCE(SUM(_num_client_active_sessions), 0) AS num_client_active_sessions,
COALESCE(SUM(_num_slackbot_useful_responses), 0) AS num_slackbot_useful_responses,
COALESCE(SUM(_num_slackbot_downvotes), 0) AS num_slackbot_downvotes,
COALESCE(SUM(_num_slackbot_upvotes), 0) AS num_slackbot_upvotes,
COALESCE(SUM(_num_slackbot_responses), 0) AS num_slackbot_responses,
COALESCE(LOGICAL_OR(_is_active_other), FALSE) AS is_active_other
FROM
feature_usage
LEFT JOIN
id_to_alias
ON
feature_usage.project_id = id_to_alias.project_id
AND feature_usage.userid = id_to_alias.aliasid
AND feature_usage.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, feature_usage.userid) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, feature_usage.userid) IS NOT NULL
GROUP BY
1, 2, 3
HAVING
COALESCE(SUM(_num_searches), 0) > 0
OR COALESCE(SUM(_num_chats), 0) > 0
OR COALESCE(SUM(_num_ai_answers), 0) > 0
OR COALESCE(SUM(_num_summarizations), 0) > 0
OR COALESCE(SUM(_num_client_active_sessions), 0) > 0
OR COALESCE(SUM(_num_slackbot_useful_responses), 0) > 0
OR COALESCE(SUM(_num_chat_upvotes), 0) > 0
OR COALESCE(SUM(_num_chat_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_downvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_upvotes), 0) > 0
OR COALESCE(SUM(_num_slackbot_responses), 0) > 0
OR COALESCE(LOGICAL_OR(_is_active_other), FALSE)
),
shortcut_events AS (
SELECT
datepartition,
jsonPayload.user.userid AS user_id,
'SHORTCUT' AS ugc_type,
CAST(CAST(jsonPayload.shortcut.id AS INT) AS STRING) AS ugc_id,
UPPER(jsonPayload.shortcut.event) AS event_type,
COUNT(*) AS frequency
FROM
glean_customer_event
WHERE
jsonPayload.type = 'SHORTCUT'
AND UPPER(jsonPayload.shortcut.event) = ('REDIRECT')
AND jsonPayload.shortcut.id IS NOT NULL
AND jsonPayload.user.userid IS NOT NULL
GROUP BY
1, 2, 3, 4, 5
),
ugc_usage AS (
SELECT
shortcut_events.datepartition,
COALESCE(latest_orgchart_data.userid, id_to_alias.canonicalid, shortcut_events.user_id) AS user_id,
shortcut_events.ugc_type,
shortcut_events.ugc_id,
shortcut_events.event_type,
SUM(shortcut_events.frequency) AS frequency
FROM
shortcut_events
LEFT JOIN
id_to_alias
ON
shortcut_events.user_id = id_to_alias.aliasid
AND shortcut_events.datepartition = id_to_alias.datepartition
LEFT JOIN
glean_customer_event.latest_orgchart_data AS latest_orgchart_data
ON
COALESCE(id_to_alias.canonicalid, shortcut_events.user_id) = latest_orgchart_data.loggingid
WHERE
COALESCE(id_to_alias.canonicalid, shortcut_events.user_id) IS NOT NULL
GROUP BY 1, 2, 3, 4, 5
)
SELECT
CAST(u.ugc_id AS INT) AS ShortcutId,
COALESCE(SUM(frequency), 0) AS VisitCount,
COUNT(DISTINCT u.user_id) AS VisitorCount
FROM
ugc_usage u
LEFT JOIN
glean_customer_event.latest_orgchart_data o
ON
u.user_id = o.userid
WHERE
(1=1)
AND u.ugc_type = 'SHORTCUT'
AND u.datepartition BETWEEN DATE(start_date) AND DATE(end_date)
GROUP BY
1
ORDER BY
2 DESC
LIMIT 100