Skip to main content
Community Hub
TL;DR

Use Lakehouse to measure daily, weekly, and monthly active users from the usage_analytics namespace.

Your AI can read this via Docs MCPcurl -fsSL "https://docs.atlan.com/install-docs-mcp" | bashConnect

Track active users

You can use Lakehouse to track daily, weekly, and monthly active users for a customer domain and monitor adoption over time. This page provides example queries for active-user metrics in the USAGE_ANALYTICS schema, including DAU, WAU, MAU, stickiness ratio, and a user roster.

note

If your Atlan users block tracking cookies or requests (for example, using Privacy Badger, ad blockers, or browser privacy settings), these metrics may be understated.

Query parameters​

These queries use the tables in the USAGE_ANALYTICS schema. For table definitions, see USAGE_ANALYTICS namespace. Replace the placeholders in each query with values for your environment.

  • {{DATABASE}}: Snowflake database name
  • {{SCHEMA}}: Use USAGE_ANALYTICS
  • {{DOMAIN}}: Customer domain, for example 'acme.atlan.com'
  • {{START_DATE}}: Start date, for example '2025-01-01'

Daily active users​

Returns the count of distinct users who performed any tracked action or page view on each calendar day for the specified domain.

-- dau_by_domain.sql
-- Daily Active Users per customer domain.
-- Uses PAGES.domain for filtering. Counts by user_id.
--
-- Parameters:
-- {{START_DATE}} - e.g., '2025-01-01'
-- {{DOMAIN}} - e.g., 'acme.atlan.com' (or replace filter line with 1=1 for all)

WITH user_domains AS (
SELECT user_id, MAX(domain) AS domain
FROM {{DATABASE}}.{{SCHEMA}}.PAGES
WHERE domain IS NOT NULL
GROUP BY user_id
),

