Asking Questions of the Data
Everything the app tracks lands in Application Insights, where you interrogate it with KQL
(Kusto Query Language). If you've never written KQL: it reads top-to-bottom as a pipeline. Start
from a table (customEvents), then each | filters, reshapes, or aggregates what flows through
— like Unix pipes for telemetry. That one idea is 80% of KQL; the recipes below are the rest.
Open the Azure portal → the App Insights resource → Logs, paste a recipe, adjust, run. Remember two facts from the overview: events arrive with a 2–5 minute lag, and history runs 90 days deep.
1. All Clicks in a Session
customEvents
| where name == "UserClick"
| where session_Id == "YOUR_SESSION_ID"
| order by timestamp asc
| project timestamp, actionName = tostring(customDimensions.actionName), parentContext = tostring(customDimensions.parentContext)
2. Most Common User Actions
customEvents
| where name == "UserClick"
| summarize clickCount = count() by actionName = tostring(customDimensions.actionName)
| order by clickCount desc
| take 20
| render barchart
3. Click Heatmap by Component
customEvents
| where name == "UserClick"
| summarize clicks = count() by component = tostring(customDimensions.parentContext)
| order by clicks desc
| render piechart
4. Session Flow Analysis
customEvents
| where name == "UserClick"
| summarize actions = make_list(tostring(customDimensions.actionName)) by session_Id
| extend actionCount = array_length(actions)
| where actionCount >= 3
| project session_Id, actionCount, actions
| take 100
5. Time Between Clicks
customEvents
| where name == "UserClick"
| order by session_Id, timestamp asc
| extend prevTimestamp = prev(timestamp, 1)
| extend prevSession = prev(session_Id, 1)
| where session_Id == prevSession
| extend timeBetweenClicks = datetime_diff('second', timestamp, prevTimestamp)
| summarize avgTime = avg(timeBetweenClicks), maxTime = max(timeBetweenClicks) by actionName = tostring(customDimensions.actionName)
| order by avgTime desc
6. Feature Funnel Analysis
customEvents
| where name startswith "Feature_"
| summarize
started = countif(tostring(customDimensions.action) == "started"),
completed = countif(tostring(customDimensions.action) == "completed"),
abandoned = countif(tostring(customDimensions.action) == "abandoned")
by featureName = tostring(customDimensions.featureName)
| extend completionRate = round(100.0 * completed / started, 1)
7. Error Rate by Action
customEvents
| where name == "UserClick"
| join kind=leftouter (exceptions | project session_Id, timestamp, errorType = type) on session_Id
| summarize errorCount = countif(isnotempty(errorType)), clickCount = count() by actionName = tostring(customDimensions.actionName)
| extend errorRate = 100.0 * errorCount / clickCount
| order by errorRate desc