Documentation Index
Fetch the complete documentation index at: https://mintlify.com/wazuh/wazuh-dashboard-plugins/llms.txt
Use this file to discover all available pages before exploring further.
The Wazuh Dashboard provides a flexible framework for creating custom dashboards that visualize security data according to your specific monitoring requirements. Custom dashboards enable you to aggregate metrics, charts, and visualizations to provide tailored views of your security posture.
Overview
Custom dashboards in Wazuh Dashboard are composed of panels that display visualizations, each querying security event data from the Wazuh indices. The dashboard framework supports:
- Dynamic panel layouts with customizable grid positioning
- Multiple visualization types including line charts, pie charts, histograms, and area charts
- Real-time data queries using the OpenSearch query language
- Interactive filtering and time range selection
- Agent-specific views for pinned agent monitoring
Dashboard architecture
Custom dashboards are built using three core components:
Dashboard configuration
The DashboardConfig class defines the dashboard metadata and orchestrates panel generation:
export class CustomDashboardConfig extends DashboardConfig {
constructor(indexPatternId: string) {
super(
indexPatternId,
new CustomDashboardLayoutDefinition(indexPatternId)
);
}
protected override getId(): string {
return 'custom-security-dashboard-tab';
}
protected override getTitle(): string {
return 'Custom Security Dashboard';
}
protected override getDescription(): string {
return 'Custom security metrics and visualizations';
}
}
Reference: plugins/main/common/dashboards/lib/dashboard-config-service.ts:77
Layout definition
The DashboardLayoutDefinition class specifies the grid layout and visualization placement:
export class CustomDashboardLayoutDefinition extends DashboardLayoutDefinition {
constructor(indexPatternId: string) {
super();
this.setGridVisualizationPairs(
{
gridData: {
w: 36, // Width (48 units total)
h: 12, // Height
x: 0, // X position
y: 0, // Y position
},
savedVis: getVisStateAlertsTimeline(indexPatternId),
},
{
gridData: {
w: 12,
h: 12,
x: 36,
y: 0,
},
savedVis: getVisStateTopAlertTypes(indexPatternId),
}
);
}
}
Reference: plugins/main/common/dashboards/dashboard-definitions/overview/mitre/overview/dashboard.ts:13
Visualization definitions
Visualization definitions specify the chart type, data aggregations, and query filters:
const getVisStateAlertsTimeline = (indexPatternId: string) => {
return {
id: 'Custom-Alerts-Timeline',
title: 'Security alerts over time',
type: 'line',
params: {
type: 'line',
addTooltip: true,
addLegend: true,
legendPosition: 'right',
categoryAxes: [
{
id: 'CategoryAxis-1',
type: 'category',
position: 'bottom',
show: true,
labels: { show: true, filter: true },
},
],
valueAxes: [
{
id: 'ValueAxis-1',
name: 'LeftAxis-1',
type: 'value',
position: 'left',
title: { text: 'Count' },
},
],
},
data: {
searchSource: {
query: {
language: 'kuery',
query: '',
},
filter: [],
index: indexPatternId,
},
aggs: [
{
id: '1',
enabled: true,
type: 'count',
schema: 'metric',
params: {},
},
{
id: '2',
enabled: true,
type: 'date_histogram',
schema: 'segment',
params: {
field: 'timestamp',
timeRange: { from: 'now-7d', to: 'now' },
interval: 'auto',
},
},
],
},
};
};
Reference: plugins/main/public/components/overview/mitre/dashboard/dashboard-panels.ts:4
Creating a custom dashboard
Step 1: Define visualization states
Create visualization configuration functions for each panel:
// File: custom-dashboard-panels.ts
const getVisStateSecurityEvents = (indexPatternId: string) => {
return {
id: 'Custom-Security-Events',
title: 'Security events by severity',
type: 'pie',
params: {
type: 'pie',
addTooltip: true,
addLegend: true,
legendPosition: 'right',
isDonut: true,
},
data: {
searchSource: {
query: { language: 'kuery', query: '' },
filter: [],
index: indexPatternId,
},
aggs: [
{
id: '1',
type: 'count',
schema: 'metric',
},
{
id: '2',
type: 'terms',
schema: 'segment',
params: {
field: 'rule.level',
orderBy: '1',
order: 'desc',
size: 10,
},
},
],
},
};
};
Step 2: Create layout definition
Define the dashboard grid layout:
// File: custom-dashboard-layout.ts
import { DashboardLayoutDefinition } from '../lib/dashboard-config-service';
import { getVisStateSecurityEvents } from './custom-dashboard-panels';
export class CustomDashboardLayoutDefinition extends DashboardLayoutDefinition {
constructor(indexPatternId: string) {
super();
this.setGridVisualizationPairs(
{
gridData: { w: 24, h: 14, x: 0, y: 0 },
savedVis: getVisStateSecurityEvents(indexPatternId),
}
// Add additional panels here
);
}
}
Step 3: Create dashboard configuration
Implement the dashboard configuration class:
// File: custom-dashboard-config.ts
import { DashboardConfig } from '../lib/dashboard-config-service';
import { CustomDashboardLayoutDefinition } from './custom-dashboard-layout';
export class CustomDashboardConfig extends DashboardConfig {
constructor(indexPatternId: string) {
super(
indexPatternId,
new CustomDashboardLayoutDefinition(indexPatternId)
);
}
protected override getId(): string {
return 'custom-security-dashboard';
}
protected override getTitle(): string {
return 'Custom Security Dashboard';
}
protected override getDescription(): string {
return 'Customized security monitoring dashboard';
}
}
Step 4: Register the dashboard component
Create the React component using the createDashboard helper:
// File: dashboard.tsx
import { createDashboard } from '../../../common/dashboards';
import { DashboardDataSource } from '../data-source';
import { DataSourceRepository } from '../repository';
export const CustomSecurityDashboard = createDashboard({
DataSource: DashboardDataSource,
DataSourceRepositoryCreator: DataSourceRepository,
getDashboardPanels: [
{
dashboardId: 'custom-security-dashboard',
className: 'custom-dashboard-container',
},
],
});
Reference: plugins/main/public/components/common/dashboards/dashboard.tsx:134
Visualization types
Line chart
Temporal data visualization with trend analysis:
type: 'line'
params: {
seriesParams: [{
type: 'line',
mode: 'normal',
drawLinesBetweenPoints: true,
showCircles: true,
lineWidth: 2,
}],
}
Pie chart
Proportional distribution of categorical data:
type: 'pie'
params: {
isDonut: true,
labels: { show: false, values: true },
}
Histogram
Bar chart for categorical comparisons:
type: 'histogram'
params: {
seriesParams: [{
type: 'histogram',
mode: 'stacked',
}],
}
Area chart
Stacked temporal visualizations:
type: 'area'
params: {
seriesParams: [{
type: 'histogram',
mode: 'normal',
interpolate: 'linear',
}],
}
Reference: plugins/main/public/components/overview/mitre/dashboard/dashboard-panels.ts:163
Advanced customization
Adding custom filters
Implement managed filters for dynamic query modification:
export const CustomDashboard = createDashboard({
DataSource: DashboardDataSource,
DataSourceRepositoryCreator: DataSourceRepository,
managedFilters: {
severity: {
field: 'rule.level',
label: 'Severity level',
options: [
{ value: '>=12', label: 'High' },
{ value: '>=7', label: 'Medium' },
{ value: '<7', label: 'Low' },
],
},
},
getDashboardPanels: [{
dashboardId: 'custom-dashboard-id',
}],
});
Agent-specific dashboards
Create dashboards that display data for a specific agent:
getDashboardPanels: [
{
dashboardId: 'custom-overview-dashboard',
agentDashboardId: 'custom-agent-dashboard',
},
]
The framework automatically switches between overview and agent views based on context.
Custom aggregations
Implement complex data aggregations:
aggs: [
{
id: '1',
type: 'count',
schema: 'metric',
},
{
id: '2',
type: 'terms',
schema: 'group',
params: {
field: 'rule.mitre.technique',
orderBy: '1',
order: 'desc',
size: 5,
},
},
{
id: '3',
type: 'terms',
schema: 'segment',
params: {
field: 'rule.mitre.tactic',
orderBy: '1',
order: 'desc',
size: 5,
},
},
]
Reference: plugins/main/public/components/overview/mitre/dashboard/dashboard-panels.ts:349
Time range configuration
Configure default time ranges for dashboard queries:
params: {
field: 'timestamp',
timeRange: { from: 'now-30d', to: 'now' },
interval: 'auto',
}
Dashboard panel service
The DashboardPanelBuilderService automatically generates panel configurations from layout definitions:
class DashboardPanelBuilderService {
getDashboardPanels(): DashboardByRendererPanels {
// Iterates through grid visualization pairs
// Assigns sequential panel IDs
// Returns fully configured panel structure
}
}
Reference: plugins/main/common/dashboards/lib/dashboard-config-service.ts:8
Query language
Dashboards support both Kuery and Lucene query languages:
Kuery syntax
searchSource: {
query: {
language: 'kuery',
query: 'rule.level >= 12 and rule.groups: "malware"',
},
}
Lucene syntax
searchSource: {
query: {
language: 'lucene',
query: 'rule.level:[12 TO *] AND rule.groups:"authentication_failed"',
},
}
Best practices
- Limit the number of panels per dashboard to maintain responsiveness
- Use appropriate aggregation sizes to balance detail and performance
- Configure reasonable default time ranges to avoid querying excessive data
- Implement pagination for large result sets
Layout design
- The grid system uses 48 horizontal units
- Standard panel heights range from 12 to 16 units
- Position related visualizations adjacent to each other
- Place high-priority metrics in the top-left quadrant
Data accuracy
- Specify appropriate time fields for temporal aggregations
- Use correct field types in aggregation parameters
- Test queries independently before integrating into dashboards
- Validate index pattern availability
Maintainability
- Organize visualization definitions in separate files
- Use descriptive IDs and titles for panels
- Document custom aggregation logic
- Implement type safety with TypeScript interfaces
Troubleshooting
Dashboard not rendering
- Verify the index pattern ID is correct and accessible
- Check that all required fields exist in the index
- Confirm the dashboard ID is unique and properly registered
- Review browser console for configuration errors
Visualizations showing no data
- Validate the time range includes relevant events
- Verify aggregation field names match index schema
- Check query syntax for errors
- Confirm data exists for the specified filters
Layout issues
- Ensure grid coordinates do not overlap
- Verify total width does not exceed 48 units
- Check that panel heights provide adequate space for content
- Test layout on different screen resolutions
- MITRE ATT&CK framework mapping for reference dashboard implementations
- Dashboard renderer service for understanding the rendering pipeline
- Data source configuration for custom data fetching logic