Questions to build custom dashlets

Is there an official/supported way to create custom dashlet types in CMK 2.5 that actually appear in the Vue dashboard picker? For example via a plugin registration that extends INTERNAL_TO_API_TYPE_NAME or WidgetContent?

Is ABCFigureDashlet still usable for third-party plugins, and if so — does it appear in the picker, or is it also limited to the hardcoded list?

Is there a roadmap entry or documentation for third-party dashlet development in CMK 2.5? The Exchange still has 2.4-style dashlets that are silently broken.

Investigation

What I found when porting to CMK 2.5:

After investigating the CMK 2.5 source on a 2.5.0p7 site, I found three fundamental changes:

1. show() is completely gone. Dashlet.show() no longer exists in cmk.gui.dashboard.dashlet.base. The dashboard is now fully Vue-based. There is no Python HTML-rendering path for dashlets anymore.

2. The Vue frontend only knows hardcoded widget types. In cmk/gui/dashboard/api/_utils.py there is a hardcoded dict INTERNAL_TO_API_TYPE_NAME with ~30 entries (url, hoststats, servicestats, nodata, linked_view, etc.). DashboardConstants.generate_api_response() uses this dict — only types listed here appear in the dashboard picker. Custom types registered via dashlet_registry.register(MyClass) are silently ignored by the frontend.

3. WidgetContent is a fixed Pydantic discriminated union. In cmk/gui/dashboard/api/model/widget_content/__init__.py the WidgetContent type is a hardcoded Annotated[TypeA | TypeB | ... | URLContent | ..., Discriminator("type")]. Custom dashlet types are not in this union and would fall into NotSupportedContent.

Greetz Bernd

