Web browser
Chromium-based (Chrome/Edge) and Firefox — any recent browser
Web browser version
Reproduces on all current browsers; the bug is a static code gap in the HACS frontend bundle, not a browser-specific rendering issue
System Health details
- Home Assistant: 2026.4.2
- HACS integration: 2.0.5 (latest release, confirmed up to date via `update.hacs_update`)
- HACS frontend bundle: latest published release is `20250128065759` (Jan 28, 2025)
- Custom integration reproducing the issue: `iskael/bosch-dishwasher`, which ships inline brand icons under `custom_components/bosch_dishwasher/brand/` per the new API
Checklist
Describe the issue
Starting with Home Assistant 2026.3, custom integrations can ship their own brand icons directly inside the integration (`custom_components//brand/icon.png`), and HA serves them through a new authenticated proxy at `/api/brands/integration//
`. See the official announcement: https://developers.home-assistant.io/blog/2026/02/24/brands-proxy-api. The `home-assistant/brands` repository now auto-closes any PR for `custom_integrations/*` and tells contributors to use the inline mechanism instead.
The problem is that the HACS frontend still hits the public CDN for custom-integration icons, so inline brands are invisible in the HACS downloads panel — the row shows the "icon not available" placeholder even though the icon is correctly served by the local proxy.
Root cause (verified against the source):
`src/dashboards/hacs-dashboard.ts` imports `brandsUrl` from the pinned `homeassistant-frontend` submodule and calls it like this:
```ts
<img
src=${brandsUrl({
domain: repository.domain || "invalid",
type: "icon",
useFallback: true,
darkOptimized: this.hass.themes?.darkMode,
})}
/>
```
`useFallback` is a field from the old `BrandsOptions` interface that no longer exists in `home-assistant/frontend` `dev`. The current implementation was rewritten for the brands proxy:
```ts
// home-assistant/frontend/src/util/brands-url.ts (current)
export const brandsUrl = (options: BrandsOptions, hassUrl?: string): string => {
hassUrl = hassUrl ?? location.origin;
const base = `/api/brands/integration/${options.domain}/${
options.darkOptimized ? "dark_" : ""
}${options.type}.png`;
const url = new URL(base, hassUrl);
if (_brandsAccessToken) {
url.searchParams.set("token", _brandsAccessToken);
}
return url.toString();
};
```
HACS's pinned submodule is still on the old version that returns `https://brands.home-assistant.io/_/{domain}/icon.png\` directly to the browser. That CDN path doesn't serve inline-shipped custom-integration icons, so custom integrations on HA 2026.3+ that use the new mechanism get the placeholder.
Also worth noting: the maintainers of `home-assistant/brands` already redirect contributors here. Closed PR home-assistant/brands#10149 from this thread was auto-closed with the exact message "we no longer accept brand icons for custom integrations in this repository".
Reproduction steps
- Run Home Assistant 2026.3.0 or newer (reproduced on 2026.4.2).
- Install any custom integration that ships brand icons inline under `custom_components//brand/icon.png`. A minimal example is `iskael/bosch-dishwasher` (v0.1.4 and later).
- Confirm that HA core renders the icon in Settings → Devices & services (it does — served via `/api/brands/integration//icon.png` with an auth token).
- Open HACS → Downloads and look at the row for that integration.
- The row shows the generic "icon not available" placeholder instead of the inline icon.
Direct verification against the HA instance:
```
200, image/png, matches the bytes of brand/icon.png
curl -H "Authorization: Bearer " \
http://HA/api/brands/integration/bosch_dishwasher/icon.png
→ 200, image/png, 2515 bytes
without the token the proxy returns 403
curl http://HA/api/brands/integration/bosch_dishwasher/icon.png
→ 403
```
Screenshots

