Splunk Dashboard Studio — Skill Reference
This skill enables Claude to generate complete, valid Splunk Dashboard Studio dashboard definitions (JSON). All output is the JSON definition that goes inside the <definition><![CDATA[ ... ]]></definition> block of a Dashboard Studio .xml file.
1. Dashboard Definition Structure
A Dashboard Studio dashboard definition is a JSON object with these top-level keys:
{
"title": "My Dashboard",
"description": "Optional description",
"dataSources": {},
"visualizations": {},
"inputs": {},
"defaults": {},
"layout": {}
}
1.1 XML Envelope (for file deployment)
The JSON definition is wrapped in an XML envelope when saved as a .xml file:
<dashboard version="2" theme="dark">
<label>My Dashboard</label>
<description>Optional description</description>
<definition><![CDATA[
{ ... JSON definition ... }
]]></definition>
</dashboard>
- •
version="2"marks it as Dashboard Studio (not classic Simple XML). - •
themecan be"light"or"dark". - •The JSON definition goes inside
<![CDATA[ ... ]]>.
2. Data Sources (dataSources)
2.1 ds.search — SPL Search
IMPORTANT: Every
ds.searchdata source MUST include anameproperty. This is the human-readable name shown in the Dashboard Studio UI. Without it, searches may not display correctly in the visual editor. Use descriptive names like"Failed Logins by Source"rather than generic ones like"Search_1".
"dataSources": {
"ds_search1": {
"type": "ds.search",
"name": "Events by Sourcetype",
"options": {
"query": "index=_internal | stats count by sourcetype",
"queryParameters": {
"earliest": "$global_time.earliest$",
"latest": "$global_time.latest$"
}
}
}
}
Key options for ds.search:
| Option | Type | Required | Description |
|---|---|---|---|
name | string | YES | Human-readable name shown in UI |
query | string | YES | SPL query (use \n for newlines) |
queryParameters.earliest | string | No | Earliest time (absolute or token) |
queryParameters.latest | string | No | Latest time (absolute or token) |
refresh | string | No | Auto-refresh interval, e.g. "10s", "1m" |
refreshType | string | No | "delay" (after completion) or "interval" (fixed) |
2.2 ds.chain — Chain Search (Post-process)
Chain searches reference a parent data source and apply additional SPL. They also require a name:
"ds_chain1": {
"type": "ds.chain",
"name": "High Count Filter",
"options": {
"extend": "ds_search1",
"query": "| where count > 100"
}
}
2.3 ds.test — Mock Data (for prototyping)
"ds_test1": {
"type": "ds.test",
"name": "Mock Category Data",
"options": {
"data": {
"fields": [
{"name": "category", "type": "string"},
{"name": "count", "type": "number"}
],
"columns": [
["web", "api", "db"],
[120, 85, 45]
]
}
}
}
2.4 ds.savedSearch — Saved/Report Search
"ds_saved1": {
"type": "ds.savedSearch",
"name": "My Saved Search",
"options": {
"ref": "my_saved_search_name"
}
}
2.5 Base Search + Chain Pattern
A common pattern is one base search feeding multiple chain searches:
"dataSources": {
"ds_base": {
"type": "ds.search",
"name": "Firewall Base Search",
"options": {
"query": "index=firewall | stats count by src_ip, action, dest_port"
}
},
"ds_allowed": {
"type": "ds.chain",
"name": "Allowed Traffic Top 10",
"options": {
"extend": "ds_base",
"query": "| where action=\"allowed\" | sort -count | head 10"
}
},
"ds_blocked": {
"type": "ds.chain",
"name": "Blocked Traffic Top 10",
"options": {
"extend": "ds_base",
"query": "| where action=\"blocked\" | sort -count | head 10"
}
}
}
3. Visualization Types (visualizations)
Every visualization follows this structure:
"viz_uniqueId": {
"type": "splunk.<viztype>",
"title": "Optional Title",
"description": "Optional description",
"dataSources": {
"primary": "ds_search1"
},
"options": {},
"context": {},
"showProgressBar": false,
"showLastUpdated": false,
"eventHandlers": []
}
3.1 Complete Visualization Type Reference
Charts
| Type | Description | Key Options |
|---|---|---|
splunk.line | Line chart (time series) | seriesColors, legendDisplay, yAxisTitleText, xAxisTitleText, stackMode, nullValueDisplay, lineDashStyle, markerDisplay |
splunk.area | Area chart | Same as line + areaOpacity, showLines |
splunk.column | Vertical bar chart | stackMode (stacked, stacked100), seriesColors, legendDisplay, dataValuesDisplay, columnSpacing, columnGrouping |
splunk.bar | Horizontal bar chart | Same as column + barSpacing, legendReversed |
splunk.pie | Pie chart | labelDisplay (valuesAndPercentage, values, percentage, off), showDonutHole |
splunk.scatter | Scatter plot | seriesColors, legendDisplay, markerDisplay |
splunk.bubble | Bubble chart | categoryField, sizeField, bubbleSizeMax, bubbleSizeMin, bubbleSizeMethod (area, diameter) |
splunk.punchcard | Punchcard chart | seriesColors |
splunk.parallelcoordinates | Parallel coordinates | seriesColors, legendDisplay, backgroundColor, lineOpacity |
splunk.timeline | Timeline (event lanes) | category, seriesColors, legendDisplay, backgroundColor, dataColors |
Single Value
| Type | Description | Key Options |
|---|---|---|
splunk.singlevalue | Single value with sparkline | majorValue, trendValue, sparklineValues, sparklineDisplay, trendDisplay, unit, unitPosition, majorColor, trendColor, backgroundColor, sparklineStrokeColor |
splunk.singlevalueicon | Single value with icon | Same as singlevalue + icon, iconColor, iconPosition |
splunk.singlevalueradial | Radial gauge single value | Same as singlevalue + radialStrokeColor, radialBackgroundColor, gaugeRanges |
Tables & Events
| Type | Description | Key Options |
|---|---|---|
splunk.table | Data table | columnFormat, tableFormat, count, dataOverlayMode, showRowNumbers, showInternalFields |
splunk.events | Events viewer | type (list, table, raw), fields, rowNumbers |
Maps
| Type | Description | Key Options |
|---|---|---|
splunk.map | Cluster map (marker/bubble) | center, zoom, layers (array of layer objects), baseLayerTileServer, baseLayerTileServerType, scaleUnit |
splunk.choropleth.map | Geographic choropleth map | source (geo://default/world, geo://default/us), projection (mercator, equirectangular), fillColor, strokeColor |
splunk.choropleth.svg | SVG choropleth | svg, areaIds, areaValues, areaColors |
Gauges
| Type | Description | Key Options |
|---|---|---|
splunk.fillergauge | Filler/progress gauge | gaugeColor, backgroundColor, orientation (vertical, horizontal), labelDisplay, valueDisplay, majorTickInterval |
splunk.markergauge | Marker gauge | gaugeRanges (array: [{"from":0,"to":50,"value":"#green"},...]), orientation, labelDisplay, valueDisplay |
Diagram & Flow
| Type | Description | Key Options |
|---|---|---|
splunk.sankey | Sankey diagram (flow) | linkColorMode, linkColor |
splunk.linkgraph | Link/node graph | fieldOrder, nodeColor, nodeHighlightColor, nodeWidth, nodeHeight, nodeSpacingX, nodeSpacingY, linkColor, showNodeCounts, showValueCounts |
Layout & Decoration
| Type | Description | Key Options |
|---|---|---|
splunk.markdown | Markdown text block (NOTE: does NOT support pipe-based markdown tables) | markdown, fontColor, fontSize (extraSmall, small, default, large, extraLarge), customFontSize, fontFamily, backgroundColor, rotation |
splunk.image | Image display | src, preserveAspectRatio |
splunk.rectangle | Rectangle shape | fillColor, fillOpacity, strokeColor, strokeWidth, strokeDashStyle, strokeOpacity, cornerRadius |
splunk.ellipse | Ellipse shape | fillColor, fillOpacity, strokeColor, strokeWidth, strokeDashStyle, strokeOpacity |
splunk.line (shape) | Line shape | strokeColor, strokeWidth, strokeDasharray, strokeOpacity, toArrow, fromArrow |
splunk.icon | Icon element | icon, color |
Trellis
Any chart type can be rendered as a trellis layout by adding the trellis wrapper options.
3.2 Common Chart Options
These options apply to most chart types (line, area, column, bar, scatter, bubble):
"options": {
"backgroundColor": "#1a1a2e",
"seriesColors": ["#00d2ff", "#ff6384", "#36a2eb", "#ffce56"],
"seriesColorsByField": {"allowed": "#00ff00", "blocked": "#ff0000"},
"legendDisplay": "right",
"legendMode": "seriesCompare",
"legendTruncation": "ellipsisEnd",
"xAxisTitleText": "Time",
"yAxisTitleText": "Count",
"xAxisTitleVisibility": "show",
"yAxisTitleVisibility": "show",
"xAxisLabelRotation": -45,
"xAxisLabelVisibility": "show",
"yAxisLabelVisibility": "show",
"yAxisScale": "linear",
"yAxisAbbreviation": "auto",
"stackMode": "stacked",
"nullValueDisplay": "connect",
"dataValuesDisplay": "all",
"resultLimit": 50000,
"showSplitSeries": false,
"showIndependentYRanges": false
}
stackMode values: "auto" (default) | "stacked" | "stacked100"
nullValueDisplay values: "gaps" (default) | "zero" | "connect"
legendDisplay values: "right" (default) | "left" | "top" | "bottom" | "off"
legendMode values: "standard" (default) | "seriesCompare" (useful for comparing series)
Line-Specific Options
| Option | Type | Default | Description |
|---|---|---|---|
lineDashStyle | string | "solid" | Dash style: "solid", "dash", "dot", "shortDash", "longDash", "dashDot", "longDashDot", "longDashDotDot" |
lineDashStylesByField | object | — | Per-field dash styles, e.g. {"count": "dash", "avg": "dot"} |
lineWidth | number | 2 | Line width in pixels |
markerDisplay | string | "off" | Data point markers: "off", "filled", "outlined" |
additionalTooltipFields | string[] | [] | Extra fields shown in tooltips on hover |
Area-Specific Options
| Option | Type | Default | Description |
|---|---|---|---|
areaOpacity | number | 0.75 | Area fill opacity (0–1) |
showLines | boolean | true | Show lines on top of areas |
Annotation Options (Line, Area, Column)
| Option | Type | Description |
|---|---|---|
annotationX | string/number | Data source field for annotation x-position |
annotationLabel | string | Label array, e.g. ["Event A", "Event B"] |
annotationColor | string | Color array, e.g. ["#FF0000", "#00FF00"] |
Y2-Axis & Overlay Options (Line, Area, Column, Bar)
| Option | Type | Description |
|---|---|---|
y2 | string | Data source for y2-axis |
y2Fields | array/string | Fields mapped to y2-axis |
y2AxisTitleText | string | Title for y2-axis |
overlayFields | array/string | Fields shown as chart overlays |
showOverlayY2Axis | boolean | Map overlay fields to y2-axis |
Default Color Palette (20 colors)
#7B56DB, #009CEB, #00CDAF, #DD9900, #FF677B, #CB2196, #813193, #0051B5, #008C80, #99B100, #FFA476, #FF6ACE, #AE8CFF, #00689D, #00490A, #465D00, #9D6300, #F6540B, #FF969E, #E47BFE
Parallel Coordinates Options (splunk.parallelcoordinates)
Visualizes multidimensional patterns across vertical axes. Lines representing events connect dimensions.
| Option | Type | Default | Description |
|---|---|---|---|
backgroundColor | string | theme default | Background color |
seriesColors | string[] | default palette | Colors for lines |
lineOpacity | number | — | Opacity of lines (0–1) |
legendDisplay | string | "right" | Legend position |
Data format: Use | stats count by <dim1>, <dim2>, ... <dimN> | fields - count. Keep under 15 dimensions.
"viz_parallel": {
"type": "splunk.parallelcoordinates",
"title": "Nutrient Comparison",
"dataSources": { "primary": "ds_nutrients" },
"options": {}
}
Timeline Options (splunk.timeline)
Shows events and activity intervals on horizontal lanes. Each resource gets its own lane.
| Option | Type | Default | Description |
|---|---|---|---|
category | string | — | DOS expression for category field, e.g. "> primary | seriesByName('attack_type')" |
seriesColors | string[] | default palette | Colors for event categories |
legendDisplay | string | "right" | Legend position |
backgroundColor | string | "transparent" | Background color |
dataColors | string | — | Data-driven colors (use with context.dataColorConfig ranges) |
Data format: | table _time <resource_field> [<color_field>] [<duration_field>]
"viz_timeline": {
"type": "splunk.timeline",
"title": "Attack Types Over Time",
"dataSources": { "primary": "ds_attacks" },
"options": {
"category": "> primary | seriesByName('attack_type')",
"legendDisplay": "right",
"backgroundColor": "transparent",
"seriesColors": ["#7B56DB", "#009CEB", "#00CDAF", "#DD9900", "#FF677B"]
},
"context": {
"dataColorConfig": [
{"to": 20, "value": "#D41F1F"},
{"from": 20, "to": 50, "value": "#F4DF7A"},
{"from": 50, "value": "#669922"}
]
}
}
3.3 Single Value — Full Example
"viz_singlevalue": {
"type": "splunk.singlevalue",
"title": "Total Events",
"dataSources": {
"primary": "ds_count"
},
"options": {
"majorValue": "> sparklineValues | lastPoint()",
"trendValue": "> sparklineValues | delta(-2)",
"sparklineValues": "> primary | seriesByName('count')",
"sparklineDisplay": "below",
"trendDisplay": "percent",
"unit": "events",
"unitPosition": "after",
"majorColor": "> majorValue | rangeValue(majorColorConfig)",
"trendColor": "> trendValue | rangeValue(trendColorConfig)",
"backgroundColor": "transparent",
"showSparklineAreaGraph": true,
"sparklineStrokeColor": "> trendColor"
},
"context": {
"majorColorConfig": [
{"value": "#DC4E41", "to": 100},
{"value": "#F8BE34", "from": 100, "to": 500},
{"value": "#53A051", "from": 500}
],
"trendColorConfig": [
{"value": "#DC4E41", "to": 0},
{"value": "#53A051", "from": 0}
]
}
}
3.4 Table — Column Formatting Example
WARNING: Do NOT use
matchValue()— causese.map is not a function. UserangeValue()with a numeric rank instead. For whole-row coloring, usetableFormat(notcolumnFormat). Prefix the rank field with_(e.g.,_color_rank) and set"showInternalFields": falseto hide it from the table.
Whole-row coloring (via tableFormat + numeric rank):
SPL must include an underscore-prefixed numeric field: | eval _color_rank=case(severity=="critical",1, severity=="high",2, severity=="medium",3, severity=="low",4, 1=1,5)
"viz_table": {
"type": "splunk.table",
"title": "Security Events",
"dataSources": {
"primary": "ds_events"
},
"options": {
"count": 20,
"showRowNumbers": true,
"showInternalFields": false,
"tableFormat": {
"rowBackgroundColors": "> table | seriesByName(\"_color_rank\") | rangeValue(severityRowColors)"
},
"columnFormat": {
"count": {
"rowBackgroundColors": "> table | seriesByName(\"count\") | rangeValue(countColors)",
"data": "> table | seriesByName(\"count\") | formatByType(countFormat)"
},
"sparkline": {
"sparklineDisplay": "area",
"sparklineColors": "> table | seriesByName('sparkline') | pick(sparklineColor)",
"sparklineAreaColors": "> sparklineColors"
}
}
},
"context": {
"severityRowColors": [
{"from": 0, "to": 1.5, "value": "#DC4E41"},
{"from": 1.5, "to": 2.5, "value": "#F1813F"},
{"from": 2.5, "to": 3.5, "value": "#F8BE34"},
{"from": 3.5, "to": 4.5, "value": "#53A051"},
{"from": 4.5, "to": 6, "value": "#5794DE"}
],
"countColors": [
{"value": "#53A051", "to": 50},
{"value": "#F8BE34", "from": 50, "to": 200},
{"value": "#DC4E41", "from": 200}
],
"countFormat": {
"number": {"thousandSeparated": true, "precision": 0}
},
"sparklineColor": ["#7B56DB"]
}
}
3.5 Map — Marker & Bubble Layers
"viz_map": {
"type": "splunk.map",
"title": "Global Attack Origins",
"dataSources": {
"primary": "ds_geo"
},
"options": {
"center": [20, 0],
"zoom": 2,
"layers": [
{
"type": "marker",
"latitude": "> primary | seriesByName(\"lat\")",
"longitude": "> primary | seriesByName(\"lon\")",
"description": "> primary | seriesByName(\"src_ip\")",
"dataColors": "> primary | seriesByName(\"count\") | rangeValue(markerColors)"
}
]
},
"context": {
"markerColors": [
{"value": "#53A051", "to": 100},
{"value": "#F8BE34", "from": 100, "to": 1000},
{"value": "#DC4E41", "from": 1000}
]
}
}
For bubble maps, the SPL uses geostats:
{
"type": "bubble",
"latitude": "> primary | seriesByName(\"latitude\")",
"longitude": "> primary | seriesByName(\"longitude\")"
}
3.6 Sankey Diagram
"viz_sankey": {
"type": "splunk.sankey",
"title": "Network Traffic Flow",
"dataSources": {
"primary": "ds_flow"
},
"options": {
"linkColorMode": "source"
}
}
SPL must produce exactly 3 columns: source, target, value:
| stats sum(bytes) as value by src_zone, dest_zone | rename src_zone as source, dest_zone as target
3.7 Choropleth SVG
"viz_choropleth": {
"type": "splunk.choropleth.svg",
"title": "Regional Activity",
"dataSources": {
"primary": "ds_regions"
},
"options": {
"svg": "<svg>...</svg>",
"areaIds": "> primary | seriesByType('string')",
"areaValues": "> primary | seriesByType('number')"
}
}
3.8 Choropleth Map (Geographic)
"viz_world_map": {
"type": "splunk.choropleth.map",
"title": "Events by Country",
"dataSources": {
"primary": "ds_geo"
},
"options": {
"source": "geo://default/world",
"projection": "mercator",
"fillColor": "#EAEFF2",
"strokeColor": "#689C8D"
}
}
Sources: "geo://default/world" or "geo://default/us". Projections: "mercator" or "equirectangular".
---
## 4. Inputs (`inputs`)
### 4.1 Available Input Types
| Type | Description | Key Options |
|------|-------------|-------------|
| `input.timerange` | Time range picker | `token`, `defaultValue` |
| `input.dropdown` | Dropdown selector | `token`, `items` (static or DOS-generated), `defaultValue` |
| `input.multiselect` | Multi-select | `token`, `items`, `defaultValue` |
| `input.text` | Text input | `token`, `defaultValue` |
| `input.checkbox` | Checkbox group | `token`, `items` |
| `input.link` | Link/tab selector | `token`, `items` |
### 4.2 Global Time Range (always include)
```json
"inputs": {
"input_global_trp": {
"type": "input.timerange",
"title": "Global Time Range",
"options": {
"token": "global_time",
"defaultValue": "-24h@h,now"
}
}
}
4.3 Dropdown — Static Items
"input_severity": {
"type": "input.dropdown",
"title": "Severity",
"options": {
"token": "severity_filter",
"defaultValue": "*",
"items": [
{"label": "All", "value": "*"},
{"label": "Critical", "value": "critical"},
{"label": "High", "value": "high"},
{"label": "Medium", "value": "medium"},
{"label": "Low", "value": "low"}
]
}
}
4.4 Dropdown — Dynamic (search-populated)
"input_host": {
"type": "input.dropdown",
"title": "Host",
"options": {
"token": "host_filter",
"defaultValue": "*",
"items": "> frame(label, value) | prepend(prependItems)",
"staticItems": "> prependItems"
},
"dataSources": {
"primary": "ds_hosts"
},
"context": {
"prependItems": [
{"label": "All", "value": "*"}
]
}
}
4.5 Multiselect Input
"input_status": {
"type": "input.multiselect",
"title": "Status Codes",
"options": {
"token": "status",
"items": "> frame(label, value) | prepend(prependItems)",
"defaultValue": "*"
},
"dataSources": {
"primary": "ds_statuses"
},
"context": {
"prependItems": [
{"label": "All", "value": "*"}
]
}
}
4.6 Text Input
"input_search_text": {
"type": "input.text",
"title": "Search Filter",
"options": {
"token": "search_text",
"defaultValue": "*"
}
}
5. Defaults (defaults)
The defaults section sets global defaults for data sources and tokens:
"defaults": {
"dataSources": {
"ds.search": {
"options": {
"queryParameters": {
"earliest": "$global_time.earliest$",
"latest": "$global_time.latest$"
}
}
}
},
"tokens": {
"default": {
"method": {
"value": "POST"
}
}
},
"visualizations": {
"splunk.table": {
"options": {
"count": 20
}
}
}
}
This applies time range tokens to ALL ds.search data sources globally, avoiding repetition.
6. Layout (layout)
6.1 Absolute Layout (pixel-perfect)
CRITICAL: Absolute layout REQUIRES the
layoutDefinitions+tabswrapper. You CANNOT use"type": "absolute"directly in the top-levellayoutobject — it causes a "CData section not finished" XML parse error in Splunk. Even single-view dashboards need at least one tab.
"layout": {
"globalInputs": ["input_global_trp"],
"layoutDefinitions": {
"layout_main": {
"type": "absolute",
"options": {
"width": 1920,
"height": 5500,
"display": "auto-scale",
"backgroundColor": "#0B0C10"
},
"structure": [
{
"item": "viz_bg_header",
"type": "block",
"position": {"x": 0, "y": 0, "w": 1920, "h": 300}
},
{
"item": "viz_header",
"type": "block",
"position": {"x": 40, "y": 20, "w": 1840, "h": 260}
}
]
}
},
"options": {},
"tabs": {
"items": [
{"label": "Main", "layoutId": "layout_main"}
]
}
}
Absolute layout options: width (default 1140), height (default 960), display ("auto-scale" | "actual-size" | "fit-to-width"), backgroundColor (hex), backgroundImage (src, sizeType: auto/contain/cover). These are ONLY available in absolute layout, not grid.
z-ordering: Items earlier in the structure array render behind items later. Use splunk.rectangle for overlapping background panels (absolute layout only).
6.2 Grid Layout (responsive, auto-sized)
IMPORTANT: Every visualization defined in the
visualizationssection MUST have a corresponding entry inlayout.structure. If a visualization is missing fromstructure, it will not render. This is the most common cause of panels not appearing — especially for multi-row dashboards where it's easy to forget a panel.
CRITICAL — NO
optionsblock for grid layout. Grid layout definitions must have ONLYtypeandstructure. Do NOT addwidth,height,backgroundColor,display, orgutterSize— these are absolute-layout-only properties. Adding anoptionsblock to a grid layout causes only the first row of panels to render.
"layout": {
"type": "grid",
"globalInputs": ["input_global_trp"],
"structure": [
{"item": "viz_chart1", "type": "block", "position": {"x": 0, "y": 0, "w": 600, "h": 300}},
{"item": "viz_chart2", "type": "block", "position": {"x": 600, "y": 0, "w": 600, "h": 300}},
{"item": "viz_chart3", "type": "block", "position": {"x": 0, "y": 300, "w": 1200, "h": 400}}
]
}
Structure rules:
- •Every
viz_*panel needs a{"item": "viz_xxx", "type": "block", "position": {...}}entry - •Grid width is always 1200. Common splits: 2 columns = 600+600, 3 columns = 400+400+400, 4 columns = 300+300+300+300
- •Y-values must be cumulative — each row's y = previous row's y + previous row's h (no gaps). Example: row 1 at y=0 h=300, row 2 must start at y=300, not y=310
- •Grid is always auto-sized vertically — do NOT set a total height
6.3 Tabbed Layout
"layout": {
"globalInputs": ["input_global_trp"],
"tabs": {
"items": [
{"layoutId": "layout_overview", "label": "Overview"},
{"layoutId": "layout_details", "label": "Details"},
{"layoutId": "layout_threats", "label": "Threats"}
],
"options": {
"barPosition": "top",
"showTabBar": true
}
},
"layoutDefinitions": {
"layout_overview": {
"type": "grid",
"structure": [
{"item": "viz_1", "type": "block", "position": {"x": 0, "y": 0, "w": 1200, "h": 300}}
]
},
"layout_details": {
"type": "grid",
"structure": [
{"item": "viz_2", "type": "block", "position": {"x": 0, "y": 0, "w": 1200, "h": 400}}
]
}
}
}
6.4 Line Connections (absolute layout only)
{
"item": "viz_line1",
"type": "line",
"position": {
"from": {"item": "viz_box1", "port": "s"},
"to": {"item": "viz_box2", "port": "n"}
}
}
Ports: "n" (north), "s" (south), "e" (east), "w" (west)
7. Dynamic Options Syntax (DOS)
DOS is the expression language used in Dashboard Studio to dynamically configure visualization options based on data.
7.1 DOS Structure
"> <data_source> | <selector> | <formatter>"
Every DOS expression starts with > and uses pipes | to chain operations. The data source can be primary, table, or a reference to another option.
7.2 Selector Functions (pick data)
| Selector | Level | Description |
|---|---|---|
seriesByName("field") | DataFrame → DataSeries | Select a column by name |
seriesByIndex(n) | DataFrame → DataSeries | Select a column by index |
seriesByPrioritizedTypes("number","string") | DataFrame | Select first column matching type |
firstPoint() | DataSeries → DataPoint | First value in series |
lastPoint() | DataSeries → DataPoint | Last value in series |
pointByIndex(n) | DataSeries → DataPoint | Value at index n |
delta(n) | DataSeries → DataPoint | Difference between last n points |
getField() | DataPoint → string | Get field name |
getType() | DataPoint → string | Get data type |
getValue() | DataPoint → value | Get value |
pick(contextVar) | any | Pick value from context |
frame(label, value) | DataFrame | Create label/value pairs for inputs |
7.3 Formatting Functions (transform data)
| Formatter | Description | Example |
|---|---|---|
rangeValue(config) | Map numeric ranges to values (colors) | rangeValue(colorConfig) |
matchValue(config) | Map exact string matches to values (BROKEN — causes e.map is not a function. Use rangeValue with numeric rank instead.) | — |
formatByType(config) | Format by data type (number, string) | formatByType(numFormat) |
prefix("str") | Add prefix to each value | prefix("$") |
suffix("str") | Add suffix to each value | suffix(" ms") |
prepend(items) | Prepend items to a list | prepend(staticItems) |
multiFormat(config) | Apply different formatters to columns | |
type() | Return data type of each element |
7.4 Context — Configuration Store
The context section of a visualization stores configuration objects used by DOS formatters:
"context": {
"colorConfig": [
{"value": "#DC4E41", "to": 50},
{"value": "#F8BE34", "from": 50, "to": 200},
{"value": "#53A051", "from": 200}
],
"severityRankColors": [
{"from": 0, "to": 1.5, "value": "#DC4E41"},
{"from": 1.5, "to": 2.5, "value": "#F8BE34"},
{"from": 2.5, "to": 4, "value": "#53A051"}
]
}
7.5 Escaping in DOS
- •Strings inside DOS use escaped quotes:
\"field_name\" - •Single quotes also work:
'field_name' - •Backslashes in strings need double escaping:
\\
8. Interactions (Drilldown & Tokens)
8.1 Setting Tokens on Click (drilldown.setToken)
"eventHandlers": [
{
"type": "drilldown.setToken",
"options": {
"tokens": [
{
"token": "selected_host",
"key": "row.host.value"
}
]
}
}
]
Token key syntax:
- •
row.<field>.value— value of clicked field in row - •
row._hidden.value— value of hidden fields (prefixed with_)
8.2 Link to URL
"eventHandlers": [
{
"type": "drilldown.customUrl",
"options": {
"url": "/app/search/target_dashboard?form.host=$selected_host|u$",
"newTab": true
}
}
]
8.3 Link to Dashboard
"eventHandlers": [
{
"type": "drilldown.linkToDashboard",
"options": {
"app": "search",
"dashboard": "detail_view",
"newTab": true,
"tokens": {
"form.src_ip": "$row.src_ip.value$"
}
}
}
]
8.4 Link to Search
"eventHandlers": [
{
"type": "drilldown.linkToSearch",
"options": {
"query": "index=main host=$row.host.value$",
"earliest": "$global_time.earliest$",
"latest": "$global_time.latest$",
"newTab": true
}
}
]
8.5 Conditional Visibility
Visualizations can be shown/hidden based on token values using encoding:
"encoding": {
"drilldown": {
"token": "show_details"
}
}
8.6 Token Filters
Use |u for URL encoding, |n for no encoding, |s for search filter:
$token|u$ — URL encoded $token|n$ — Raw (no encoding) $token|s$ — Search filter safe
9. Standard Patterns & Templates
9.1 Minimal Dashboard Skeleton
{
"title": "Dashboard Title",
"description": "",
"dataSources": {
"ds_search1": {
"type": "ds.search",
"name": "Events by Sourcetype",
"options": {
"query": "index=_internal | stats count by sourcetype"
}
}
},
"visualizations": {
"viz_chart1": {
"type": "splunk.column",
"dataSources": {"primary": "ds_search1"},
"title": "Events by Sourcetype"
}
},
"inputs": {
"input_global_trp": {
"type": "input.timerange",
"title": "Global Time Range",
"options": {
"token": "global_time",
"defaultValue": "-24h@h,now"
}
}
},
"defaults": {
"dataSources": {
"ds.search": {
"options": {
"queryParameters": {
"earliest": "$global_time.earliest$",
"latest": "$global_time.latest$"
}
}
}
}
},
"layout": {
"type": "grid",
"globalInputs": ["input_global_trp"],
"structure": [
{
"item": "viz_chart1",
"type": "block",
"position": {"x": 0, "y": 0, "w": 1200, "h": 400}
}
]
}
}
9.2 Security SOC Dashboard Pattern
A typical SOC overview dashboard includes:
- •Row 1: 3-4 single value KPIs (total events, alerts, critical alerts, avg response time)
- •Row 2: Timeline chart (events over time by severity) + Pie chart (by category)
- •Row 3: Table of recent alerts with severity coloring
- •Inputs: Global time range + severity dropdown + host filter
Layout grid positions for this pattern (width=1200):
| Viz | x | y | w | h |
|---|---|---|---|---|
| SV1 | 0 | 0 | 300 | 120 |
| SV2 | 300 | 0 | 300 | 120 |
| SV3 | 600 | 0 | 300 | 120 |
| SV4 | 900 | 0 | 300 | 120 |
| Timeline | 0 | 120 | 800 | 300 |
| Pie | 800 | 120 | 400 | 300 |
| Table | 0 | 420 | 1200 | 400 |
9.3 Color Conventions (Dark Theme)
| Purpose | Color | Hex |
|---|---|---|
| Critical/High/Error | Red | #DC4E41 |
| Warning/Medium | Orange | #F1813F |
| Caution/Medium | Yellow | #F8BE34 |
| OK/Low/Success | Green | #53A051 |
| Info | Blue | #5794DE |
| Accent 1 | Cyan | #00D2FF |
| Accent 2 | Purple | #7B56DB |
| Background (dark) | Dark blue | #0B0C10 |
| Panel background | Slightly lighter | #171D29 |
| Text on dark | Light gray | #C3CBD4 |
10. Best Practices
- •Always include a global time range input and wire it through
defaults.dataSources.ds.search.options.queryParameters. - •Use base+chain searches when multiple visualizations need variations of the same data — avoids redundant searching.
- •Use
ds.testfor prototyping layouts before wiring real searches. - •Grid layout for quick responsive dashboards; absolute layout for pixel-perfect designs with backgrounds and shapes. When using either layout, ensure every visualization has a matching entry in
layout.structure— missing entries cause panels to silently not render. - •Unique IDs: Data source IDs start with
ds_, visualization IDs withviz_, input IDs withinput_. - •Name all searches: Every
ds.searchandds.chainMUST have a descriptivenameproperty. Use meaningful names like"Failed Logins by Host"instead of"Search_1". - •Validate JSON before deploying — Dashboard Studio provides limited validation.
- •Dark theme (
theme="dark") is preferred for SOC/monitoring dashboards. - •10,000 result limit per visualization — use
| head 10000or appropriate aggregation. - •Escaped quotes in DOS: Use
\"inside DOS strings, e.g.,seriesByName(\"field\"). - •Token syntax: Always
$tokenName$with dollar signs. For time range tokens:$global_time.earliest$and$global_time.latest$. - •Use
seriesColorsByFieldinstead ofseriesColorswhen you need stable per-field colors (e.g.,{"allowed": "#53A051", "blocked": "#DC4E41"}). - •Use
nullValueDisplay: "connect"for time series with gaps to avoid misleading gaps or zeroes. - •Quote rules: Strings and options need quotes. Booleans and numbers do NOT need quotes in JSON options.
- •
splunk.markdowndoes NOT support markdown tables — Pipe-based table syntax (| col1 | col2 |) does not render. Usesplunk.tablewith| makeresultsor static data for tabular content instead. - •Absolute layout REQUIRES
layoutDefinitions+tabs-- Never put"type": "absolute"directly in the top-levellayoutobject. Even single-view absolute dashboards must use thelayoutDefinitionswrapper with at least one tab. - •Avoid problematic Unicode in CDATA JSON -- Splunk's XML parser can break CDATA sections with "CData section not finished" error on certain non-ASCII characters. Emojis are OK (e.g., ☠, 🔍, 🎣, ✅, ⚠, 🛡). Avoid em-dashes (U+2014), arrows (U+2192), middle dots (U+00B7), and similar typographic Unicode -- replace with ASCII:
--,->,|.
11. Common SPL Patterns for Dashboard Studio
# Single value — total count index=main | stats count # Single value with sparkline — timechart index=main | timechart count # Table — top sources index=main | stats count by src_ip, action | sort -count | head 20 # Pie chart — distribution index=main | stats count by category # Line chart — time series with split index=main | timechart span=1h count by severity # Map — geo data index=main | iplocation src_ip | geostats latfield=lat longfield=lon count # Sankey — flow between fields index=main | stats count as value by src_zone, dest_zone | rename src_zone as source, dest_zone as target # Table with sparkline column index=main | stats count, sparkline(count, 1h) as sparkline by host
IMPORTANT — Nested JSON field quoting: When using
eval,where,if, orcasewith dotted field names from JSON sourcetypes (e.g.,properties.status.errorCode,requestParameters.bucketName), you MUST wrap the field in single quotes:
- •✅
| eval status=if('properties.status.errorCode'=0, "Success", "Failed")- •❌
| eval status=if(properties.status.errorCode=0, "Success", "Failed")This applies everywhere dots appear in field names.
statsandtablecommands handle dotted fields without quotes, buteval/where/if/casedo not.
12. Output Checklist
When generating a Dashboard Studio dashboard, verify:
- • Valid JSON (no trailing commas, properly escaped strings)
- • All
ds.searchandds.chaindata sources have a descriptivenameproperty - • All
dataSourcesreferenced by visualizations exist - • All
visualizationsreferenced inlayout.structureexist - • All
inputslisted inlayout.globalInputsexist - •
defaultssection includes time range token binding - • Token names are consistent (
$token$syntax) - • DOS expressions start with
>and use proper escaping - • Layout positions don't overlap (grid) or are intentional (absolute)
- •
contextobjects are defined for all DOSrangeValuereferences (do NOT usematchValue— it is broken) - • Option names match official docs (e.g.,
nullValueDisplaynotnullValueMode,stackModedefault is"auto") - • Booleans/numbers are unquoted; strings/options are quoted in JSON