activity_events AS (
SELECT
t.user_id,
ud.domain,
DATE(CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', t.TIMESTAMP)) AS event_date
FROM {{DATABASE}}.{{SCHEMA}}.TRACKS t
INNER JOIN user_domains ud ON ud.user_id = t.user_id
WHERE t.event_text NOT IN (
'atlan_analaytics_aggregateinfo_fetch',
'api_error_emit', 'api_evaluator_cancelled', 'api_evaluator_succeeded',
'Experiment Started', '$experiment_started',
'web_vital_metric_inp_track', 'web_vital_metric_ttfb_track',
'performance_metric_user_timing_discovery_search',
'performance_metric_user_timing_app_bootstrap',
'web_vital_metric_fcp_track', 'web_vital_metric_lcp_track'
)
AND t.event_text NOT LIKE 'workflow_%'
AND t.TIMESTAMP >= {{START_DATE}}

UNION ALL

SELECT
p.user_id,
p.domain,
DATE(CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', p.TIMESTAMP)) AS event_date
FROM {{DATABASE}}.{{SCHEMA}}.PAGES p
WHERE p.TIMESTAMP >= {{START_DATE}}
)

SELECT
domain,
event_date,
COUNT(DISTINCT user_id) AS dau
FROM activity_events
WHERE domain = {{DOMAIN}}
GROUP BY domain, event_date
ORDER BY domain, event_date DESC;
Sample output
DOMAINEVENT_DATEDAU
acme.atlan.com2025-03-1547
acme.atlan.com2025-03-1452
acme.atlan.com2025-03-1338

Weekly active users​

Returns the count of distinct users who performed any tracked action or page view within each calendar week for the specified domain.

-- wau_by_domain.sql
-- Weekly Active Users per customer domain.
-- Uses PAGES.domain for filtering. Counts by user_id.
--
-- Parameters:
-- {{START_DATE}} - e.g., '2025-01-01'
-- {{DOMAIN}} - e.g., 'acme.atlan.com' (or replace filter line with 1=1 for all)

WITH user_domains AS (
SELECT user_id, MAX(domain) AS domain
FROM {{DATABASE}}.{{SCHEMA}}.PAGES
WHERE domain IS NOT NULL
GROUP BY user_id
),

activity_events AS (
SELECT
t.user_id,
ud.domain,
DATE_TRUNC('WEEK', CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', t.TIMESTAMP)) AS event_week
FROM {{DATABASE}}.{{SCHEMA}}.TRACKS t
INNER JOIN user_domains ud ON ud.user_id = t.user_id
WHERE t.event_text NOT IN (
'atlan_analaytics_aggregateinfo_fetch',
'api_error_emit', 'api_evaluator_cancelled', 'api_evaluator_succeeded',
'Experiment Started', '$experiment_started',
'web_vital_metric_inp_track', 'web_vital_metric_ttfb_track',
'performance_metric_user_timing_discovery_search',
'performance_metric_user_timing_app_bootstrap',
'web_vital_metric_fcp_track', 'web_vital_metric_lcp_track'
)
AND t.event_text NOT LIKE 'workflow_%'
AND t.TIMESTAMP >= {{START_DATE}}

UNION ALL

SELECT
p.user_id,
p.domain,
DATE_TRUNC('WEEK', CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', p.TIMESTAMP)) AS event_week
FROM {{DATABASE}}.{{SCHEMA}}.PAGES p
WHERE p.TIMESTAMP >= {{START_DATE}}
)

SELECT
domain,
event_week,
COUNT(DISTINCT user_id) AS wau
FROM activity_events
WHERE domain = {{DOMAIN}}
GROUP BY domain, event_week
ORDER BY domain, event_week DESC;
Sample output
DOMAINEVENT_WEEKWAU
acme.atlan.com2025-03-1089
acme.atlan.com2025-03-0394
acme.atlan.com2025-02-2481

Monthly active users​

Returns the count of distinct users active each calendar month with month-over-month delta and percentage change.

-- mau_by_domain.sql
-- Monthly Active Users per customer domain with month-over-month delta.
-- Uses PAGES.domain for domain filtering. Counts by user_id (not email).
-- LEFT JOINs USERS for optional email enrichment.
--
-- Parameters:
-- {{START_DATE}} - e.g., '2025-01-01'
-- {{DOMAIN}} - e.g., 'acme.atlan.com' (or replace filter line with 1=1 for all)

WITH user_domains AS (
SELECT user_id, MAX(domain) AS domain
FROM {{DATABASE}}.{{SCHEMA}}.PAGES
WHERE domain IS NOT NULL
GROUP BY user_id
),

activity_events AS (
SELECT
t.user_id,
ud.domain,
DATE_TRUNC('MONTH', CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', t.TIMESTAMP)) AS event_month
FROM {{DATABASE}}.{{SCHEMA}}.TRACKS t
INNER JOIN user_domains ud ON ud.user_id = t.user_id
WHERE t.event_text NOT IN (
'atlan_analaytics_aggregateinfo_fetch',
'api_error_emit', 'api_evaluator_cancelled', 'api_evaluator_succeeded',
'Experiment Started', '$experiment_started',
'web_vital_metric_inp_track', 'web_vital_metric_ttfb_track',
'performance_metric_user_timing_discovery_search',
'performance_metric_user_timing_app_bootstrap',
'web_vital_metric_fcp_track', 'web_vital_metric_lcp_track'
)
AND t.event_text NOT LIKE 'workflow_%'
AND t.TIMESTAMP >= {{START_DATE}}

UNION ALL

SELECT
p.user_id,
p.domain,
DATE_TRUNC('MONTH', CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', p.TIMESTAMP)) AS event_month
FROM {{DATABASE}}.{{SCHEMA}}.PAGES p
WHERE p.TIMESTAMP >= {{START_DATE}}
),

mau_counts AS (
SELECT
domain,
event_month,
COUNT(DISTINCT user_id) AS mau
FROM activity_events
WHERE domain = {{DOMAIN}}
GROUP BY domain, event_month
)

SELECT
domain,
event_month,
mau,
LAG(mau) OVER (PARTITION BY domain ORDER BY event_month) AS prev_month_mau,
mau - LAG(mau) OVER (PARTITION BY domain ORDER BY event_month) AS mau_delta,
ROUND(100.0 * (mau - LAG(mau) OVER (PARTITION BY domain ORDER BY event_month))
/ NULLIF(LAG(mau) OVER (PARTITION BY domain ORDER BY event_month), 0), 1) AS mau_change_pct
FROM mau_counts
ORDER BY domain, event_month DESC;
Sample output
DOMAINEVENT_MONTHMAUPREV_MONTH_MAUMAU_DELTAMAU_CHANGE_PCT
acme.atlan.com2025-03-0112411865.1
acme.atlan.com2025-02-0111811087.3
acme.atlan.com2025-01-01110nullnullnull

Stickiness ratio​

Computes the DAU/MAU stickiness ratio per domain per month. A ratio greater than 0.3 indicates strong daily engagement. A ratio less than 0.1 indicates episodic usage.

-- mau_dau_ratio.sql
-- DAU/MAU stickiness ratio per domain per month.
-- >0.3 = strong daily engagement, <0.1 = episodic usage.
-- Uses PAGES.domain for filtering. Counts by user_id.
--
-- Parameters:
-- {{START_DATE}} - e.g., '2025-01-01'
-- {{DOMAIN}} - e.g., 'acme.atlan.com' (or replace filter line with 1=1 for all)

WITH user_domains AS (
SELECT user_id, MAX(domain) AS domain
FROM {{DATABASE}}.{{SCHEMA}}.PAGES
WHERE domain IS NOT NULL
GROUP BY user_id
),

activity_events AS (
SELECT
t.user_id,
ud.domain,
DATE(CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', t.TIMESTAMP)) AS event_date,
DATE_TRUNC('MONTH', CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', t.TIMESTAMP)) AS event_month
FROM {{DATABASE}}.{{SCHEMA}}.TRACKS t
INNER JOIN user_domains ud ON ud.user_id = t.user_id
WHERE t.event_text NOT IN (
'atlan_analaytics_aggregateinfo_fetch',
'api_error_emit', 'api_evaluator_cancelled', 'api_evaluator_succeeded',
'Experiment Started', '$experiment_started',
'web_vital_metric_inp_track', 'web_vital_metric_ttfb_track',
'performance_metric_user_timing_discovery_search',
'performance_metric_user_timing_app_bootstrap',
'web_vital_metric_fcp_track', 'web_vital_metric_lcp_track'
)
AND t.event_text NOT LIKE 'workflow_%'
AND t.TIMESTAMP >= {{START_DATE}}

UNION ALL

SELECT
p.user_id,
p.domain,
DATE(CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', p.TIMESTAMP)) AS event_date,
DATE_TRUNC('MONTH', CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', p.TIMESTAMP)) AS event_month
FROM {{DATABASE}}.{{SCHEMA}}.PAGES p
WHERE p.TIMESTAMP >= {{START_DATE}}
),

daily_users AS (
SELECT
domain,
event_month,
event_date,
COUNT(DISTINCT user_id) AS dau
FROM activity_events
WHERE domain = {{DOMAIN}}
GROUP BY domain, event_month, event_date
),

monthly_users AS (
SELECT
domain,
event_month,
COUNT(DISTINCT user_id) AS mau
FROM activity_events
WHERE domain = {{DOMAIN}}
GROUP BY domain, event_month
)

SELECT
m.domain,
m.event_month,
m.mau,
ROUND(AVG(d.dau), 1) AS avg_dau,
ROUND(AVG(d.dau) / NULLIF(m.mau, 0), 3) AS stickiness_ratio,
CASE
WHEN AVG(d.dau) / NULLIF(m.mau, 0) >= 0.3 THEN 'Strong'
WHEN AVG(d.dau) / NULLIF(m.mau, 0) >= 0.1 THEN 'Moderate'
ELSE 'Episodic'
END AS engagement_level
FROM monthly_users m
JOIN daily_users d ON d.domain = m.domain AND d.event_month = m.event_month
GROUP BY m.domain, m.event_month, m.mau
ORDER BY m.domain, m.event_month DESC;
Sample output
DOMAINEVENT_MONTHMAUAVG_DAUSTICKINESS_RATIOENGAGEMENT_LEVEL
acme.atlan.com2025-03-0112441.20.332Strong
acme.atlan.com2025-02-0111818.50.157Moderate
acme.atlan.com2025-01-011108.90.081Episodic

User roster​

Returns the full list of active users for a domain with activity metadata: total events, active days, first and last activity timestamps, days since last activity, and a status label (Active, Inactive, or Churned).

-- user_roster_by_domain.sql
-- Full user list for a domain with activity status, last activity, and event counts.
-- Starts from active user_ids in PAGES, LEFT JOINs USERS for metadata.
-- Shows all active users even if they have no USERS record.
--
-- Parameters:
-- {{START_DATE}} - e.g., '2025-01-01'
-- {{DOMAIN}} - e.g., 'acme.atlan.com'

WITH user_domains AS (
SELECT user_id, MAX(domain) AS domain
FROM {{DATABASE}}.{{SCHEMA}}.PAGES
WHERE domain IS NOT NULL
GROUP BY user_id
),

activity_events AS (
SELECT
t.user_id,
CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', t.TIMESTAMP) AS event_ts
FROM {{DATABASE}}.{{SCHEMA}}.TRACKS t
INNER JOIN user_domains ud ON ud.user_id = t.user_id AND ud.domain = {{DOMAIN}}
WHERE t.event_text NOT IN (
'atlan_analaytics_aggregateinfo_fetch',
'api_error_emit', 'api_evaluator_cancelled', 'api_evaluator_succeeded',
'Experiment Started', '$experiment_started',
'web_vital_metric_inp_track', 'web_vital_metric_ttfb_track',
'performance_metric_user_timing_discovery_search',
'performance_metric_user_timing_app_bootstrap',
'web_vital_metric_fcp_track', 'web_vital_metric_lcp_track'
)
AND t.event_text NOT LIKE 'workflow_%'
AND t.TIMESTAMP >= {{START_DATE}}

UNION ALL

SELECT
p.user_id,
CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', p.TIMESTAMP) AS event_ts
FROM {{DATABASE}}.{{SCHEMA}}.PAGES p
WHERE p.domain = {{DOMAIN}}
AND p.TIMESTAMP >= {{START_DATE}}
),

user_activity AS (
SELECT
user_id,
COUNT(*) AS total_events,
COUNT(DISTINCT DATE(event_ts)) AS active_days,
MIN(event_ts) AS first_activity,
MAX(event_ts) AS last_activity
FROM activity_events
GROUP BY user_id
),

user_meta AS (
SELECT id, email, username, role,
MAX(license_type) AS license_type,
MAX(job_role) AS job_role,
MIN(created_at) AS user_created_at
FROM {{DATABASE}}.{{SCHEMA}}.USERS
WHERE email IS NOT NULL
GROUP BY id, email, username, role
)

SELECT
a.user_id,
um.email,
um.username,
um.role,
um.license_type,
um.job_role,
um.user_created_at,
a.total_events,
a.active_days,
a.first_activity,
a.last_activity,
DATEDIFF('day', a.last_activity, CURRENT_TIMESTAMP()) AS days_since_last_activity,
CASE
WHEN a.last_activity >= DATEADD('day', -30, CURRENT_TIMESTAMP()) THEN 'Active'
WHEN a.last_activity >= DATEADD('day', -90, CURRENT_TIMESTAMP()) THEN 'Inactive'
WHEN a.last_activity IS NULL THEN 'Never Active'
ELSE 'Churned'
END AS status
FROM user_activity a
LEFT JOIN user_meta um ON um.id = a.user_id
ORDER BY a.total_events DESC;
Sample output
USER_IDEMAILUSERNAMEROLELICENSE_TYPEJOB_ROLEUSER_CREATED_ATTOTAL_EVENTSACTIVE_DAYSFIRST_ACTIVITYLAST_ACTIVITYDAYS_SINCE_LAST_ACTIVITYSTATUS
usr_001alice@acme.comaliceadminguestData Engineer2024-01-103420582025-01-022025-03-141Active
usr_002bob@acme.combobmembermemberData Analyst2024-02-151850412025-01-052025-03-105Active
usr_003carol@acme.comcarolmemberguestBusiness Analyst2024-03-01320122025-01-082024-12-2085Inactive