Analyze feature adoption
You can use Lakehouse to analyze which Atlan features users adopt and how deeply they engage with each area.
This page provides queries for feature adoption in the USAGE_ANALYTICS schema, including connector usage, adoption matrices, engagement quadrants, trends, and top events and pages.
Before you begin
Before you run these queries, make sure:
- Your Lakehouse setup is complete and Lakehouse is enabled for your organization. If setup isn't complete, see Get started with Lakehouse.
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}}: UseUSAGE_ANALYTICS{{DOMAIN}}: Customer domain, for example'acme.atlan.com'{{START_DATE}}: Start date, for example'2025-01-01'
Connector usage
Shows which data source connectors and asset types users interact with, revealing whether a customer uses only one source system or a broader set of integrations.
- Snowflake
-- connector_usage.sql
-- Which data source connectors and asset types customers interact with.
-- Reveals if a customer uses only Snowflake or also Tableau, dbt, etc.
--
-- Pattern: Schema-aware (domain from PAGES directly, user_id as identity key).
-- PAGES has domain natively so no USERS join is needed.
--
-- Parameters:
-- {{START_DATE}} - e.g., '2025-01-01'
-- {{DOMAIN}} - e.g., 'acme.atlan.com' (or replace filter with 1=1 for all)
SELECT
p.domain,
p.connector_name,
p.type_name AS asset_type,
COUNT(*) AS interactions,
COUNT(DISTINCT p.user_id) AS unique_users,
COUNT(DISTINCT p.asset_guid) AS unique_assets_viewed
FROM {{DATABASE}}.{{SCHEMA}}.PAGES p
WHERE p.TIMESTAMP >= {{START_DATE}}
AND p.connector_name IS NOT NULL
AND p.domain IS NOT NULL
AND p.domain = {{DOMAIN}}
GROUP BY p.domain, p.connector_name, p.type_name
ORDER BY interactions DESC;
Sample output
| DOMAIN | CONNECTOR_NAME | ASSET_TYPE | INTERACTIONS | UNIQUE_USERS | UNIQUE_ASSETS_VIEWED |
|---|---|---|---|---|---|
| acme.atlan.com | snowflake | Table | 8420 | 87 | 1240 |
| acme.atlan.com | tableau | TableauDashboard | 2310 | 54 | 187 |
| acme.atlan.com | dbt | dbtModel | 1180 | 31 | 412 |
Feature adoption matrix
Produces a per-user, per-month boolean matrix showing which feature areas each user accessed. Combines page visits and tracked events into logical feature categories such as Discovery, Governance, AI Copilot, and Lineage.
- Snowflake
-- feature_adoption_matrix.sql
-- Feature-by-user boolean matrix per month.
-- Maps raw page names and events into logical feature areas.
--
-- Pattern: Schema-aware (domain from PAGES directly, user_id as identity key).
-- LEFT JOINs to USERS only for optional metadata (email, username, role).
--
-- Feature area mapping (derived from data exploration):
-- Discovery/Search: pages=discovery, events=discovery_search_*, discovery_filter_*, discovery_asset_*
-- Chrome Extension: pages=reverse-metadata-sidebar, events=chrome_reverse_*
-- Insights/SQL: pages=saved_query, events=insights_*
-- Governance: pages=glossary/term/category/classifications, events=governance_*, gtc_tree_*
-- AI Copilot: events=atlan_ai_*
-- Lineage: events=lineage_*
-- Asset Profile: pages=asset_profile/overview
-- Admin: pages=users/personas/config/sso/api-access/api_keys/policyManager
-- Workflows: pages=workflows-home/workflows-profile/runs
-- Data Quality: pages=monitor
--
-- 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
),
page_features AS (
SELECT
p.user_id,
p.domain,
DATE_TRUNC('MONTH', CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', p.TIMESTAMP)) AS activity_month,
CASE
WHEN p.name = 'discovery' THEN 'Discovery'
WHEN p.name = 'reverse-metadata-sidebar' THEN 'Chrome Extension'
WHEN p.name = 'saved_query' THEN 'Insights/SQL'
WHEN p.name IN ('glossary', 'term', 'category', 'classifications', 'custom_metadata') THEN 'Governance'
WHEN p.name IN ('asset_profile', 'overview') THEN 'Asset Profile'
WHEN p.name IN ('users', 'personas', 'config', 'sso', 'api-access', 'api_keys', 'policyManager', 'manage') THEN 'Admin'
WHEN p.name IN ('workflows-home', 'workflows-profile', 'runs', 'playbook') THEN 'Workflows'
WHEN p.name = 'monitor' THEN 'Data Quality'
WHEN p.name = 'home' THEN 'Home'
WHEN p.name = 'marketplace' THEN 'Marketplace'
WHEN p.name = 'insights' THEN 'Insights/SQL'
WHEN p.name = 'inbox' THEN 'Notifications'
WHEN p.name = 'usage' THEN 'Usage Analytics'
ELSE 'Other'
END AS feature_area
FROM {{DATABASE}}.{{SCHEMA}}.PAGES p
WHERE p.TIMESTAMP >= {{START_DATE}} AND p.name IS NOT NULL
),
event_features AS (
SELECT
t.user_id,
ud.domain,
DATE_TRUNC('MONTH', CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', t.TIMESTAMP)) AS activity_month,
CASE
WHEN t.event_text LIKE 'discovery_%' THEN 'Discovery'
WHEN t.event_text LIKE 'chrome_%' THEN 'Chrome Extension'
WHEN t.event_text LIKE 'insights_%' THEN 'Insights/SQL'
WHEN t.event_text LIKE 'governance_%' OR t.event_text LIKE 'gtc_tree_%' THEN 'Governance'
WHEN t.event_text LIKE 'atlan_ai_%' THEN 'AI Copilot'
WHEN t.event_text LIKE 'lineage_%' THEN 'Lineage'
WHEN t.event_text LIKE 'products_home_%' THEN 'Data Products'
ELSE NULL
END AS feature_area
FROM {{DATABASE}}.{{SCHEMA}}.TRACKS t
INNER JOIN user_domains ud ON ud.user_id = t.user_id
WHERE t.TIMESTAMP >= {{START_DATE}}
AND 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_%'
),
all_features AS (
SELECT user_id, domain, activity_month, feature_area FROM page_features WHERE feature_area != 'Other'
UNION
SELECT user_id, domain, activity_month, feature_area FROM event_features WHERE feature_area IS NOT NULL
)
SELECT
af.domain,
af.activity_month,
af.user_id,
um.email,
um.username,
um.role,
MAX(CASE WHEN af.feature_area = 'Discovery' THEN 1 ELSE 0 END) AS used_discovery,
MAX(CASE WHEN af.feature_area = 'Chrome Extension' THEN 1 ELSE 0 END) AS used_chrome_ext,
MAX(CASE WHEN af.feature_area = 'Insights/SQL' THEN 1 ELSE 0 END) AS used_insights,
MAX(CASE WHEN af.feature_area = 'Governance' THEN 1 ELSE 0 END) AS used_governance,
MAX(CASE WHEN af.feature_area = 'AI Copilot' THEN 1 ELSE 0 END) AS used_ai_copilot,
MAX(CASE WHEN af.feature_area = 'Lineage' THEN 1 ELSE 0 END) AS used_lineage,
MAX(CASE WHEN af.feature_area = 'Asset Profile' THEN 1 ELSE 0 END) AS used_asset_profile,
MAX(CASE WHEN af.feature_area = 'Admin' THEN 1 ELSE 0 END) AS used_admin,
MAX(CASE WHEN af.feature_area = 'Workflows' THEN 1 ELSE 0 END) AS used_workflows,
MAX(CASE WHEN af.feature_area = 'Data Quality' THEN 1 ELSE 0 END) AS used_data_quality,
MAX(CASE WHEN af.feature_area = 'Data Products' THEN 1 ELSE 0 END) AS used_data_products,
MAX(CASE WHEN af.feature_area = 'Marketplace' THEN 1 ELSE 0 END) AS used_marketplace
FROM all_features af
LEFT JOIN (
SELECT id, email, username, role, MAX(job_role) AS job_role
FROM {{DATABASE}}.{{SCHEMA}}.USERS
WHERE email IS NOT NULL
GROUP BY id, email, username, role
) um ON um.id = af.user_id
WHERE af.domain = {{DOMAIN}}
GROUP BY af.domain, af.activity_month, af.user_id, um.email, um.username, um.role
ORDER BY af.activity_month DESC, af.user_id;
Sample output
| DOMAIN | ACTIVITY_MONTH | USER_ID | USERNAME | ROLE | USED_DISCOVERY | USED_CHROME_EXT | USED_INSIGHTS | USED_GOVERNANCE | USED_AI_COPILOT | USED_LINEAGE | USED_ASSET_PROFILE | USED_ADMIN | USED_WORKFLOWS | USED_DATA_QUALITY | USED_DATA_PRODUCTS | USED_MARKETPLACE | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| acme.atlan.com | 2025-03-01 | usr_001 | [email protected] | alice | admin | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| acme.atlan.com | 2025-03-01 | usr_002 | [email protected] | bob | member | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
Feature engagement quadrant
Plots each feature area by reach (unique users) versus depth (average events per user), inspired by Heap's engagement matrix. Helps identify which features are broadly adopted but shallow versus niche but deeply engaged.
- Snowflake
-- feature_engagement_quadrant.sql
-- Feature engagement quadrant: plots each feature by reach (unique users)
-- vs depth (avg events per user). Inspired by Heap's engagement matrix.
-- Combines PAGES and TRACKS into unified feature categories.
--
-- Pattern: Schema-aware. PAGES has domain natively; TRACKS uses user_domains CTE.
--
-- Parameters:
-- {{START_DATE}} - e.g., '2025-01-01'
-- {{DOMAIN}} - e.g., 'acme.atlan.com' (or replace filter 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
),
page_events AS (
SELECT p.user_id, CASE
WHEN p.name = 'discovery' THEN 'Discovery/Search'
WHEN p.name = 'reverse-metadata-sidebar' THEN 'Chrome Extension'
WHEN p.name IN ('saved_query', 'insights') THEN 'Insights/SQL'
WHEN p.name IN ('glossary', 'term', 'category', 'classifications', 'custom_metadata') THEN 'Governance'
WHEN p.name IN ('asset_profile', 'overview') THEN 'Asset Profile'
WHEN p.name = 'monitor' THEN 'Data Quality'
WHEN p.name IN ('workflows-home', 'workflows-profile', 'runs', 'playbook') THEN 'Workflows'
WHEN p.name = 'home' THEN 'Home'
ELSE NULL END AS feature
FROM {{DATABASE}}.{{SCHEMA}}.PAGES p
WHERE p.domain = {{DOMAIN}}
AND p.TIMESTAMP >= {{START_DATE}}
AND p.name IS NOT NULL
),
track_events AS (
SELECT t.user_id, CASE
WHEN t.event_text LIKE 'discovery_search%' THEN 'Discovery/Search'
WHEN t.event_text LIKE 'chrome_%' THEN 'Chrome Extension'
WHEN t.event_text LIKE 'insights_%' THEN 'Insights/SQL'
WHEN t.event_text LIKE 'governance_%' OR t.event_text LIKE 'gtc_tree_%' THEN 'Governance'
WHEN t.event_text LIKE 'atlan_ai_%' THEN 'AI Copilot'
WHEN t.event_text LIKE 'lineage_%' THEN 'Lineage'
WHEN t.event_text LIKE 'discovery_metadata_%' THEN 'Metadata Curation'
WHEN t.event_text = 'main_navigation_button_clicked' THEN 'Navigation'
ELSE NULL END AS feature
FROM {{DATABASE}}.{{SCHEMA}}.TRACKS t
INNER JOIN user_domains ud ON ud.user_id = t.user_id AND ud.domain = {{DOMAIN}}
WHERE t.TIMESTAMP >= {{START_DATE}}
AND 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_%'
),
combined AS (
SELECT user_id, feature FROM page_events WHERE feature IS NOT NULL
UNION ALL
SELECT user_id, feature FROM track_events WHERE feature IS NOT NULL
),
per_user AS (
SELECT feature, user_id, COUNT(*) AS events
FROM combined
GROUP BY feature, user_id
)
SELECT
feature,
COUNT(DISTINCT user_id) AS unique_users,
SUM(events) AS total_events,
ROUND(AVG(events), 1) AS avg_events_per_user,
ROUND(MEDIAN(events), 1) AS median_events_per_user
FROM per_user
GROUP BY feature
ORDER BY unique_users DESC;
Sample output
| FEATURE | UNIQUE_USERS | TOTAL_EVENTS | AVG_EVENTS_PER_USER | MEDIAN_EVENTS_PER_USER |
|---|---|---|---|---|
| Discovery/Search | 112 | 18420 | 164.5 | 87.0 |
| Asset Profile | 98 | 9830 | 100.3 | 52.0 |
| Governance | 43 | 7210 | 167.7 | 120.0 |
| AI Copilot | 28 | 3640 | 130.0 | 95.5 |
| Lineage | 21 | 1870 | 89.0 | 44.0 |
Feature trends (weekly)
Shows week-over-week unique users and total events per feature area, enabling you to spot adoption trends, seasonal patterns, or engagement drops for specific features.
- Snowflake
-- feature_trend_weekly.sql
-- Week-over-week feature usage trending for a domain.
-- Shows unique users per feature area per week.
--
-- Pattern: Schema-aware (domain from PAGES directly, user_id as identity key).
-- PAGES provides domain natively; TRACKS gets domain via user_domains CTE.
--
-- 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
),
all_activity AS (
SELECT
user_id,
domain,
DATE_TRUNC('WEEK', CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', TIMESTAMP)) AS event_week,
CASE
WHEN name = 'discovery' THEN 'Discovery'
WHEN name = 'reverse-metadata-sidebar' THEN 'Chrome Extension'
WHEN name IN ('saved_query', 'insights') THEN 'Insights/SQL'
WHEN name IN ('glossary', 'term', 'category', 'classifications', 'custom_metadata') THEN 'Governance'
WHEN name IN ('asset_profile', 'overview') THEN 'Asset Profile'
WHEN name = 'monitor' THEN 'Data Quality'
WHEN name = 'home' THEN 'Home'
ELSE NULL
END AS feature_area
FROM {{DATABASE}}.{{SCHEMA}}.PAGES
WHERE TIMESTAMP >= {{START_DATE}} AND name IS NOT NULL
UNION ALL
SELECT
t.user_id,
ud.domain,
DATE_TRUNC('WEEK', CONVERT_TIMEZONE('UTC', 'Asia/Kolkata', t.TIMESTAMP)) AS event_week,
CASE
WHEN t.event_text LIKE 'discovery_%' THEN 'Discovery'
WHEN t.event_text LIKE 'chrome_%' THEN 'Chrome Extension'
WHEN t.event_text LIKE 'insights_%' THEN 'Insights/SQL'
WHEN t.event_text LIKE 'governance_%' OR t.event_text LIKE 'gtc_tree_%' THEN 'Governance'
WHEN t.event_text LIKE 'atlan_ai_%' THEN 'AI Copilot'
WHEN t.event_text LIKE 'lineage_%' THEN 'Lineage'
ELSE NULL
END AS feature_area
FROM {{DATABASE}}.{{SCHEMA}}.TRACKS t
INNER JOIN user_domains ud ON ud.user_id = t.user_id
WHERE t.TIMESTAMP >= {{START_DATE}}
AND 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_%'
)
SELECT
event_week,
feature_area,
COUNT(DISTINCT a.user_id) AS unique_users,
COUNT(*) AS total_events
FROM all_activity a
WHERE a.feature_area IS NOT NULL
AND a.domain = {{DOMAIN}}
GROUP BY event_week, feature_area
ORDER BY event_week DESC, unique_users DESC;
Sample output
| EVENT_WEEK | FEATURE_AREA | UNIQUE_USERS | TOTAL_EVENTS |
|---|---|---|---|
| 2025-03-10 | Discovery | 78 | 4210 |
| 2025-03-10 | Asset Profile | 65 | 2180 |
| 2025-03-10 | Governance | 32 | 1450 |
| 2025-03-10 | AI Copilot | 19 | 870 |
Top events
Returns the 50 most frequently fired tracked events for a domain, filtered for noise events, with unique user counts and events-per-user ratios.
- Snowflake
-- top_events_by_domain.sql
-- Most frequent tracked events per customer domain (noise filtered).
--
-- Pattern: Schema-aware (domain from PAGES via user_domains CTE, user_id as identity key).
-- TRACKS does not have domain natively, so we derive it from PAGES.
--
-- Parameters:
-- {{START_DATE}} - e.g., '2025-01-01'
-- {{DOMAIN}} - e.g., 'acme.atlan.com' (or replace filter 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
)
SELECT
ud.domain,
t.event_text,
COUNT(*) AS event_count,
COUNT(DISTINCT t.user_id) AS unique_users,
ROUND(COUNT(*) / NULLIF(COUNT(DISTINCT t.user_id), 0), 1) AS events_per_user
FROM {{DATABASE}}.{{SCHEMA}}.TRACKS t
INNER JOIN user_domains ud ON ud.user_id = t.user_id
WHERE t.TIMESTAMP >= {{START_DATE}}
AND t.event_text IS NOT NULL
AND 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 ud.domain = {{DOMAIN}}
GROUP BY ud.domain, t.event_text
ORDER BY event_count DESC
LIMIT 50;
Sample output
| DOMAIN | EVENT_TEXT | EVENT_COUNT | UNIQUE_USERS | EVENTS_PER_USER |
|---|---|---|---|---|
| acme.atlan.com | discovery_search_results | 12840 | 98 | 131.0 |
| acme.atlan.com | main_navigation_button_clicked | 8920 | 112 | 79.6 |
| acme.atlan.com | atlan_ai_conversation_prompt_submitted | 3410 | 27 | 126.3 |
| acme.atlan.com | lineage_tab_clicked | 2180 | 45 | 48.4 |
Top pages
Returns the 50 most visited Atlan pages for a domain, with tab-level detail for sub-page analysis and views-per-user ratios.
- Snowflake
-- top_pages_by_domain.sql
-- Most visited Atlan pages per customer domain, ranked by usage.
-- Includes tab-level detail for sub-page analysis.
--
-- Pattern: Schema-aware (domain from PAGES directly, user_id as identity key).
-- USERS table is not required since PAGES has domain natively.
--
-- Parameters:
-- {{START_DATE}} - e.g., '2025-01-01'
-- {{DOMAIN}} - e.g., 'acme.atlan.com' (or replace filter with 1=1 for all)
SELECT
p.domain,
p.name AS page_name,
p.tab,
COUNT(*) AS page_views,
COUNT(DISTINCT p.user_id) AS unique_users,
ROUND(COUNT(*) / NULLIF(COUNT(DISTINCT p.user_id), 0), 1) AS views_per_user
FROM {{DATABASE}}.{{SCHEMA}}.PAGES p
WHERE p.TIMESTAMP >= {{START_DATE}}
AND p.name IS NOT NULL
AND p.domain IS NOT NULL
AND p.domain = {{DOMAIN}}
GROUP BY p.domain, p.name, p.tab
ORDER BY page_views DESC
LIMIT 50;
Sample output
| DOMAIN | PAGE_NAME | TAB | PAGE_VIEWS | UNIQUE_USERS | VIEWS_PER_USER |
|---|---|---|---|---|---|
| acme.atlan.com | asset_profile | overview | 9840 | 104 | 94.6 |
| acme.atlan.com | discovery | null | 7210 | 98 | 73.6 |
| acme.atlan.com | asset_profile | lineage | 3180 | 67 | 47.5 |
| acme.atlan.com | glossary | null | 2410 | 41 | 58.8 |