silence in the wood`s ?!?!?!

@BH2005

No official way, however:

Hi @BH2005,

We are currently looking into options for embedding custom widgets in Checkmk 2.5 dashboards.

Right now, the most feasible approach is using the Embed URL widget to load your custom widget inside an IFrame. To make this much more useful, our plan is to support passing dashboard filters (both default and runtime) as URL parameters so your custom widget receives the full context of the dashboard.

Would this solution work for your use case?

Additionally, you mentioned wanting “custom dashlet types in CMK 2.5 that actually appear in the Vue dashboard picker”. Could you share a bit more about why having them directly in the widget picker is important for you?

Best,
Mathieu

Hi @Mathieu,

Good question, and it’s worth spelling out — a few concrete reasons why picker integration matters beyond just “selection”:

Configuration. The native picker gives you a structured config dialog right inside the dashboard editor (pick a host/service, a metric, a time range, with validation). With the embed-URL approach, all of that configuration has to be built and hosted separately — you end up handing the widget nothing more than a URL, with no schema or validation on the Checkmk side.

Dashboard context. Native widgets automatically participate in dashboard-wide filters, the global time range, theme (light/dark), and grid resizing. An iframe is opaque to all of that — it has to be reconstructed manually via URL parameters, which I know is planned for filters, but that only covers part of what “being a first-class widget” gives you for free.

Portability. A native widget is part of the dashboard’s JSON definition, so it travels with export/import/cloning. An iframe just points at an external URL, which has to stay hosted, reachable, and versioned independently — otherwise the dashboard breaks on reimport on a different site.

Auth. iframe content needs its own session/auth story (SSO or separate login), whereas a native widget runs inside Checkmk’s existing auth context.

So iframe is a reasonable stopgap, but I’d see it as a workaround rather than the destination. The cleaner long-term direction would be a plugin-registry approach — similar to how Grafana panel plugins or Kibana visualizations work: an installed MKP registers a widget type (Vue component + config schema), and the picker builds itself dynamically from the registry instead of the current static INTERNAL_TO_API_TYPE_NAME list. Checkmk already does exactly this for other extension points (views, check plugins, etc.) via MKPs — it’s really only the dashboard/Vue layer that hasn’t picked that pattern up since the rewrite.

Is native custom-dashlet support (via MKP-registered types) something that’s realistically on the roadmap at some point, even long-term? That would help me decide whether to keep pushing on this or just build around the iframe limitation for now.

I hope the automatic translate give the points clear back (my writen english is really bad)

Greetz Bernd

Hi Bernd,

Thank you for taking the time to provide such a detailed explanation. It really helps to have the full context.

With 2.5, we rebuilt the dashboard on a new Vue.js foundation. This new architecture works differently from the previous one, and the approach you used previously to extend dashboards through dashlets is no longer available in the same form.
I understand your point and I can see why this matters. You had a capability that allowed you to extend dashboards to fit your specific needs, and the new Vue.js architecture currently limits that flexibility.

As a short-term solution, we are planning to support embedding external content through an iframe, with the ability to pass dashboard filters (both default and runtime) as sanitized URL parameters. This should provide a way to continue extending dashboards, but we see this as a practical interim solution rather than the final answer.

When it comes to native custom-widget support it’s a fair request. However, it is a larger piece of work and first requires the underlying Vue.js layer to provide the necessary capabilities. At the moment it is not officially on our roadmap, so I don’t want to give you a timeline that we cannot commit to.
What I can say is that this is on our radar, and feedback like yours is valuable in helping us understand where the current limitations are and which capabilities would provide the most value as we continue to evolve the dashboard experience.

Best
Mathieu

Hi @Mathieu,

thanks for the honest answer — “on the radar but not committed” is fair, and I get that the Vue rewrite has to stabilize first. Let me make the ask more concrete though, because I think the actual gap is smaller than it looks.

You already solved this exact problem once, for a different part of the UI: FormSpecs. Rule configuration in WATO isn’t hand-written per rule anymore — it’s rendered generically from a Pydantic schema via the FormSpec → Vue component tree. I’d propose reusing that same mechanism for dashlet config instead of inventing a new schema format for widgets.

Concretely, three pieces:

  1. A registry instead of INTERNAL_TO_API_TYPE_NAME
    An MKP registers a widget type with: type_name, a config_schema (a regular FormSpec — no new format needed), a data_endpoint (REST route returning the widget’s data), and context_filters: list[str] declaring which dashboard filters it consumes. WidgetContent becomes a discriminated union resolved against the registry at runtime instead of a fixed compiled list.

  2. Two rendering tiers — this also addresses the obvious security concern
    Declarative: the plugin only ships data + a render type chosen from the existing Vue widget building blocks (table, gauge, graph, stat tile — whatever the dashboard layer already has). No foreign JS ever runs in the browser. This tier could ship without any special review process.
    Native component: the plugin ships an actual Vue SFC, loaded at runtime via dynamic import() (Module Federation or similar) — this is the Grafana/Kibana-panel equivalent I mentioned earlier, and it’s the one that needs signing/review like MKPs already get.

  3. A data-driven picker
    GET /api/dashboards/widget-types returns the registry contents (label, icon, schema). The picker grid renders from that response instead of being hardcoded — installing an MKP is enough to make a new widget type appear, no frontend release required.

The nice side effect: this also directly answers the four gaps I listed in my last post — config validation comes for free from FormSpec reuse, filter/theme/resize context comes from the shared dashboard Vue layer injecting props into the widget instead of the widget fetching them itself, portability falls out because the widget config is just a normal part of the dashboard JSON (import just needs to check the referenced MKP is installed, same as it already does for rules), and auth is just the existing REST session — no separate mechanism.

None of this requires a new config-UI framework — it’s the same FormSpec renderer you already have, plus a registry indirection and two render tiers. Would that change the roadmap calculus, or is there a specific blocker in the Vue layer that makes even this harder than it sounds from the outside?

That’s a whole bunch of explanations, but I hope I’m not completely off the mark with my assumptions and “naive” suggestions for solutions.

Greetz Bernd