Rules / Performance
Remove custom visuals which are not used in the report
What it checks
Custom visuals from AppSource that the report registers in report.json and that no visual on any page uses.
Each finding is on the report, as Report, one for each unused visual, and its detail names the visual by the type name the report registers it under, as ChicletSlicer1448559807354 is registered but no visual uses it.
Example
The report registers the Chiclet Slicer from AppSource, and no visual on its one page is a Chiclet Slicer.
report.json{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/report/3.2.0/schema.json",
"themeCollection": {
"baseTheme": {
"name": "Fluent2-CY26SU04",
"reportVersionAtImport": { "visual": "2.8.0", "report": "3.2.0", "page": "2.3.1" },
"type": "SharedResources"
}
},
"resourcePackages": [
{
"name": "SharedResources",
"type": "SharedResources",
"items": [
{ "name": "Fluent2-CY26SU04", "path": "BaseThemes/Fluent2-CY26SU04.json", "type": "BaseTheme" }
]
}
],
"publicCustomVisuals": ["ChicletSlicer1448559807354"]
}
report.json{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definition/report/3.2.0/schema.json",
"themeCollection": {
"baseTheme": {
"name": "Fluent2-CY26SU04",
"reportVersionAtImport": { "visual": "2.8.0", "report": "3.2.0", "page": "2.3.1" },
"type": "SharedResources"
}
},
"resourcePackages": [
{
"name": "SharedResources",
"type": "SharedResources",
"items": [
{ "name": "Fluent2-CY26SU04", "path": "BaseThemes/Fluent2-CY26SU04.json", "type": "BaseTheme" }
]
}
],
"publicCustomVisuals": []
}
Why it matters
Importing a visual from AppSource registers it with the report, and deleting the last visual that drew with it leaves the registration behind. The report then declares a dependency on third-party code it no longer uses: the visual sits in the Visualizations pane for everyone who edits the report, and whoever reviews which custom visuals a report relies on, or checks a report against the visuals the organization allows, has to account for one that draws nothing. Over time the pane stops being a reliable list of what the report needs, and nobody tidying it can tell which entries are safe to remove.
How to fix it
In Power BI Desktop, right-click the visual's icon among the imported visuals in the Visualizations pane and remove it, confirming when Desktop asks. In report.json, delete the name from publicCustomVisuals; when it was the only one, the list is left empty, as in the example. If a page needs the visual again later, import it again from AppSource.
When to ignore it
A report kept as a starting point for other reports, which registers the visuals its authors are expected to use before any page uses them, is the one case where an unused registration is deliberate. A report that readers open is not that case: if a page is about to need the visual, importing it again when that page is built costs a minute.
This rule reports on the report itself, so there is no object to annotate. To turn the rule off for a whole project, set "REMOVE_UNUSED_CUSTOM_VISUALS": "off" under rules in pbiplint.config.json.
Quirks
- Only the AppSource visuals listed in
publicCustomVisualsare checked. A visual imported from a .pbiviz file is stored in the report's CustomVisuals folder instead, and pbiplint does not read that folder, so an unused visual imported from a file is not reported. - A visual counts as used when any visual in the report has its type name, on any page, hidden pages and hidden visuals included.
- The finding is on the report rather than on a page or visual, because an unused visual has neither, so it cannot be ignored for one visual alone.
- While a visual.json cannot be read, such as one holding merge-conflict markers or one pbiplint could not open at all, or a folder under the definition folder that could hold one could not be listed, and a registered visual is not used by any visual pbiplint could read, the rule reports nothing, because the unread visual could be the one that uses it and pbiplint does not guess what a file it could not read says. The skipped line gives the reason,
a report file could not be read, the file's ownPARSE_ISSUEfinding names it, or a notice does for a file pbiplint could not open or a folder it could not list, and the Visuals line of Report at a glance says how many registered types are used is unknown. When the report registers no custom visual, or every one it registers is used by a visual that was read, the unread file cannot change the answer, and the rule runs.
Links
- Import Power BI visuals from AppSource or from a file
- The Power BI Desktop project report folder and its CustomVisuals folder
Ported from PBI Inspector's base rules by Nat Van Gulck.