
Dt App Dashboards
- 1.6k installs
- 119 repo stars
- Updated July 29, 2026
- dynatrace/dynatrace-for-ai
dt-app-dashboards is an agent skill for work with dynatrace dashboards - create, modify, query, and analyze dashboard json including tiles, layouts, dql queries, variables, and visualizations.
About
The dt-app-dashboards skill is designed for work with Dynatrace dashboards - create, modify, query, and analyze dashboard JSON including tiles, layouts, DQL queries, variables, and visualizations. Dynatrace Dashboard Skill Overview Dynatrace dashboards are JSON documents stored in the Document Store containing tiles (content/visualizations), layouts (grid positioning), and variables (dynamic query parameters). When to use: Creating, modifying, querying, or analyzing dashboards. Invoke when the user asks about dt app dashboards or related SKILL.md workflows.
- Tile IDs in tiles must match IDs in layouts.
- Grid is 24 units wide. Common widths: 24 (full), 12 (half), 6 (quarter).
- Two tile types: markdown (text content) and data (DQL query + visualization).
- Load domain skills BEFORE generating queries — do not invent DQL.
- Validate ALL queries before adding to dashboard.
Dt App Dashboards by the numbers
- 1,592 all-time installs (skills.sh)
- +87 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #137 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
dt-app-dashboards capabilities & compatibility
- Capabilities
- tile ids in tiles must match ids in layouts · grid is 24 units wide. common widths: 24 (full), · two tile types: markdown (text content) and data · load domain skills before generating queries — d
What dt-app-dashboards says it does
Work with Dynatrace dashboards - create, modify, query, and analyze dashboard JSON including tiles, layouts, DQL queries, variables, and visualizations.
Work with Dynatrace dashboards - create, modify, query, and analyze dashboard JSON including tiles, layouts, DQL queries, variables, and visualizations.
npx skills add https://github.com/dynatrace/dynatrace-for-ai --skill dt-app-dashboardsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.6k |
|---|---|
| repo stars | ★ 119 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 29, 2026 |
| Repository | dynatrace/dynatrace-for-ai ↗ |
How do I work with dynatrace dashboards - create, modify, query, and analyze dashboard json including tiles, layouts, dql queries, variables, and visualizations?
Work with Dynatrace dashboards - create, modify, query, and analyze dashboard JSON including tiles, layouts, DQL queries, variables, and visualizations.
Who is it for?
Developers using dt app dashboards workflows documented in SKILL.md.
Skip if: Skip when the task falls outside dt-app-dashboards scope or needs a different stack.
When should I use this skill?
User asks about dt app dashboards or related SKILL.md workflows.
What you get
Completed dt-app-dashboards workflow with documented commands, files, and expected deliverables.
- Dynatrace dashboard JSON
- DQL timeseries tile definitions
- threshold-aware line chart configs
By the numbers
- Example dashboard JSON uses content version 21
Files
Dynatrace Dashboard Skill
Overview
Dynatrace dashboards are JSON documents stored in the Document Store containing tiles (content/visualizations), layouts (grid positioning), and variables (dynamic query parameters).
When to use: Creating, modifying, querying, or analyzing dashboards.
Dashboard JSON Structure
{
"name": "My Dashboard",
"type": "dashboard",
"content": {
"version": 21,
"variables": [],
"tiles": { "<id>": { "type": "data|markdown", ... } },
"layouts": { "<id>": { "x": 0, "y": 0, "w": 24, "h": 8 } }
}
}- Tile IDs in
tilesmust match IDs inlayouts - Grid is 24 units wide. Common widths: 24 (full), 12 (half), 6 (quarter)
- Two tile types:
markdown(text content) anddata(DQL query + visualization)
Optional content properties: settings, refreshRate, annotations
Create/Update Workflow (Mandatory Order)
Carefully follow the workflow described in references/create-update.md.
Key rules:
- Load domain skills BEFORE generating queries — do not invent DQL
- Validate ALL queries before adding to dashboard
- No time-range filters in queries unless explicitly requested by user
- Set
namebefore deploying - Updating — ALWAYS download first:
dtctl get dashboard <id> -o json --plain > dashboard.json, modify, then deploy the downloaded file. Never reconstruct JSON from scratch or inject anidmanually — both silently overwrite any UI edits the user made since last deployment. - Deploy with `dtctl apply` — validation runs automatically, and the local file is deleted on success.
Visualization Types
- Time-series (require
timeseries/makeTimeseries):lineChart,areaChart,barChart,bandChart - Categorical (
summarize ... by:{field}):categoricalBarChart,pieChart,donutChart - Single value/gauge (single numeric record):
singleValue,meterBar,gauge - Tabular (any data shape):
table,raw,recordList - Distribution/status:
histogram,honeycomb - Maps:
choroplethMap,dotMap,connectionMap,bubbleMap - Matrix:
heatmap,scatterplot
Required field types per visualization: references/tiles.md
Variables Quick Reference
{ "version": 2, "key": "Service", "type": "query", "visible": true,
"editable": true, "input": "smartscapeNodes SERVICE | fields name",
"multiple": false }- Single-select:
filter service.name == $Service - Multi-select:
filter in(service.name, array($Service)) - Types:
query(DQL-populated),csv(static list),text(free-form)
Full variable reference: references/variables.md
References
| File | When to Load |
|---|---|
| create-update.md | Creating/updating dashboards |
| tiles.md | Tile types, visualization field requirements, settings |
| variables.md | Variable types, replacement strategies, patterns |
| analyzing.md | Reading dashboards, extracting queries, health assessment |
{
"name": "Example Dashboard",
"type": "dashboard",
"content": {
"version": 21,
"variables": [],
"tiles": {
"0": {
"type": "markdown",
"content": "# Example Dashboard\nDemonstrates tile types and visualizations."
},
"1": {
"type": "data",
"title": "Response Time (line chart with thresholds)",
"query": "timeseries avg(dt.service.request.response_time), by:{dt.smartscape.service}",
"visualization": "lineChart",
"visualizationSettings": {
"chartSettings": {
"xAxisScaling": "analyzedTimeframe",
"legend": { "position": "right" }
},
"thresholds": [
{
"id": 1,
"field": "",
"title": "",
"isEnabled": true,
"rules": [
{ "id": 0, "color": { "Default": "var(--dt-colors-charts-status-ideal-default, #2f6862)" }, "comparator": "≥", "label": "OK", "value": 0 },
{ "id": 1, "color": { "Default": "var(--dt-colors-charts-status-warning-default, #eea53c)" }, "comparator": "≥", "label": "WARN", "value": 4000000 },
{ "id": 2, "color": { "Default": "var(--dt-colors-charts-status-critical-default, #c62239)" }, "comparator": "≥", "label": "CRITICAL", "value": 8000000 }
]
}
],
"unitsOverrides": [
{ "identifier": "avg(dt.service.request.response_time)", "unitCategory": "time", "baseUnit": "microsecond", "displayUnit": null, "decimals": null, "suffix": "", "delimiter": false, "added": 1770204632795 }
]
},
"querySettings": {}
},
"2": {
"type": "data",
"title": "Events by Category (donut)",
"query": "fetch dt.davis.events\n| summarize count(), by:{event.category}",
"visualization": "donutChart",
"visualizationSettings": {
"chartSettings": {
"circleChartSettings": { "valueType": "relative" }
}
},
"querySettings": {}
},
"3": {
"type": "data",
"title": "Total Events (single value)",
"query": "fetch dt.davis.events\n| summarize count=count()",
"visualization": "singleValue",
"visualizationSettings": {
"singleValue": {
"colorThresholdTarget": "value",
"recordField": "count",
"label": "Number Events",
"isIconVisible": true
},
"unitsOverrides": [
{ "identifier": "count", "unitCategory": "unspecified", "baseUnit": "count", "displayUnit": null, "decimals": null, "suffix": "", "delimiter": false, "added": 1770205033513 }
]
},
"querySettings": {}
}
},
"layouts": {
"0": { "x": 0, "y": 0, "w": 24, "h": 1 },
"1": { "x": 0, "y": 1, "w": 12, "h": 7 },
"2": { "x": 12, "y": 1, "w": 12, "h": 7 },
"3": { "x": 0, "y": 8, "w": 24, "h": 5 }
}
}
}
{
// Reference for visualizationSettings by visualization type.
// All properties are optional unless noted. Only visualization-specific
// differences are shown; shared patterns (legend, tooltip, zoom,
// unitsOverrides, coloring, thresholds) apply to most chart types.
// ── Shared patterns (apply to most visualizations) ──
// legend: { "position": "auto", "showLegend": true, "textTruncationMode": "end", "ratio": "auto" }
// tooltip: { "variant": "single", "seriesDisplayMode": "single-line" }
// zoom: { "isActive": true, "zoom": {"enabled": true}, "pan": {"enabled": true}, "zoomX": {"enabled": true} }
// coloring: { "colorRules": [], "thresholdRules": [] }
// unitsOverrides: [{ "identifier": "field", "unitCategory": "time", "baseUnit": "microsecond", "displayUnit": null, "decimals": null, "suffix": "", "delimiter": false, "added": <timestamp> }]
// ── Time-series charts (lineChart, areaChart, barChart, bandChart) ──
"lineChart": {
"visualizationSettings": {
"dataMapping": { "time": null, "displayedFields": [], "series": [], "interval": null },
"axes": {
"xAxis": { "label": "", "showLabel": false, "displayTimeFrame": "auto" },
"yAxis": { "label": "", "min": {"mode": "auto"}, "max": {"mode": "auto"}, "scale": "linear", "showLabel": false },
"rightYAxis": { "label": "", "min": {"mode": "auto"}, "max": {"mode": "auto"}, "scale": "linear", "showLabel": false }
},
"valueSettings": { "valueRepresentation": "absolute" },
"seriesOverrides": [],
"seriesConfig": { "curve": "linear", "pointsDisplay": "auto", "gapPolicy": "gap" },
"colorModeType": { "colorPalette": "categorical", "seriesCustomColors": [] }
}
},
// areaChart, barChart: same structure as lineChart
// bandChart: adds dataMapping.min and dataMapping.max for upper/lower band fields
// ── Categorical charts (categoricalBarChart, pieChart, donutChart) ──
"categoricalBarChart": {
"visualizationSettings": {
"categoryAxis": { "label": {"label": "", "showLabel": true}, "tickLayout": "horizontal" },
"numericAxis": { "label": {"showLabel": true, "label": ""}, "scale": "linear" },
"dataMapping": { "displayedFields": [], "values": [] },
"valueBoundaries": { "max": {"mode": "auto"}, "min": {"mode": "auto"} },
"valueSettings": { "valueRepresentation": "absolute" },
"layout": { "groupMode": "stacked", "position": "horizontal" },
"colorModeType": { "colorCategoryMode": "multi-color", "colorPalette": "categorical", "customCategoryColors": {} }
}
},
"pieChart": {
"visualizationSettings": {
"dataMapping": { "value": "", "displayedFields": [] },
"labels": { "showLabels": true },
"valueSettings": { "valueRepresentation": "absolute" },
"groupingSettings": { "groupingStrategy": "absolute", "limit": 0, "label": "" }
}
},
// donutChart: same as pieChart plus "totalLabel" in labels and "showTotals" in valueSettings
// ── Single value / gauge / meter ──
"singleValue": {
"visualizationSettings": {
"alignment": "center",
"colorThresholdTarget": "value",
"dataMapping": { "record": null, "timeseries": null, "value": null, "label": null },
"icon": "AnalyticsIcon",
"showIcon": false,
"label": { "label": "", "mode": "custom" },
"sparkline": { "color": "#3f8cff", "isVisible": true, "lineType": "linear", "variant": "line", "gapPolicy": "connect" },
"trend": { "isVisible": null, "valueRepresentation": "relative", "trendType": "auto" },
"valueBoundaries": { "min": {"mode": "auto"}, "max": {"mode": "auto"} }
}
},
"meterBar": {
"visualizationSettings": {
"valueBoundaries": { "min": {"mode": "auto"}, "max": {"mode": "auto"} },
"icon": { "showIcon": true, "icon": "MeterbarIcon" },
"label": { "showLabel": true, "label": "" },
"dataMapping": { "value": null, "maxDataField": null, "minDataField": null }
}
},
// gauge: same structure as meterBar (different default icon)
// ── Table / raw / recordView ──
"table": {
"visualizationSettings": {
"table": {
"colorThresholdTarget": "value",
"columnOrder": [],
"hiddenColumns": [],
"rowDensity": "condensed",
"sortBy": [],
"columnWidthStrategy": "content",
"enableSparklines": false,
"linewrapEnabled": false
}
}
},
// ── Distribution / status ──
"histogram": {
"visualizationSettings": {
"axes": {
"xAxis": { "label": "", "showLabel": false, "scale": "linear" },
"yAxis": { "label": "Frequency", "showLabel": true, "scale": "linear" }
},
"dataMapping": { "displayedFields": [], "value": "", "range": "" }
}
},
"honeycomb": {
"visualizationSettings": {
"shape": "hexagon",
"valueBoundaries": { "min": {"mode": "auto"}, "max": {"mode": "auto"} },
"dataMapping": { "dimension": null, "displayedFields": [] },
"labels": { "showLabels": false }
}
},
// ── Geographic maps ──
// Shared: mapView { "defaultZoom": "data", "longitude": 0, "latitude": 0, "zoom": 0 }
// Shared: regions { "showRegions": false, "regions": [] }
"choropleth": {
"visualizationSettings": {
"dataMapping": { "countryCode": null, "dimension": null, "displayedFields": [] }
}
},
"dotMap": {
"visualizationSettings": {
"dataMapping": { "bearingValue": null, "dimension": null, "latitude": null, "longitude": null, "displayedFields": [] },
"mapShape": { "bearing": 0, "shape": "pin", "shapeSize": 32, "shapeStyle": "shape" }
}
},
"connectionMap": {
"visualizationSettings": {
"dataMapping": { "latitudeList": null, "longitudeList": null, "dimension": null, "displayedFields": [] },
"mapLine": { "curve": "smooth", "directionIndicator": "start", "line": "solid", "thickness": 2 }
}
},
"bubbleMap": {
"visualizationSettings": {
"dataMapping": { "latitude": null, "longitude": null, "radius": null, "dimension": null, "displayedFields": [] },
"mapRadius": { "sizeInterpolation": "zoom", "scale": "linear", "radius": 12, "radiusRange": [10, 100] }
}
},
// ── Matrix / correlation ──
"heatmap": {
"visualizationSettings": {
"dataMapping": { "xAxis": null, "yAxis": null, "bucketValue": null },
"axes": {
"xAxis": { "label": "", "showLabel": false, "position": "bottom" },
"yAxis": { "label": "", "showLabel": false, "position": "left" }
}
}
},
"scatterplot": {
"visualizationSettings": {
"dataMapping": { "xAxis": null, "yAxis": null, "displayedFields": [] }
}
}
}
Dashboard Analysis & Information Extraction
Two Main Workflows
1. Look into dashboard — read global context, then tiles top-to-bottom 2. Search for something — find specific content by keyword
---
Workflow 1: Read Dashboard
Global Context
Read .content.version for the schema version, count entries in .content.tiles for total tile count, and count entries in .content.variables for total variable count.
For each variable in .content.variables[], note its key, type, input, and defaultValue — these are the filters available to the user.
Tiles Top-to-Bottom
To read tiles in display order, iterate .content.layouts entries sorted by .value.y then .value.x. For each entry, look up the corresponding tile in .content.tiles[id].
For a specific tile, look it up by ID in .content.tiles["<id>"] and read: title, query, visualization, and visualizationSettings.
Per tile, extract: title (what it shows), query (DQL), visualization (chart type), thresholds (color interpretation), content (markdown text).
---
Workflow 2: Search
To search by title: iterate .content.tiles and find entries where .value.title (case-insensitive) contains the keyword.
To search by query content: iterate .content.tiles and find entries where .value.query contains the search pattern.
---
Executing Queries from Dashboard
1. Extract query with title, visualization, and thresholds for context 2. Check for variables ($VarName references) 3. Resolve variables: if type=="query", execute the variable's input query to get valid values; if type=="text", use defaultValue 4. Substitute variable values into the query 5. Execute and interpret results based on visualization type and thresholds
---
Purpose Identification
Analyze tile titles and data sources to infer dashboard purpose:
- "Request Rate", "Error Count", "Response Time" → Service Health (RED)
- "CPU Usage", "Memory Usage" → Infrastructure Monitoring
- "SLI", "Error Budget" → SLO Tracking
- Single values with thresholds → Executive / KPI dashboard
To identify data sources, scan .content.tiles[].query for fetch <entity> patterns to see which Dynatrace entity types are queried.
Dashboard Create & Update Workflows
Mandatory 7-Step Order
1. Define purpose and load required skills, references and assets 2. Explore available data fields/metrics 3. Plan dashboard structure: variables, tiles, layout 4. Design and validate all DQL with dtctl query '<DQL>' --plain 5. (Update only) Download existing dashboard JSON from the server 6. Construct new dashboard JSON (create) or modify the downloaded JSON (update) 7. Deploy with dtctl apply — when updating, deploy the file downloaded in step 5
---
Mandatory Requirements
- No time-range filters in tile queries — the dashboard UI time-frame
picker handles this. Only add time filters when user explicitly requests it.
- DQL validation — test ALL queries (tile and variable) before adding
- Skill-based queries — load domain skills BEFORE generating queries;
do not invent DQL queries, field names, or data sources
- Verify field names — run a sample query (e.g.
limit 1) and only use
fields that actually exist in the result
DQL Validation
Syntax + execution validation is mandatory for all queries.
1. Validate tile queries and variable input queries 2. For queries with $VariableName: extract the variable's input query, execute it to get real values, then test the tile query with those values 3. Variable queries MUST return at least one value; tile queries may return empty results (e.g. error logs when no errors exist)
Creating Dashboards
Step 1: Define Purpose
Identify metrics, audience, and actions. Then load relevant domain skills.
Step 2: Explore Data
For fields and metrics already documented in the loaded domain skill, skip exploration — confirm with one | limit 1 query. Only run broader discovery queries for data models not covered by the skill.
Step 3: Plan Structure
Sketch approximate layout: number of tiles, positions, variables needed.
Layout Grid
Default: 24 columns (settings.gridLayout.columnsCount). Full-width w: 24, half w: 12, quarter w: 6. Height: h: 1 for headers, h: 6-8 for charts, h: 12-16 for detailed views.
Each tile in tiles must have a matching entry in layouts with x, y, w, h. Tiles with x + w > columnsCount wrap. Use standard widths for responsiveness.
"layouts": {
"1": { "x": 0, "y": 0, "w": 24, "h": 1 },
"2": { "x": 0, "y": 1, "w": 12, "h": 8 },
"3": { "x": 12, "y": 1, "w": 12, "h": 8 },
"4": { "x": 0, "y": 9, "w": 24, "h": 8 }
}Step 4: Design and Validate Queries
dtctl query '<your DQL query>' --plainAlways use single quotes around the DQL string to avoid shell interpretation of $, \, and other special characters.
Use limit to cap results. Use summarize before visualization. Source queries from loaded skills.
Step 5 (Update only): Download Existing Dashboard JSON
Skip when creating. Download the current server state before making any modifications:
dtctl get dashboard <id> -o json --plain > dashboard.jsonThis preserves user UI edits since the last deployment. The downloaded file contains the id — do not add or change it manually.
Step 6: Construct New or Modify Downloaded Dashboard JSON
For new dashboards, build JSON from scratch (no id — server assigns one). For updates, modify the file downloaded in Step 5 — do not construct new JSON and inject an id.
{
"name": "My Dashboard Name", // "id" is present when updating (from downloaded JSON)
"type": "dashboard",
"content": {
"version": 21,
"variables": [],
"tiles": {
"1": { "type": "markdown", "content": "# Title" },
"2": {
"type": "data", "title": "Metric",
"query": "fetch ... | summarize ...",
"visualization": "lineChart",
"visualizationSettings": {}, "querySettings": {}
}
},
"layouts": { "1": { "x": 0, "y": 0, "w": 24, "h": 1 }, "2": { "x": 0, "y": 1, "w": 24, "h": 8 } }
}
}Checklist before writing JSON:
- Every data tile has: unique ID, validated DQL,
visualizationSettings,querySettings, matching layout entry - Every defined variable is referenced in at least one tile query — remove unused variables
- When updating: confirm the JSON is the downloaded file (
idfield present), not a freshly constructed one
See tiles.md for visualization types and field requirements. See variables.md for variable definitions and usage patterns.
Step 7: Deploy
dtctl apply -f dashboard.json -o yaml
# preview without persisting:
dtctl apply -f dashboard.json -o yaml --dry-runValidation runs automatically before deployment. If validation fails, fix all reported errors before re-running — do not fix one error and re-deploy in a loop.
When updating: ensure dashboard.json is the file downloaded in Step 5. A missing id field means a fresh JSON is being deployed — a new dashboard will be created instead of updating.
On success, dtctl apply outputs the deployment result (action, id, name, url) and the local file is deleted automatically. Present the URL to the user.
---
Anti-Patterns
- Inventing queries without loading skills first
- Inventing DQL field names without checking sample output
- Overlapping layouts
- Hardcoding time-range filters (overrides UI time picker)
- Defining variables that are not referenced in any tile query (every variable must be used as
$keyin at least one tile query) - Missing
namein dashboard JSON - Setting a custom
idon a new dashboard (server assigns IDs; only downloaded dashboards carry theirid) - Skipping the download when updating — building JSON from scratch loses user UI edits made since last deployment
- Injecting an `id` into freshly-constructed JSON — same as above; overwrites server state with stale content
- Downloading but not using the file — deploying a freshly-constructed JSON instead of the downloaded one defeats the download step
Dashboard Tiles
Tiles are stored in content.tiles as an object map with string keys.
Tile Types
Markdown Tiles
{ "type": "markdown", "content": "# Section Header" }Data Tiles
{
"type": "data", "title": "Tile Name",
"query": "timeseries avg(metric), by:{dimension}",
"visualization": "lineChart",
"visualizationSettings": {},
"querySettings": {}
}Optional properties: description, customLinkSettings, davis, davisCopilot, timeframe, segments.
Code Tiles
{ "type": "code", "title": "Custom", "input": "// JS code",
"visualization": "lineChart", "visualizationSettings": {} }SLO Tiles
{ "type": "slo", "title": "SLO Name", "input": "slo-id",
"visualizationSettings": {} }Visualization Types and Required Field Types
Each visualization requires specific field types in the query result. If the query produces wrong types, the tile renders blank or errors. The field types below correspond to DQL output types: timestamp, timeframe, long, double, duration, string, numericArray (array of long/double — the output of timeseries/makeTimeseries value columns).
Legend: R = required, O = optional, C = conditional.
Time-Series Charts
`lineChart`, `areaChart`, `barChart`: Display metric data over time.
| Slot | Accepted types | Count | Req |
|---|---|---|---|
| Time | timestamp, timeframe | 1 | R |
| Interval | duration | 1 | C — required when Values is numericArray |
| Values | long, double, duration, numericArray | 1+ | R |
| Names | any | 1+ | O |
When the query uses timeseries or makeTimeseries, values are numericArrays and the interval field (duration) must be present. If you pipe through | fields after timeseries, always include interval and timeframe.
`bandChart`: Same as above plus two additional required numericArray slots for band min and band max values.
Categorical Charts
`categoricalBarChart`, `pieChart`, `donutChart`: Show values grouped by categories.
| Slot | Accepted types | Count | Req |
|---|---|---|---|
| Values | long, double, duration | 1+ | R |
| Categories | any | 1+ | R |
Typical query pattern: summarize <agg>, by:{category}.
`barChart` vs `categoricalBarChart`: barChart is a time-series chart requiring a timestamp/timeframe axis. For "values per category" (e.g. request count per service), use categoricalBarChart. If you use barChart with summarize ... by:{category} (no time axis), the tile will fail validation.
Timeseries data in categorical charts: If you need to show summarized metrics (not over time), first convert the timeseries arrays to scalars using array functions (arrayAvg, arraySum, etc.), then use categoricalBarChart.
Single Value / Gauge
`singleValue`: Displays a single metric.
| Slot | Accepted types | Count | Req |
|---|---|---|---|
| Single value | any | 1 | R |
| Sparkline | numericArray | 1 | O |
`meterBar`, `gauge`: Display a numeric value on a scale.
| Slot | Accepted types | Count | Req |
|---|---|---|---|
| Meter/Gauge value | long, double, duration | 1 | R |
Configure minValue/maxValue in visualizationSettings.
Tabular
`table`, `raw`, `recordList`: Any data shape. No field-type requirements.
Distribution / Status
`histogram`: Shows distribution of values.
| Slot | Accepted types | Count | Req |
|---|---|---|---|
| Range | range (object with start/end) | 1 | R |
| Values | long, double, duration | 1 | R |
| Names | any | 1+ | O |
`honeycomb`: Grid of colored cells.
| Slot | Accepted types | Count | Req |
|---|---|---|---|
| Values | long, double, duration | 1 | R |
| Names | any | 1+ | O |
Geographic Maps
`choroplethMap`: Colored regions on a map.
| Slot | Accepted types | Count | Req |
|---|---|---|---|
| Country/subdivision code | string (ISO 3166) | 1 | R |
| Color value | long, double, duration, string | 1 | R |
`dotMap`, `connectionMap`: Points on a map.
| Slot | Accepted types | Count | Req |
|---|---|---|---|
| Latitude | long, double, duration | 1 | R |
| Longitude | long, double, duration | 1 | R |
| Color value | long, double, duration, string | 1 | O |
`bubbleMap`: Sized circles on a map.
| Slot | Accepted types | Count | Req |
|---|---|---|---|
| Latitude | long, double, duration | 1 | R |
| Longitude | long, double, duration | 1 | R |
| Radius value | long, double, duration | 1 | R |
| Color value | long, double, duration, string | 1 | O |
Matrix / Correlation
`heatmap`: 2D grid with colored cells.
| Slot | Accepted types | Count | Req |
|---|---|---|---|
| X-axis | timeframe, range, string | 1 | R |
| Y-axis | timeframe, range, string | 1 | R |
| Values | long, double, duration, string | 1 | R |
bin(timestamp, ...) returns timestamp — heatmap axes do not accept timestamp. Wrap with toString(): by:{x = toString(bin(timestamp, 1h))}.
`scatterplot`: X/Y point chart.
| Slot | Accepted types | Count | Req |
|---|---|---|---|
| X-axis | timeframe, long, double, duration, string | 1 | R |
| Y-axis | long, double, duration, string | 1 | R |
| Names | any | 1+ | O |
Visualization Settings
See assets/visualization-settings.reference.jsonc for the complete per-visualization settings reference.
Common settings across visualizations: legend, tooltip, zoom, unitsOverrides, coloring, thresholds, colorModeType.
Dashboard Variables
Variables provide dynamic filtering across tiles. Defined in content.variables array, referenced in queries as $key.
Required Properties
| Property | Type | Description |
|---|---|---|
key | string | Identifier used as $key in queries |
type | string | "query", "text", or "csv" |
visible | boolean | Show in dashboard UI |
editable | boolean | Allow users to change value |
Variable Types
Query Variables (type: "query")
Dynamic values from DQL. Most common type.
{
"version": 2, "key": "Service", "type": "query",
"visible": true, "editable": true,
"input": "smartscapeNodes SERVICE | fields name | sort name asc",
"multiple": false
}Critical: Query must return exactly one field. Multiple fields break the dropdown. Variable query MUST return at least one row — empty results mean the dashboard is invalid.
Getting distinct values for variable dropdowns:
- For entity names:
smartscapeNodes SERVICE | fields name | sort name asc - For logs/events fields:
fetch logs | filter isNotNull(field) | filter field != "" | dedup field | fields field | sort field asc - Do not use
summarize by: {field}without an aggregation; usededup fieldfor distinct values - Filter out empty strings (
field != "") to avoid blank variable options and empty tile results
Multi-select with all-selected default:
{
"version": 2, "key": "Services", "type": "query",
"visible": true, "editable": true,
"input": "smartscapeNodes SERVICE | fields name | sort name asc",
"multiple": true,
"defaultValue": "3420b2ac-f1cf-4b24-b62d-61ba1ba8ed05*"
}Text Variables (type: "text")
Free-form text input.
{ "version": 1, "key": "Threshold", "type": "text",
"visible": true, "editable": true, "defaultValue": "" }CSV Variables (type: "csv")
Static predefined values. Prefer `type: "query"` when values come from live data — CSV values must exactly match real data or tiles show blank.
{ "version": 1, "key": "Status", "type": "csv",
"visible": true, "editable": true,
"input": "WARN,ERROR,INFO,NONE", "multiple": true,
"defaultValue": "3420b2ac-f1cf-4b24-b62d-61ba1ba8ed05*" }Default Values
- query/csv, `multiple: true`: use magic token
"3420b2ac-f1cf-4b24-b62d-61ba1ba8ed05*"to select all - query/csv, `multiple: false`: omit
defaultValue(first value auto-selected). Do NOT use magic token. - text: omit or use
"". Do NOT use"*"(passed literally into query).
Query Reference Syntax
| Variable Config | Query Pattern |
|---|---|
Single-select (multiple: false) | field == $Variable |
Multi-select (multiple: true) | in(field, array($Variable)) |
Modifiers
| Modifier | Use for | Example |
|---|---|---|
| default | String equality, multi-select | field == $Var, in(field, array($Var)) |
:noquote | Numeric/duration parameters | limit $N:noquote, bin(timestamp, $Bin:noquote) |
:backtick | Field name in by:{} or sort | by: {$GroupBy:backtick} |
:triplequote | String constants in matchesPhrase(), contains() | matchesPhrase(content, $Search:triplequote) |
Do not double-wrap: :backtick already adds backticks. Write $GroupBy:backtick, never ` $GroupBy:backtick `.
For durations: duration(toLong($Minutes:noquote), unit:"m").
Variable Dependencies
Variables can reference other variables. Dependent variables recalculate when dependencies change. Circular dependencies are not allowed.
[
{ "key": "Cluster", "type": "query",
"input": "smartscapeNodes K8S_CLUSTER | fields name" },
{ "key": "Namespace", "type": "query",
"input": "smartscapeNodes K8S_NAMESPACE | filter belongs_to == $Cluster | fields name" }
]Version
Use version: 2 for new dashboards (supports fetch, expand, summarize). version: 1 is legacy.
Limitations
| Limitation | Workaround |
|---|---|
| Duration types | duration() with conversion: bin(timestamp, duration(toLong($res:noquote), unit:"m")) |
| Type mismatches | DQL conversion: filter amount == toString($amount) |
| URL size limit | Keep variable values under 30 KB total |
| Explore tiles | Multi-select not supported; use single-select with = |
Related skills
How it compares
Choose dt-app-dashboards when you need native Dynatrace DQL dashboard JSON for AI services rather than Grafana panel provisioning skills.
FAQ
What does dt-app-dashboards do?
Work with Dynatrace dashboards - create, modify, query, and analyze dashboard JSON including tiles, layouts, DQL queries, variables, and visualizations.
When should I use dt-app-dashboards?
User asks about dt app dashboards or related SKILL.md workflows.
Is dt-app-dashboards safe to install?
Review the Security Audits panel on this page before installing in production.