The same integration renders its icon correctly in HA core's integration list and on the config-flow dialog — the gap is specific to the HACS panel.
Javascript logs from your browser console
No runtime errors. The bug is a static code gap: the bundled `brandsUrl` returns the old CDN URL (`https://brands.home-assistant.io/_/bosch_dishwasher/icon.png\`), the browser requests it, the CDN responds 404, and HACS's `
` falls back to the placeholder. No exceptions are thrown.
Debug logs
Not applicable. This is not a runtime error in the integration; it is reproducible by reading the source of `src/dashboards/hacs-dashboard.ts` and the pinned `homeassistant-frontend` submodule. Enabling HACS debug logging produces no additional information because the icon resolution happens entirely on the frontend.
Diagnostics dump
Not applicable for the same reason — the HACS integration diagnostics do not cover frontend bundle paths. Happy to provide one if the maintainers believe it would add information.
Requested change
- Bump the pinned `homeassistant-frontend` submodule past the brands-proxy rewrite (so `brandsUrl` points at `/api/brands/integration/...` and uses the access token flow).
- In `src/dashboards/hacs-dashboard.ts`, drop `useFallback: true` (no longer a valid `BrandsOptions` field) and call `fetchAndScheduleBrandsAccessToken(this.hass)` during panel initialization so `
` URLs carry a valid `?token=...` query string.
- Cut a new HACS frontend release — the last published one is `20250128065759`, which predates the HA 2026.3 brands-proxy feature.
With those three changes the HACS panel will pick up inline brand icons automatically, no PR to `home-assistant/brands` required (which is the officially supported path now).
Web browser
Chromium-based (Chrome/Edge) and Firefox — any recent browser
Web browser version
Reproduces on all current browsers; the bug is a static code gap in the HACS frontend bundle, not a browser-specific rendering issue
System Health details
Checklist
Describe the issue
Starting with Home Assistant 2026.3, custom integrations can ship their own brand icons directly inside the integration (`custom_components//brand/icon.png`), and HA serves them through a new authenticated proxy at `/api/brands/integration//
`. See the official announcement: https://developers.home-assistant.io/blog/2026/02/24/brands-proxy-api. The `home-assistant/brands` repository now auto-closes any PR for `custom_integrations/*` and tells contributors to use the inline mechanism instead.
The problem is that the HACS frontend still hits the public CDN for custom-integration icons, so inline brands are invisible in the HACS downloads panel — the row shows the "icon not available" placeholder even though the icon is correctly served by the local proxy.
Root cause (verified against the source):
`src/dashboards/hacs-dashboard.ts` imports `brandsUrl` from the pinned `homeassistant-frontend` submodule and calls it like this:
```ts
<img
src=${brandsUrl({
domain: repository.domain || "invalid",
type: "icon",
useFallback: true,
darkOptimized: this.hass.themes?.darkMode,
})}
/>
```
`useFallback` is a field from the old `BrandsOptions` interface that no longer exists in `home-assistant/frontend` `dev`. The current implementation was rewritten for the brands proxy:
```ts
// home-assistant/frontend/src/util/brands-url.ts (current)
export const brandsUrl = (options: BrandsOptions, hassUrl?: string): string => {
hassUrl = hassUrl ?? location.origin;
const base = `/api/brands/integration/${options.domain}/${
options.darkOptimized ? "dark_" : ""
}${options.type}.png`;
const url = new URL(base, hassUrl);
if (_brandsAccessToken) {
url.searchParams.set("token", _brandsAccessToken);
}
return url.toString();
};
```
HACS's pinned submodule is still on the old version that returns `https://brands.home-assistant.io/_/{domain}/icon.png\` directly to the browser. That CDN path doesn't serve inline-shipped custom-integration icons, so custom integrations on HA 2026.3+ that use the new mechanism get the placeholder.
Also worth noting: the maintainers of `home-assistant/brands` already redirect contributors here. Closed PR home-assistant/brands#10149 from this thread was auto-closed with the exact message "we no longer accept brand icons for custom integrations in this repository".
Reproduction steps
Direct verification against the HA instance:
```
200, image/png, matches the bytes of brand/icon.png
curl -H "Authorization: Bearer " \
http://HA/api/brands/integration/bosch_dishwasher/icon.png
→ 200, image/png, 2515 bytes
without the token the proxy returns 403
curl http://HA/api/brands/integration/bosch_dishwasher/icon.png
→ 403
```
Screenshots
The same integration renders its icon correctly in HA core's integration list and on the config-flow dialog — the gap is specific to the HACS panel.
Javascript logs from your browser console
No runtime errors. The bug is a static code gap: the bundled `brandsUrl` returns the old CDN URL (`https://brands.home-assistant.io/_/bosch_dishwasher/icon.png\`), the browser requests it, the CDN responds 404, and HACS's `
` falls back to the placeholder. No exceptions are thrown.
Debug logs
Not applicable. This is not a runtime error in the integration; it is reproducible by reading the source of `src/dashboards/hacs-dashboard.ts` and the pinned `homeassistant-frontend` submodule. Enabling HACS debug logging produces no additional information because the icon resolution happens entirely on the frontend.
Diagnostics dump
Not applicable for the same reason — the HACS integration diagnostics do not cover frontend bundle paths. Happy to provide one if the maintainers believe it would add information.
Requested change
With those three changes the HACS panel will pick up inline brand icons automatically, no PR to `home-assistant/brands` required (which is the officially supported path now).