feat!: release v2 (#6545)

Co-authored-by: Artur <145776561+arturict@users.noreply.github.com>
Co-authored-by: arturict <arturict@users.noreply.github.com>
Co-authored-by: Thomas <thomas@ajnart.fr>
Co-authored-by: Afonso Jorge Ramos <afonsojorgeramos@gmail.com>
Co-authored-by: Danura30082 <danura30082+github@gmail.com>
Co-authored-by: Kushie <122986913+kushiemoon-dev@users.noreply.github.com>
Co-authored-by: ajnart <thomas@ajnart.fr>
Co-authored-by: ajnart <thomas@ajnart.dev>
Co-authored-by: chenjun <chenjun@foxmail.com>
Co-authored-by: Wikibear <wikibear@users.noreply.github.com>
Co-authored-by: Bergasha <bergasha@gmail.com>
Co-authored-by: leafyelin <43306196+leafyelin@users.noreply.github.com>
Co-authored-by: Lucas Araujo <lucas.lra@gmail.com>
Co-authored-by: GreenMonito <86085570+GreenMonito@users.noreply.github.com>
Co-authored-by: Nerdy-Technician <roffo@nerdy-technician.social>
Co-authored-by: Jun <34545896+jcstrong@users.noreply.github.com>
Co-authored-by: Edmond Abraham <54119952+gitedmond@users.noreply.github.com>
Co-authored-by: thrawnx <tight.bulb9384@fastmail.com>
Co-authored-by: Chris <58918656+nordada@users.noreply.github.com>
Co-authored-by: yi111 <153097222+Yi-111-a@users.noreply.github.com>
Co-authored-by: Yanis <naamaneyanis@gmail.com>
Co-authored-by: Wikibear <me@sej.de>
Co-authored-by: alessiottavo <93441886+alessiottavo@users.noreply.github.com>
This commit is contained in:
3286 files changed
+284386 -139176

No files matched your search

@@ -1,9 +0,0 @@
{
"label": "Management",
"collapsed": true,
"position": 2,
"link": {
"type": "generated-index",
"title": "Management pages"
}
}
+46 -53
View File
@@ -6,80 +6,73 @@ tags:
- Interface
---
Using the Homarr API, you can interface with the application with your own code and business logic.
It enables you to trigger almost all actions that you can perform from the Homarr UI.
With the API, you can build resilient systems that automatically update Homarr with data - for example syncing it with
your deployments in a cluster or dynamically adding integrations depending on how many replicas you run.
Use the generated specification under **Management → Tools → API** or the [interactive API reference](/api-reference).
This page covers contracts that are not obvious from those schemas.
The in-app reference loads its schema from `/api/openapi?format=scalar` on your Homarr instance. `/api/openapi` provides the raw JSON specification.
This page is language-neutral, and you must implement the API on your own in your desired language.
It requires you to know your programming language well and have a basic understanding of HTTP, JSON and networking.
You can test out API endpoints using any OpenAPI client - for example [Yaak](https://yaak.app/).
![Homarr's API documentation page](../img/api.png)
## Opening the API specification
## Authentication and browser access
The specification is implemented according to the OpenAPI standard.
To access the documentation, you'll need to spin up an instance of Homarr.
Navigate to `Management` > `Tools` > `API`.
You can copy the JSON url into your OpenAPI client or try out the endpoints directly from your browser.
API keys are shown once as `<id>.<token>`. Send one in the `ApiKey` header; it acts as its creator and does not expire.
tRPC accepts the same header. Same-origin browser requests can use the Homarr session cookie.
Alternatively, you can [open the full interactive API reference](/api-reference) directly in your browser.
Cross-origin browser requests require `ApiKey`; they do not use session cookies. Reverse proxies must forward `OPTIONS`
and preserve CORS headers. An HTTPS API reference cannot call an HTTP-only instance because browsers block mixed content.
## Authentication
## Endpoint constraints
Many endpoints will require you to authenticate. At the top of the API reference, you'll find a button to authenticate yourself with an API key.
You can obtain API keys from the "Authentication" tab at the top of the page.
API keys will not expire and can be used indefinitely.
- General pagination and shared search are capped at 100 records.
- `POST /api/invites` and `invite.createInvite` accept `expirationDate` as a timezone-qualified ISO 8601 string.
- `GET /api/health/live` is unauthenticated and returns `200` when all dependencies are healthy, `500` otherwise.
### API Key Format
`widget.immich.getAlbumPreview` returns at most one image from a selected album. Its input includes `albumId` and
`randomizePhotos`; it uses the same saved-integration access rules as `widget.immich.getAlbum`. Use `getAlbum` for the
complete album image list.
API keys are provided in the format `<id>.<token>`. When making requests, include the key in the `ApiKey` header:
## Permissions and results
```
ApiKey: abc123def456.xyz789tokenvalue...
```
Requests use the API key owner's permissions. Unauthorized operations return `FORBIDDEN`; resource-aware lists are
filtered on the server.
### Supported Endpoints
`app.all`, `app.getPaginated`, and `app.search` require **Modify all apps** because they include internal URLs. Use
`app.selectable` for reduced picker data. Integration lists include only accessible integrations; check `hasUseAccess`
and `hasInteractAccess` before reading data or invoking actions.
API key authentication works with both endpoint types:
Multi-integration queries can return partial data with endpoint-specific failure metadata.
| Endpoint Type | Path Pattern | API Key Support |
| ------------- | --------------- | --------------- |
| OpenAPI | `/api/...` | ✅ Supported |
| tRPC | `/api/trpc/...` | ✅ Supported |
## Board automation
If no API key is provided, Homarr falls back to session cookie authentication (for browser-based access).
Each board has one Base and one Mobile layout; Mobile uses breakpoint `0`. Other breakpoints must be unique, and Homarr
uses the highest breakpoint that fits. Reuse canonical layouts and generated IDs returned by save operations.
### Usage Examples
Integration-backed widgets require use access to each newly selected integration.
**OpenAPI endpoint:**
`board.addItem` accepts `size: { width, height }` in grid cells (1–24 each), places the item in the first free position
on every layout, and caps width to the available columns.
```bash
curl -H 'ApiKey: <id>.<token>' http://localhost:7575/api/health/live
```
`board.updateItemLayout` (`PATCH /api/boards/{boardId}/items/{itemId}/layouts/{layoutId}`) moves or resizes one item in
one layout without replacing the board. It cannot move the item outside its section or overlap another item/container.
**tRPC endpoint:**
## Docker targets
```bash
curl -H 'ApiKey: <id>.<token>' http://localhost:7575/api/trpc/app.all
```
Docker actions require `{ endpointId, id }` targets from `docker.getContainers`; `endpointId` distinguishes hosts.
Omit `endpointIds` or pass an empty array to query every configured endpoint.
### Use Cases
## Custom Widget resources
API key authentication enables programmatic access for:
Administrators can retrieve the Custom Widget authoring prompt, schema, component catalog, skill, and references under
`/api/custom-widgets/`. See [agent authoring](/docs/management/custom-widgets/agent-authoring) for the workflow.
- Automation scripts and CI/CD pipelines
- Third-party integrations
- Custom dashboards and monitoring tools
- Container orchestration systems that need to sync app definitions
## Call any integration API endpoint
## Board Automation
`POST /api/integrations/request` is available as tRPC `integration.request` and MCP `integration_request`. Homarr uses
the saved integration credentials; callers do not supply them. The `path` stays within the saved integration URL, and
redirects are rejected. See the generated schema for selectors, permissions, and request limits.
The OpenAPI and MCP APIs include board management endpoints for common automation workflows:
Even `GET` can change upstream state. Homarr `200` can contain an upstream failure; inspect `ok`, `status`, and `data`.
Requests are not retried, so check upstream state after a timeout before retrying a write.
- Create, duplicate, rename and delete boards
- Change board visibility
- Update board visual and behavior settings
- Set desktop and mobile home boards for the current user
- Configure global board defaults such as public home boards and status behavior
Use the interactive API reference to inspect the exact request body for each endpoint under the `boards` and `settings` tags.
The iCalendar feed integration stores a calendar URL rather than arbitrary HTTP API credentials. TrueNAS uses a WebSocket
API. Neither works with `integration_request` or Custom Widget integration sources. qBittorrent generic requests require
a saved API key and qBittorrent 5.2.0 or newer. UniFi generic requests require the controller's HTTPS URL and actual port.
+25 -35
View File
@@ -7,50 +7,40 @@ tags:
- Ping
---
Apps are the building blocks of your Homarr board.
Most of the time they are a simple link to a website, but used on your board they also support a simple ping to check if your service is up.
Apps are used in the bookmark and app widget.
import { AppFlowDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams";
## Create an app
An **app** is a saved shortcut used by the App and Bookmarks widgets. It contains a name, destination, icon, and
optional status-check address.
To create an app you can click on the button on the top right of the apps management page:
![The Apps management page](../img/apps.png)
![New app button](./img/new-app-button.png)
## How an app is used
Next, you'll need to fill out the required fields to configure the app:
<AppFlowDiagram />
![New app form](./img/new-app-form.png)
## Configuration
### Name
Create and manage apps under **Management → Apps**.
Creating or deleting an app refreshes open app lists and app widgets.
The name must be at least one character long and can be chosen freely.
| Field | Purpose |
| ----------- | ---------------------------------------------------------------------------------------- |
| Name | Label shown on the board |
| Icon URL | Direct image URL, icon-library result, or uploaded image |
| Description | Optional tooltip |
| URL | Destination opened from the board; custom URI schemes are supported except `javascript:` |
| Ping URL | Optional HTTP(S) address used for status checks when it differs from the destination |
### Icon URL
An app can be linked to an [integration](../integrations). Integration widgets then use the app as their destination
when they provide a link to the service.
This is the URL to the icon that will be displayed on the app widget.
You can paste a direct HTTP(S) URL to an image, search the included icon repositories by name, or upload a local file through the upload button. The app name is pre-filled as the initial library search when no image is selected. Local images appear first, followed by SVG icons and other formats. Direct image URLs are previewed, used as entered, and are not searched in the icon repositories.
See [Icons](/docs/advanced/icons) for icon sources and uploads.
![Icon URL](./img/app-icon-url.png)
## Permissions
### Description
- `app-create` creates apps.
- `app-modify-all` lists and edits every app.
- `app-full-all` also deletes and uses every app.
- `app-use-all` allows using every app on boards without granting management access.
An optional description that can be shown as tooltip on the app widget.
### URL
The URL to the website you want to link to. Clicking on the app widget or bookmark will open this URL.
You can also use custom URI schemes such as `vscode://file/path`, `microsoft-edge:https://example.com`, or `myapp://open` to link to local applications or third-party programs. We trust that you know what you are doing — only `javascript:` URIs are blocked for security reasons.
### Ping URL
When you want to use another url for the simple status check you can set it here.
This will allow you to set a different URL for the ping than the URL that is opened when clicking on the app widget.
It's useful when you want to ping the service internally for example with a custom ip but open the website externally.
Note that the ping URL only accepts `http://` and `https://` URLs — custom URI schemes are not supported for pings.
## List of apps
On the apps management page you find all apps that exist in your Homarr instance. You can edit and delete them.
![Apps list](./img/app-list.png)
Users with only `app-create` can open the page and create an app, but do not receive the existing app list.
+69
View File
@@ -0,0 +1,69 @@
---
description: Configure and use Assistant.
tags:
- Assistant
- AI
- Administration
---
import { AssistantFlowDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams";
# Assistant
Assistant answers questions and operates Homarr through the signed-in user's permissions. Read-only tools can run
automatically; changes require approval by default.
![The Assistant management page](./img/assistant.png)
## Request flow
<AssistantFlowDiagram />
## Configuration
Under **Management → Assistant**, select a provider, configure its API URL and key when required, select the default
model, and enable Assistant. Users can choose another available model for a conversation.
Provider presets cover common APIs. **Custom endpoint** accepts an OpenAI-compatible Chat Completions API. For a model
server outside the Homarr container, use a hostname that the container can resolve instead of `localhost`.
The [Homarr provider](/docs/workshop/homarr-provider) is available through the Community Workshop without an administrator
API key and has a daily request allowance.
<Alert type="warning" title="Using an existing AI subscription">
Homarr Assistant cannot use existing AI subscriptions such as Claude or GitHub Copilot, and this is not planned. To use
your preferred AI client with Homarr, connect it to the [Homarr MCP server](/docs/management/mcp).
</Alert>
## Access
Open Assistant from the user menu, with `Shift+A`, from search with `Cmd/Ctrl+/`, or through the
[Assistant widget](/docs/widgets/assistant).
Homarr checks Assistant availability alongside other page settings, so an enabled Assistant appears with the dashboard
without reloading its widgets after the page opens. Widget configuration loads its editor when you open the configuration
dialog.
Assistant can work with boards, apps, integrations, widgets, Custom Widgets, and supported connected services. Mention
Homarr resources with `@`; the model loads additional live context only when needed.
Conversations are stored per user and can be searched, renamed, exported, or deleted.
## Permissions and data
- Every tool call uses the current user's Homarr permissions.
- Automatic approvals apply only to the current conversation and reset when switching conversations.
- Provider keys and custom headers are encrypted and are not returned to the browser.
- Prompts, attachments, tool definitions, and tool results are sent to the selected model provider.
See [MCP](/docs/management/mcp) to connect an external AI client and
[Custom Widget agent authoring](/docs/management/custom-widgets/agent-authoring) for widget generation.
## Troubleshooting
- **No models found:** check the API URL, discovery path, and API key, or enter a model ID manually.
- **Assistant is unavailable:** enable it and save the configuration.
- **Tool calls stop:** use a model that supports streaming and tool calls.
- **Local endpoint is unreachable:** check container DNS, routing, and the model server's listen address.
+22 -56
View File
@@ -6,71 +6,37 @@ tags:
- Data
---
# Backup & Restore
# Backup and restore
Homarr provides a built-in backup and restore system for **SQLite** instances. You can export your entire database - including apps, integrations, boards, users, and encryption keys - as a ZIP archive, and restore it on the same or a different Homarr instance.
Administrators using SQLite can export and restore the complete Homarr database under
**Management → Tools → Backup**. PostgreSQL installations must use their database-native backup tools.
:::warning
![The Backup and restore management page](./img/backup.png)
Backup and restore is only available when using the **SQLite** database driver. MySQL and PostgreSQL instances do not show this page.
For an existing MySQL installation, [convert to SQLite before upgrading to v2](/docs/advanced/mysql-to-sqlite). The converter produces a database file, not a backup ZIP.
:::
## Export
## Accessing the Backup Page
The ZIP contains:
Navigate to `Management` → `Tools` → `Backup`. You must have **admin** permissions to access this page.
| File | Contents |
| --------------- | ----------------------------------------------------------- |
| `db.sqlite` | Apps, integrations, boards, users, settings, and other data |
| `metadata.json` | Homarr version, backup timestamp, and encryption metadata |
## Exporting a Backup
Export requires typing `I understand`. Store the ZIP as sensitive data: it contains the database and the material
needed to restore encrypted integration credentials.
Click the **Export** button in the export card. You'll be prompted to type `I understand` to confirm. Once confirmed, a ZIP file downloads containing:
## Restore
| File | Description |
| -------------------- | ------------------------------------------------------------------- |
| `db.sqlite` | Full SQLite database with all entities |
| `metadata.json` | Backup metadata: Homarr version, creation timestamp, encryption key |
Select a Homarr backup ZIP. The browser previews entity counts, board names, and required database migrations before
the archive is uploaded.
The backup includes everything: apps, integrations, secrets, boards, users, groups, permissions, search engines, custom widgets, and server settings. (It just backs-up the whole database)
Restoring replaces the current SQLite database and cannot be undone. It also invalidates the current database session.
After a successful management restore, Homarr waits for the restarted server and sends the administrator to sign in
again. The first-run onboarding restore keeps its existing board destination.
## Restoring a Backup
A backup can be restored on another Homarr instance. When its `SECRET_ENCRYPTION_KEY` differs, Homarr re-encrypts stored
integration secrets for the target instance. Version metadata is used to apply compatible migrations.
### 1. Upload
Drag and drop or select a `.zip` backup file. The import card validates that the file contains a valid `db.sqlite` and metadata.
### 2. Preview
Before restoring, Homarr uses **sql.js WASM** to analyze the backup directly in your browser. You'll see:
- **Entity counts** - how many apps, integrations, boards, users, etc. are in the backup
- **Board names** - which boards will be restored
- **Migration status** - Drizzle migrations are applied in-browser with a visual timeline showing each migration step
### 3. Confirm
Type `I understand` to acknowledge that restoring will replace your current database. This cannot be undone.
### 4. Restore
The backup ZIP is sent to the server, validated, and applied. After a successful restore:
- **The Next.js server restarts automatically** to reload the new database state
- Nginx and Redis (if running in Docker) stay up - only the Next.js process restarts
- The page reloads once the server is ready
## Cross-Instance Restore
You can restore a backup from one Homarr instance onto another. Homarr handles:
- **Encryption key re-encryption** - If the target instance has a different `SECRET_ENCRYPTION_KEY`, integration secrets are decrypted with the old key and re-encrypted with the new one during import
- **Version compatibility** - Backups include the Homarr version they were created with. Backward compatibility is maintained for older backup formats
## Backup During Onboarding
When setting up a new SQLite Homarr instance, the onboarding flow includes a **Restore from SQLite backup** step. You can upload a backup ZIP directly during onboarding to skip manual setup.
## Security
- Export requires admin permissions
- The `I understand` confirmation dialog prevents accidental exports and overwrites
- Backups contain encrypted integration secrets - they cannot be read without the `SECRET_ENCRYPTION_KEY`
- Import only works on SQLite instances - the API routes refuse requests from MySQL/PostgreSQL instances
The same restore flow is available during first-run onboarding, before the target database contains user data.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 256 KiB

+80 -255
View File
@@ -9,287 +9,112 @@ tags:
- Layout
---
import iconColorImage from "./img/icon-color.png";
import itemRadiusImage from "./img/item-radius.png";
import layoutLargeImage from "./img/layout-large.png";
import layoutMediumImage from "./img/layout-medium.png";
import layoutSmallImage from "./img/layout-small.png";
import { BoardLayoutsDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams";
Each dashboard is called a "board".
You can create as many boards as you want.
Boards can be restricted to user groups.
A user may also have a "home board" which they will see at the root path (e.g. my-homarr.com or my-homarr.com/board).
Other boards can be viewed by direct links (e.g. my-homarr.com/board/smart-home) or via the management pages.
A **board** is a dashboard page containing apps, widgets, and Containers. Its name is unique and forms the board URL.
Boards can be public or restricted to users and groups.
Names of boards must be unique because this will be used in the URL to load the desired board.
![The Boards management page](../img/boards.png)
## Create a new board
Create, duplicate, open, and delete boards under **Management → Boards**. Press `Shift+C` from a board to open the
board switcher.
When creating a board, the availability of the board name will be checked for you.
## Initial loading
![](./img/create-board-modal.png)
Homarr starts supported widgets' initial data queries together on the server after resolving the board and its initial
layout. Results stream independently while the board loads. The board remains visible as widgets fill in. App and
bookmark tiles use the initial server HTML; other widgets show labeled cards until browser hydration. Previously
loaded, bounded integration data and matching board RSS feeds can appear from the board's Redis snapshot while fresh
data loads. If Redis is slow, Homarr starts uncached widget requests without waiting for that snapshot. Widgets without
a cached result stay empty until their first result arrives. Integration
queries for collapsed sections wait until opened, and queries that need another result start when that dependency
resolves. Existing integration permissions and live refresh intervals still apply.
### Name
## Responsive layouts
The name must not include any special characters and must be at least one character long.
Underscores and hyphen-minus are allowed.
<BoardLayoutsDiagram />
### Column count
Mobile and Base are protected layouts. New boards use three Mobile columns; Base uses the column count selected at
creation. Additional layouts use unique breakpoints. Homarr selects the layout with the highest breakpoint that fits
the current viewport.
Homarr has a complex drag-and-drop system that can be used from the browser.
The column count defines how many horizontal columns are available to drag and drop elements to.
Tiles use fixed `200 × 200` logical-pixel cells with a `24px` gap. Homarr scales the complete layout to the available
width instead of changing each widget's proportions. **Reset from Base** regenerates a Mobile or custom layout from the
current Base layout.
### Public
### Containers and rails
This will enable public access for everyone - regardless of whether they are logged in or not.
This can be really useful if you want to have public boards in your company or for family and friends.
Modifications for public boards must be allowed explicitly using user groups and their permissions.
A **Container** groups apps, widgets, and nested Containers. It can have a label, collapse control, app-opening action,
border color, and CSS classes.
Items can occupy the outermost rows and columns of a Container. The drop preview shows the position where the item
will remain when released.
Dragging an item onto another item of the same size swaps their positions. Displaced items snap directly to their
previewed positions without a movement animation and stay there when you release the pointer.
A **rail** reserves one to three columns at the left or right of a non-Mobile layout. Rails stay fixed while the page
scrolls and store their contents separately for each layout. Layout settings and Manage Boards use the same preview,
with enabled sidebars shown beside the main canvas.
## Edit a board
Enter edit mode from the board header to add, move, resize, configure, or remove content. Save the board to persist the
layout.
- Drag from an item's inactive content area; Containers use their grip.
- Hold `Ctrl` on Windows/Linux or `Cmd` on macOS to select several items.
- Use **Move / resize item** for another canvas, rail, Container, or exact coordinates.
- Keyboard users can focus a tile, press Enter or Space, then move with arrow keys or resize with Shift + arrow keys.
- Press Escape during a pointer or touch interaction to restore the item to its previous position.
The add-content menu can create an app, integration, widget, or Container without leaving the board.
When adding apps, click one app to add it immediately, or choose **Select multiple** to add several at once. `Ctrl`/`Cmd`
click remains available as a shortcut.
## Board settings
You navigate to the board settings by clicking on these three dots:
Board settings cover:
![](./img/navigate-to-settings.png)
- **General:** page title, browser title, logo, and favicon.
- **Layout:** responsive layouts, breakpoints, columns, and rails.
- **Background:** image, attachment, size, and repeat behavior.
- **Appearance:** colors, opacity, icon color, and item radius.
- **Custom CSS:** styles applied only to the current board.
- **Behaviour:** app status and widget context-menu behavior.
Alternatively, you can also navigate from the board page itself using the cog icon at the top right:
See [Styling](/docs/advanced/styling) for board and global CSS.
![](./img/navigate-to-settings-2.png)
Outside edit mode, widgets may expose an advanced view and a context menu for status, refresh, quick options, settings,
and actions. Available controls depend on the widget and the user's board and integration permissions.
Closing the context menu does not cancel a widget refresh. Reopen it to see the current status.
All board settings are edited on a single page. Click the **Save changes** button in the save bar at the bottom to apply them, or **Discard** to restore the last saved values. The save bar only appears when you have unsaved changes. Access control and the Danger zone are independent sections and are applied immediately.
## Access control
### General
Public boards are readable without signing in. Private boards require user, group, or global access.
#### Page title
| Board access | View | Edit content and settings | Access control, rename, delete |
| ------------ | ---- | ------------------------- | ------------------------------ |
| View | Yes | No | No |
| Modify | Yes | Yes | No |
| Full | Yes | Yes | Yes |
This is the title that will be visible at the top left in the navigation bar:
Inherited access comes from group permissions. Resource-specific access can be granted from the board's access-control
section.
![](./img/page-title.png)
Renaming a board changes its URL without a redirect. Deleting a board is permanent.
This field is optional and Homarr will fall back to "Homarr" if nothing is set.
In edit mode, nested Container settings controls are staggered to reduce overlap where space allows.
#### Meta title
## Home boards
This is the secondary title of the page that is not directly visible in the page itself.
Browser will use it to set the title of tabs:
A **home board** opens at `/` and `/boards`. Desktop and mobile home boards are separate from the responsive layouts
inside a board.
![](./img/meta-title.png)
Defaults can be set for a user, group, or the whole server. User settings take priority, followed by matching groups,
the `Everyone` group, and server defaults. Server-wide fallback boards must be public.
Homarr will fall back to the board name and a suffix if nothing is set.
See [Users and groups](/docs/management/users) and [Server settings](/docs/management/settings#boards).
#### Logo image URL
## Widget previews
This is the URL that is used for the image at the top left.
Homarr will fall back to the Homarr logo if nothing is set.
#### Favicon image URL
This is the URL that is used for the favicon in the tab title.
Homarr will fall back to the Homarr logo if nothing is set.
### Layout
In this section you can configure the different responsive layouts. Depending on your screens width the layout will change.
![](./img/layout-settings.png)
On each element the position and size of items can be changed seperately.
When adding a new layout the position and sizes will automatically be generated depending on the column count.
When adding a new item / dynamic section that will always be 1x1 on each layout and placed on the first available position.
#### Name
The name of the layout can be choosen freely. It is only used for the management and will not be visible on the board.
#### Column count
Amount of columns for this layout. Defines how many items can be placed in a row. When changed it will automatically adjust the position and size of the items.
#### Breakpoint
Minimum width of the screen where the layout will be used.
Once the minimum of the next layout is reached the layout will change.
#### Preview
<img src={layoutSmallImage} height={256} />
<img src={layoutMediumImage} height={256} />
<img src={layoutLargeImage} height={256} />
### Background
#### Background image URL
Homarr can display a background image behind apps and widgets.
This URL can be used to define what image should be shown.
#### Background image attachment
This defines whether the background should move when the user scrolls.
#### Background image size
This defines whether the background should cover the entire page (and possibly be cropped) or never be cropped but may not cover the entire page.
#### Background image repeat
This defines whether the background should be repeated if it cannot cover the entire page.
This option can be useful if you have patterns that can be repeated easily (e.g. patterns):
![](./img/background-repeat.png)
### Appearance
#### Primary color
Color that can be chosen freely to give accents to active elements.
#### Secondary color
Color that can be chosen freely to give accents.
#### Opacity
Opacity of the colors.
#### Icon color
Change the color of your bookmark / app icons.
<img src={iconColorImage} height={100} />
#### Item radius
Change the radius of your items / categories.
<img src={itemRadiusImage} height={100} />
### Custom CSS
This is the field where you can enter custom CSS.
The styling will only be applied on the respective board page.
[See this guide on how to work with custom CSS](/docs/advanced/styling/).
### Behaviour
#### Disable app status
This will disable the status check for apps.
### Access control
With the access control, you can permit a single user or a group to your board.
The users and groups can have one of these three levels of access:
| **Permission Level** | View board | Edit mode | Settings | Danger zone (eg. delete) |
| -------------------- | ---------- | --------- | -------- | ------------------------ |
| View board | X | | | |
| Modify board | X | X | X | |
| Full access | X | X | X | X |
The permission level can only be changed after adding the user / group:
![](./img/change-user-permission-level.png)
If the board is private and the user is not added in any of the three tabs, they cannot access the board.
They also do not see the board on the start page nor do they have access to any links for the board.
Groups that have high permissions (e.g. administrator or all board permissions) will be shown as "inherited".
They are permitted implicitly due to their permissions.
After editing permissions, the save button below the table must be pressed.
Otherwise, all changes will be discarded.
### Danger zone
#### Rename
Renaming a board will break all existing links to it permanently with no redirect.
#### Board visibility
By default, boards will be private. This means only authenticated users that are authorized have access.
Making a board public will expose it to everyone - including unauthenticated users.
#### Delete
This will permanently delete the board.
This action is irreversible and cannot be undone.
## Delete boards
The deletion of boards is permanent and cannot be undone.
There are two ways to delete a board:
- Navigate to the settings of your board, open the "Danger zone" section and click on the "delete this board" button.
- Navigate to the list of boards in the management pages, click the three dots and click on "delete permanently".
Both actions will execute the same deletion process.
## Duplicate boards
:::note
Duplicating a board will not copy the users and groups that have access to the board
nor the integrations the user does not have access to.
:::
Duplicating a board will create a new board with the same settings and layout as the original board.
You can duplicate a board by clicking on the three dots in the list of boards and selecting "Duplicate board".
![](./img/duplicate-board-modal.png)
## Setting boards as your home board
The home board is the dashboard, that will be shown at the root path of Homarr or if no board name was passed in the URL.
All the following paths will lead to the home board:
- `my-homarr.com`
- `my-homarr.com/boards`
Your home board will have a special small badge at the top right in the list of boards:
![](./img/home-board-flag.png)
### For yourself
To set the home board yourself, the easiest option is to set it directly in the list of boards:
![](./img/set-as-home-board-menu.png)
Alternatively, you can also define it via your user profile:
1. Click on your user profile at the top right
2. Click on `Your preferences`
3. Change the home board in the `home board` dropdown and click on `Save`.
### For other users
1. Navigate to the users: `Management` > `Users` > `Manage`
2. Click on the username of the user that you want to adjust
3. Select the desired home board via the dropdown and click on `Save` \
![](./img/set-home-board-other-user.png)
### For user groups
1. Navigate to the user groups: `Management` > `Users` > `Groups` > `Manage`
2. Go to tab `Settings`
3. Select the desired home board via the dropdown and click on `Save` \
![](./img/set-home-board-user-group.png)
### For whole server
You can also set a global home board that will be used for all users that have not set a home board themselves.
It will also be used for anonymous users.
1. Navigate to the settings: `Management` > `Settings` > `Boards`
2. Select the desired home board via the dropdown and click on `Save` \
![](./img/set-home-board-global.png)
:::note
For the global home board you can only select boards that are public.
:::
### Mobile home board
Same as the home board, you can also set a mobile home board.
It will be used for devices that are detected as mobile devices. (Using User-Agent header)
The add and edit dialogs use the target board section’s sizing and scale. Large widgets may be shrunk to fit the preview area; their content layout is preserved. Custom CSS that depends on dashboard ancestors may render differently inside the dialog.
@@ -7,44 +7,45 @@ tags:
---
# Certificates
On this page you can manage your trusted certificates.
On this page you can manage your trusted certificates.
For example if you use a self signed certificate for one of the integrations you want to connect, you can add it here.
Below you can see a screenshot of the certificates page.
The items show the subject, filename and when it expires.
Below you can see a screenshot of the certificates page.
The items show the subject, filename and when it expires.
The color of the icon indicates how long it is valid.
![](./img/screenshot.png)
![The Trusted certificates management page](../img/certificates.png)
| Color | Meaning |
| --- | --- |
| 🟩 Green | Valid for more than 30 days |
![Trusted certificates page listing a certificate's subject, filename, and expiry](./img/screenshot.png)
| Color | Meaning |
| --------- | --------------------------- |
| 🟩 Green | Valid for more than 30 days |
| 🟨 Yellow | Valid for less than 30 days |
| 🟧 Orange | Valid for less than a week |
| 🟥 Red | Valid for less than a day |
| 🟧 Orange | Valid for less than a week |
| 🟥 Red | Valid for less than a day |
## Opening the certificates page
Navigate to ``Management`` > ``Tools`` > ``Certificates``.
Navigate to `Management` > `Tools` > `Certificates`.
## Add a certificate
To add a certificate click on the "Add certificate" button.
![](./img/add-button.png)
To add a certificate click on the "Add certificate" button. The upload form expands directly on the certificates page.
Then select the certificate file you want to add.
![Add certificate button on the Trusted certificates page](./img/add-button.png)
![](./img/add-modal.png)
And click the "Add" button.
Then select the certificate file you want to add and click the "Add" button. You can cancel to collapse the form without
leaving the page.
## Delete a certificate
To delete a certificate you can click on the trash icon in the certificate card.
![](./img/card.png)
![Certificate card with subject, filename, expiry date, and delete action](./img/card.png)
Then confirm the deletion.
The first click arms the action and the second click confirms the deletion in place; no confirmation dialog is opened.
## Managing it through file system
@@ -52,21 +53,19 @@ The certificates are stored in the `/appdata/trusted-certificates` directory whi
This means you can automate the update of the certificates by simply replacing or adding a new file in the directory.
## Obtaining certificates
Every integration has its own way of obtaining certificates.
Generally it is recommended to search for the documentation of the integration you are using.
Most of the time you can find the certificate in the file system of the integration.
The certificate file needs to be uploaded to Homarr. To first get the file on your computer you can either:
- use `scp user@host:/path/to/file ./certificate.pem`
- use `cat /path/to/file` to print the certificate. Then recreate the file on your machine.
Below you can find instructions for some of the integrations.
### Pi-hole (v6)
Since version 6 of Pi-hole, the web interface can be accessed through HTTPS.
The certificate can be found in the path `/etc/pihole/tls_ca.crt`.
The certificate can be found in the path `/etc/pihole/tls_ca.crt`. To add the certificate, this file needs to be copied and uploaded to Homarr.
You can find more details regarding SSL / TLS for Pi-hole [here](https://docs.pi-hole.net/api/tls/).
### Proxmox
By default, Proxmox VE uses a node certificate signed by the cluster. You only need to configure Homarr with the certificate of a single node.
The certificate can be found in any node on the path `/etc/pve/pve-root-ca.pem`.
You can learn more about certificate management in Proxmox [here](https://pve.proxmox.com/wiki/Certificate_Management).
For the default Proxmox VE cluster certificates, trust the cluster CA from `/etc/pve/pve-root-ca.pem` on any node.
See [Proxmox certificate management](https://pve.proxmox.com/wiki/Certificate_Management).
@@ -0,0 +1,48 @@
# Connect an agent
An MCP-connected agent can validate, preview, test, and save Custom Widgets. The API key owner must be a Homarr
administrator.
Install the official skill:
```sh
npx skills add https://github.com/homarr-labs/homarr --skill homarr-custom-widget
```
The skill routes the agent to the release-matched schema, runtime, security, examples, and component metadata. It keeps
those references separate so the agent loads only what the current widget needs.
## MCP resources
- Prompt: `homarr-custom-widget-author`
- Skill: `homarr://custom-widgets/skill`
- References: `homarr://custom-widgets/references/{schema|runtime|security}`
- Schema: `homarr://custom-widgets/schema`
- Components: `homarr://custom-widgets/components` and `components/{name}`
- Examples: `homarr://custom-widgets/examples/{name}`
Equivalent HTTP resources are available under `/api/custom-widgets/` for authenticated administrators.
## Authoring lifecycle
1. Load the skill and only the references needed for the design.
2. Read the external API documentation and build the definition.
3. Create a preview from the complete definition; it validates both the manifest and JSX.
4. Run every returned query and simulate every relevant action against the current preview revision.
5. Inspect the preview and redacted journal. Revise the existing preview for JSX-only changes.
6. Save from the final tested preview.
7. Configure deployment-specific source URLs and credentials, then preview the saved definition again.
Use `templateLines` for multiline JSX tool input. A preview must have current evidence for every query and action before
it can be saved. Simulation counts as action evidence without performing the mutation.
Migration-only exports can return validated JSON without credentials. Authentication is preserved, and live testing
remains unverified until the administrator configures and tests the imported widget.
If the agent does not have a source URL or credential, it can request a short-lived Homarr configuration URL. An
authenticated administrator completes it in Homarr; the agent receives the status, never the plaintext credential.
Agents can also search, inspect, install, and configure existing Workshop widgets instead of regenerating them.
See [MCP](/docs/management/mcp) for client configuration and [requests and security](/docs/management/custom-widgets/requests-and-security) for the
runtime limits.
@@ -0,0 +1,30 @@
# Create a Custom Widget
The workbench provides editors for general metadata, API sources, requests, widget options, JSX, and preview data. Raw
JSON is available when direct editing is faster.
## Workflow
1. Configure each API source, network scope, authentication method, and credential.
2. Add named queries and actions. Values can reference widget options or invocation parameters.
3. Define widget options and their defaults.
4. Write JSX using `data`, `status`, `options`, and temporary `inputs`.
5. Run **Test and preview**, inspect the response data and redacted request journal, then save.
Changing the definition, options, or credentials invalidates the previous preview. Preview actions are simulated unless
**Run actions against the configured API** is enabled for that preview session.
Widget options support text, textarea, number, switch, select, multi-select, slider, date, time, color, icon, URL,
duration, time zone, and JSON controls. Dynamic choices can come from a load query.
See the [safe JSX runtime](/docs/management/custom-widgets/custom-jsx),
[component reference](/docs/management/custom-widgets/component-reference), and
[request reference](/docs/management/custom-widgets/requests-and-security) for the authoring contract.
## Create with another AI service
**Create or fix with any AI** copies a self-contained prompt for an ordinary ChatGPT or Claude conversation. The model
must return one fenced `json` block containing the complete definition. Paste that block into the workbench, add
credentials separately, and validate it against a real preview.
For an MCP-connected agent, use the [Homarr Custom Widget skill](/docs/management/custom-widgets/agent-authoring) instead.
@@ -0,0 +1,13 @@
---
title: Component reference
sidebar_position: 3
tags: [Custom Widgets, JSX, Mantine, Components]
---
import { CustomJsxComponentReference } from "@site/src/components/custom-jsx-component-reference";
# Custom JSX component reference
Search the components and properties exposed by Homarr's safe Custom JSX runtime. The live schema and diagnostics remain authoritative: properties marked as blocked cannot be passed from widget code, and denied components are shown only for explanation.
<CustomJsxComponentReference />
@@ -0,0 +1,76 @@
# Use the safe JSX runtime
Templates are JSX expressions interpreted inside a widget-local safety and render budget. They can read:
- `data.requestId` — the latest response
- `status.requestId` — `{ loading, ok, status, statusText, error }`
- `options.name` — saved widget configuration
- `inputs.name` — temporary values from declarative `bind`
The v2 manifest requires a `default` source and supports up to eight sources, 64 requests, and 64 options. Source IDs are
case-insensitively unique. Each request allows up to 32 static headers and 32 invalidation targets; a widget can contain
up to 24 secrets, each up to 8,192 characters, and templates are limited to 50,000 characters. Validation reports the
exact field when a limit is exceeded.
Authoring input accepts either `template` or `templateLines`, not both. `templateLines` accepts 1–2,000 lines, each up to
10,000 characters; after joining lines with newlines, the complete template must still fit the 50,000-character limit.
The safe interpreter also bounds JSX evaluation: AST depth 64, 25,000 operations, 4,000 collection items, 10,000 rendered
nodes, and 200,000 characters in one string or rendered value. API responses are bounded separately before they reach the
template.
Use normal Mantine layouts, typography, feedback, dates, and charts. Official compound names such as `Card.Section`, `Tabs.List`, and `Radio.Group` are supported. Ordinary safe props pass through; a dangerous capability produces an explicit error.
Unsafe URLs, callback props, and unapproved style properties are stripped. Response data is deep-sanitized and budgeted
before it reaches `data`, so treat it as untrusted input even when the source is private.
## Temporary inputs
```jsx
<Stack>
<TextInput bind="search" defaultValue="" label="Search" />
<Pagination bind="page" resetKey={inputs.search} defaultValue={1} total={5} />
<SubFetch requestId="search" trigger="manual" params={{ query: inputs.search, page: inputs.page ?? 1 }}>
{(results, meta) => (
<Stack>
{(results ?? []).map((item) => (
<Text key={item.id}>{item.name}</Text>
))}
</Stack>
)}
</SubFetch>
</Stack>
```
Bound values live only in React memory while the widget is mounted. They are not saved to the database, board options, exports, browser storage, or `localStorage`. Remounting resets them. Components can share a binding when their adapter types agree.
Bindable controls accept a scalar `resetKey`. When it changes, Homarr restores that control to its declared `defaultValue` or `defaultChecked` without running a request. This keeps dependent pagination correct while a manual `SubFetch` waits for the user to submit the new query.
## Expression language
Use expressions, conditionals, optional chaining, arrays, objects, template strings, safe standard helpers, and expression callbacks for `map`, `filter`, `sort`, and trusted runtime slots. Callback blocks, authored `const`, IIFEs, authored recursion, arbitrary functions, imports, hooks, refs, raw events, browser requests, `eval`, and bigint are blocked.
For user-facing timestamps, use the safe static helpers instead of `new Date` or an invented component. `Date.toLocaleString(value, "en-US", "UTC")` produces a concise absolute date and time for an explicitly labeled UTC value. `Date.toISOString`, `Date.toLocaleDateString`, and `Date.toLocaleTimeString` are also available.
Bounded regex literals are supported for string matching, splitting, search, and replacement. Regex literals are limited to
128 characters and flags `gimsu`; lookarounds, backreferences, repeated alternatives/groups, unsupported flags, and more
than one variable quantifier are rejected.
## Runtime components
- `SubFetch` runs a named query. Automatic queries run when the widget loads; set `trigger="manual"` to defer one and pass
primitive `params` for its invocation references. With `triggerContent`, any content node (commonly a card or image) becomes
the accessible click and keyboard trigger instead of showing the default load button.
- `SubFetch` with `trigger="manual"` keeps its result local to that instance; it does not populate the shared
`data.requestId` or `status.requestId` roots. The child callback receives `(result, meta)`, while loading, errors, and
retry are handled by `SubFetch`. Provide both `triggerContent` and `triggerAriaLabel` when custom content launches it.
- `SubFetch`, `ActionButton`, and `ToggleSwitch` require a quoted literal `requestId`. Independent JSX validation rejects
missing or computed IDs before a complete manifest or preview must be sent.
- `ActionButton` and `ToggleSwitch` run actions only when the widget is mounted outside edit mode. A toggle needs both
enabled and disabled request parameters and rolls back its visual state if the action fails.
- `RefreshButton` renders a compact, accessible icon control that invalidates the client&apos;s load-query cache so active load
queries can refetch. Set `requestId` inside a successful manual `SubFetch` result to rerun only that named query with the
same parameters. A targeted rerun respects an explicit request `cacheSeconds`; an untargeted button also clears the
widget&apos;s server cache. It is disabled when there is no active item/preview or while the board is in edit mode.
- `Icon`/`TablerIcon` resolves installed safe icons.
Always include responsive loading, empty, error, and success states. Runtime failures remain inside the widget tile.
@@ -1,208 +1,54 @@
---
tags:
- Custom Widgets
- API
- Widgets
- JSX
title: Custom Widgets
sidebar_label: Overview
tags: [Custom Widgets, API, JSX, MCP]
---
import { CustomWidgetFlowDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams";
# Custom Widgets
:::warning
A **Custom Widget** is a validated `homarr-custom-widget-v2` definition containing API sources, queries and actions,
optional settings, and a safe JSX template.
Custom widgets are a new feature. Share feedback, ask questions, and discuss ideas in our [GitHub Discussions](https://github.com/homarr-labs/homarr/discussions/categories/custom-widgets).
Homarr executes requests on the server and renders the template in a restricted runtime. Source credentials are
encrypted separately and are not included in exports, prompts, browser data, or Workshop submissions.
:::
<CustomWidgetFlowDiagram />
Custom widgets allow you to fetch data from any HTTP API and display it on your Homarr dashboard. You define the API endpoint, authentication, and how the response should be rendered - no code compilation or server restart required.
![The Custom Widgets management page](../img/custom-widgets.png)
## Creating a Custom Widget
## Manage Custom Widgets
To create a custom widget, navigate to the **Custom Widgets** section in the management sidebar and click the **Add** button. Fill in the configuration:
Administrators can create, import, duplicate, enable, export, publish, and delete definitions under
**Management → Custom Widgets**. Adding or configuring one on a board also requires permission to modify that board.
Use **Actions → Configure sources** to update deployment-specific URLs, network access, and encrypted credentials
without reopening the authoring workbench.
- **Name** - Display name shown in the widget picker and on the dashboard
- **Description** - Optional description shown in tooltips and management UI
- **Icon URL** - Optional URL to an icon image for the widget
- **URL** - The API endpoint to fetch data from (must include protocol, e.g. `https://api.example.com/stats`)
- **Authentication** - How the API request is authenticated:
- `none` - Public APIs with no authentication
- `bearer` - Bearer token authentication
- `basic` - HTTP Basic auth (username + password)
- `apiKeyHeader` - API key sent as a custom HTTP header
- `apiKeyQuery` - API key sent as a query parameter
- **Header Name** - Custom header or query parameter name for API key auth (e.g. `X-API-Key`)
- **HTTP Method** - `GET`, `POST`, `PUT`, `PATCH`, or `DELETE`
- **Request Body** - JSON string body for `POST`/`PUT`/`PATCH` requests
- **Display Type** - How the API response is rendered (see below)
Once placed, normal board permissions control rendering and requests. Queries can run for anonymous viewers on public
boards; actions require authentication and the permission declared by the request.
## Display Types
## Authoring
| Display Type | Description | Best For |
| -------------------- | ---------------------------------------------------- | ---------------------------------------- |
| **Single Value** | Extracts a single value with a label and unit | Metrics: temperature, uptime, user count |
| **Key Value** | Multiple labeled key-value pairs with optional units | System stats: CPU, memory, disk |
| **Table** | API array data rendered as a sortable table | Lists of items with columns |
| **Stat Grid** | Labeled values in colored stat cards | Counts: movies, series, albums |
| **Progress Bars** | Values as progress bars with percentages | Usage: disk, quota, capacity |
| **Status Indicator** | Green/red status dots for health checks | Service monitoring |
| **Count Grid** | Simple counts in a grid (no colors) | Library counts |
| **Raw** | Pretty-prints the raw JSON response | Debugging |
| **Action Button** | Clickable button executing the API request | Triggers: restart, clear cache |
| **Custom JSX** | Custom JSX template with Mantine v9 components | Full layout control |
- [Create a Custom Widget](/docs/management/custom-widgets/authoring) in the workbench or from a copied AI prompt.
- [Use the safe JSX runtime](/docs/management/custom-widgets/custom-jsx) for data bindings, temporary inputs, and components.
- [Browse the component reference](/docs/management/custom-widgets/component-reference).
- [Configure requests and security](/docs/management/custom-widgets/requests-and-security).
- [Connect an agent](/docs/management/custom-widgets/agent-authoring) through MCP and the Homarr skill.
- [Troubleshoot a definition](/docs/management/custom-widgets/troubleshooting).
### AI-Powered JSX Generation
The workbench validates the same schema used by imports, Workshop, HTTP authoring resources, and MCP. Test every query
and simulate relevant actions before saving. Live preview actions are opt-in because they can change the source service.
When editing or creating a custom widget with the **Custom JSX** display type, you'll find a **Copy Prompt** button. Clicking it copies a pre-formatted prompt describing your widget's name, API endpoint, and available Mantine components. Paste this into your preferred AI assistant (ChatGPT, Claude, Copilot, etc.) to generate a JSX template tailored to your data.
## Import and Workshop
<details>
<summary>Example: Pokédex widget using Custom JSX</summary>
Use **Import from Workshop** while adding board content or import a v2 JSON definition directly. Review the source,
requested permissions, API hosts, and actions before installation, then configure deployment-specific URLs and
credentials in Homarr.
```json
{
"$schema": "homarr-custom-widget-v2",
"name": "Pokédex",
"description": "Browseable Pokémon list",
"iconUrl": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/items/poke-ball.png",
"url": "https://pokeapi.co/api/v2/pokemon?limit=75",
"authType": "none",
"method": "GET",
"displayType": "customJsx",
"displayConfig": {
"type": "customJsx",
"template": "<Stack gap=\"md\" p=\"xs\">\n <Card withBorder radius=\"xl\" p=\"md\" shadow=\"md\">\n <Group justify=\"space-between\">\n <Title order={3}>Pokédex</Title>\n </Group>\n </Card>\n <PaginatedList pageSize={12}>\n <Grid gutter=\"sm\">\n {data.results.map((pokemon, i) =>\n <Grid.Col span={1.5}>\n <Anchor href={pokemon.url} target=\"_blank\" underline=\"never\">\n <Card withBorder radius=\"xl\" p=\"xs\" shadow=\"md\">\n <Stack gap=\"sm\" align=\"center\">\n <Group justify=\"space-between\" style={{ width: \"100%\" }}>\n <Badge size=\"sm\" color=\"red\">#{i + 1}</Badge>\n <Text fw={800} tt=\"capitalize\">{pokemon.name}</Text>\n </Group>\n <Avatar\n src={\"https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/\" + (i + 1) + \".png\"}\n size={92}\n radius=\"xl\"\n />\n </Stack>\n </Card>\n </Anchor>\n </Grid.Col>\n )}\n </Grid>\n </PaginatedList>\n</Stack>"
}
}
```
Legacy definitions show **Migration required**. The migration prompt preserves the original template and API contract
while excluding credentials. Import the returned v2 definition and verify it before removing the archived version.
Missing credentials do not block a validated portable migration export; configure them after import and verify live data.
</details>
## Importing and Exporting
Custom widgets can be exported and imported as JSON files. To export, select the widget in the list and click the export button. To import, click the import button and paste the JSON. Secrets (API keys, passwords) are never included in exports and must be configured after import.
The import format uses `"$schema": "homarr-custom-widget-v2"` to identify the widget version.
## Available Mantine Components for Custom JSX
When using the `customJsx` display type, your template has access to a whitelist of [Mantine v9](https://mantine.dev) components. Unrecognized components, event handlers, and dangerous tags are stripped for security.
### Layout
| Component | Doc |
| ------------------- | --------------------------------------------- |
| `Stack` | [docs](https://mantine.dev/core/stack) |
| `Group` | [docs](https://mantine.dev/core/group) |
| `Flex` | [docs](https://mantine.dev/core/flex) |
| `Grid` / `Grid.Col` | [docs](https://mantine.dev/core/grid) |
| `SimpleGrid` | [docs](https://mantine.dev/core/simple-grid) |
| `Center` | [docs](https://mantine.dev/core/center) |
| `Container` | [docs](https://mantine.dev/core/container) |
| `Space` | [docs](https://mantine.dev/core/space) |
| `AspectRatio` | [docs](https://mantine.dev/core/aspect-ratio) |
### Typography & Content
| Component | Doc |
| ----------------- | ------------------------------------------------- |
| `Text` | [docs](https://mantine.dev/core/text) |
| `Title` | [docs](https://mantine.dev/core/title) |
| `Code` | [docs](https://mantine.dev/core/code) |
| `Highlight` | [docs](https://mantine.dev/core/highlight) |
| `Mark` | [docs](https://mantine.dev/core/mark) |
| `Kbd` | [docs](https://mantine.dev/core/kbd) |
| `Blockquote` | [docs](https://mantine.dev/core/blockquote) |
| `Anchor` | [docs](https://mantine.dev/core/anchor) |
| `NumberFormatter` | [docs](https://mantine.dev/core/number-formatter) |
### Data Display
| Component | Doc |
| ------------------------- | ------------------------------------------------- |
| `Badge` | [docs](https://mantine.dev/core/badge) |
| `Card` / `Card.Section` | [docs](https://mantine.dev/core/card) |
| `Paper` | [docs](https://mantine.dev/core/paper) |
| `Alert` | [docs](https://mantine.dev/core/alert) |
| `ThemeIcon` | [docs](https://mantine.dev/core/theme-icon) |
| `ColorSwatch` | [docs](https://mantine.dev/core/color-swatch) |
| `Avatar` / `Avatar.Group` | [docs](https://mantine.dev/core/avatar) |
| `Image` | [docs](https://mantine.dev/core/image) |
| `BackgroundImage` | [docs](https://mantine.dev/core/background-image) |
| `Indicator` | [docs](https://mantine.dev/core/indicator) |
| `Pill` | [docs](https://mantine.dev/core/pill) |
| `Spoiler` | [docs](https://mantine.dev/core/spoiler) |
### Tables
| Component | Doc |
| --------------------------------------- | -------------------------------------- |
| `Table` / `Table.Thead` / `Table.Tbody` | [docs](https://mantine.dev/core/table) |
| `Table.Tr` / `Table.Th` / `Table.Td` | [docs](https://mantine.dev/core/table) |
### Lists
| Component | Doc |
| ---------------------------- | ----------------------------------------- |
| `List` / `List.Item` | [docs](https://mantine.dev/core/list) |
| `Timeline` / `Timeline.Item` | [docs](https://mantine.dev/core/timeline) |
### Feedback & Loading
| Component | Doc |
| ------------------------------- | ---------------------------------------------- |
| `Progress` / `Progress.Section` | [docs](https://mantine.dev/core/progress) |
| `RingProgress` | [docs](https://mantine.dev/core/ring-progress) |
| `Skeleton` | [docs](https://mantine.dev/core/skeleton) |
| `Loader` | [docs](https://mantine.dev/core/loader) |
### Navigation & Overlay
| Component | Doc |
| ------------------------------------------------------------------------ | -------------------------------------------- |
| `TabsContainer` / `TabPanel` | Custom interactive component |
| `Accordion` / `Accordion.Item` / `Accordion.Control` / `Accordion.Panel` | [docs](https://mantine.dev/core/accordion) |
| `ScrollArea` | [docs](https://mantine.dev/core/scroll-area) |
| `Tooltip` | [docs](https://mantine.dev/core/tooltip) |
### Charts
| Component | Doc |
| ---------------- | --------------------------------------------------- |
| `AreaChart` | [docs](https://mantine.dev/charts/area-chart) |
| `BarChart` | [docs](https://mantine.dev/charts/bar-chart) |
| `LineChart` | [docs](https://mantine.dev/charts/line-chart) |
| `DonutChart` | [docs](https://mantine.dev/charts/donut-chart) |
| `PieChart` | [docs](https://mantine.dev/charts/pie-chart) |
| `RadarChart` | [docs](https://mantine.dev/charts/radar-chart) |
| `RadialBarChart` | [docs](https://mantine.dev/charts/radial-bar-chart) |
| `Sparkline` | [docs](https://mantine.dev/charts/sparkline) |
### Interactive Components
| Component | Description |
| --------------- | ---------------------------------------- |
| `PaginatedList` | Client-side pagination wrapper |
| `Collapsible` | Expandable/collapsible section |
| `StatBar` | Horizontal stat bar |
| `TypeBadge` | Type-styled badge |
| `Divider` | [docs](https://mantine.dev/core/divider) |
## Template Bindings
Your template receives:
- `data` - The sanitized API response object. Access fields via `data.fieldName` or `data.results[0].name`.
- `String(v)` - Type-safe string conversion
- `Number(v)` - Type-safe number conversion
- `Boolean(v)` - Type-safe boolean conversion
- `Math` - Safe subset: `round`, `floor`, `ceil`, `abs`, `min`, `max`, `pow`, `sqrt`, `PI`
- `JSON.stringify(v)` - JSON serialization
- `Array.isArray(v)` - Array type check
- `Object.keys(v)`, `Object.values(v)`, `Object.entries(v)` - Object utilities
## Security Constraints
- Event handlers (`onClick`, `onChange`, etc.) are stripped
- Dangerous HTML attributes (`dangerouslySetInnerHTML`) are stripped
- `script`, `iframe`, `object`, `embed`, `form`, `style`, `link`, `meta`, `base` tags are forbidden
- Template strings containing `eval`, `Function`, `import`, `require`, `globalThis`, `window`, `document`, `fetch` are rejected
- Anchor `href` attributes are validated to only allow `https://`, relative (`/`), and hash (`#`) URLs
Keep `SECRET_ENCRYPTION_KEY` unchanged when updating Homarr so existing credentials remain readable. Multi-replica
installations must use the same Redis service so cached responses invalidate consistently.
@@ -0,0 +1,12 @@
{
"title": "Custom Widgets",
"pages": [
"index",
"authoring",
"agent-authoring",
"custom-jsx",
"component-reference",
"requests-and-security",
"troubleshooting"
]
}
@@ -0,0 +1,91 @@
# Configure requests and security
Most widgets use a single source named `default`; the manifest must contain it. Extra keyed sources are available for widgets
that combine APIs. Source IDs are case-insensitively unique. Base URLs must use HTTP(S), contain no embedded credentials,
query string, or fragment, and sources can be `public`, `private`, or `loopback`. Authentication is `none`, `bearer`,
`basic`, an API-key header, or an API-key query parameter. HTTP source credentials belong to the widget but remain outside its manifest.
Source origins are fixed by the definition and source-setup flow; widget options and invocation parameters cannot redirect a
request to a different origin.
## Existing integrations
Available types come from Homarr's integration registry. Saved credentials are applied by the integration's authentication
contract, including services that require a login session. **iCalendar feeds (iCal)** are calendar URLs rather than arbitrary
service APIs, and **TrueNAS uses a WebSocket API**; neither appears as a generic HTTP source. qBittorrent requires a saved
API key and qBittorrent 5.2.0 or newer; saved username/password credentials cannot authenticate generic requests. UniFi
generic requests require an HTTPS saved URL with the controller's actual port.
```json
{
"sources": { "default": { "type": "integration", "integrationKind": "sonarr" } },
"requests": { "queue": { "path": "/api/v3/queue" } }
}
```
Select the local instance during source setup. Homarr uses its current URL, API key, and trusted certificates;
paths append to the saved URL, including reverse-proxy subpaths. Changing the integration updates all sources bound to it.
Deleting it leaves the widget unconfigured until another instance is selected. The binding is shared by every placement
of that widget definition. Exports and Workshop submissions retain the required type and omit the local integration ID.
Arbitrary integration requests require integration `full` access, including GET requests: service APIs can expose credentials or change state through reads. Board permissions still apply separately. Requests inherit saved authentication unless `auth: "none"` explicitly disables it. Credentials used for authentication are redacted from upstream responses. Non-GET integration requests must be actions. Requests stay within the configured URL path; authenticated requests do not follow redirects.
## Named requests
Requests are keyed by ID. `source`, `kind`, `method`, `trigger`, `auth`, and `permission` have sensible defaults, so a load query can be as small as:
```json
{ "status": { "path": "/api/status" } }
```
The request `path` is appended to the source `baseUrl`, including a base path such as `/api/v2`.
For HTTP sources, GET, POST, PUT, and PATCH work for queries and actions. Integration queries use GET. DELETE is restricted to actions so it can never run while a
board loads. Kind controls the remaining behavior: load queries run automatically, manual queries run through
`SubFetch`, and actions run only from `ActionButton` or `ToggleSwitch`.
Bind values directly where they are used:
```json
{
"containers": {
"path": "/api/endpoints/{option:endpointId}/docker/containers/json",
"query": { "all": { "$option": "showAll" } }
},
"restart": {
"kind": "action",
"method": "POST",
"path": "/api/endpoints/{option:endpointId}/docker/containers/{param:id}/restart",
"invalidates": ["containers"]
}
}
```
`{option:name}` and `$option` read saved widget options. `{param:name}` and `$param` read invocation-time `params`. Load queries cannot use invocation parameters. Homarr infers the exact parameter names and primitive values from these references, rejecting missing or extra invocation params at the request boundary.
Path placeholders and query values must resolve to text, numbers, or booleans. `$option` and `$param` references may appear
recursively in JSON bodies; invocation parameters remain primitive, and load queries cannot use `$param`. JSON bodies can
also use structured `json` and `multiSelect` option values, for example `{ "entity_ids": { "$option": "entities" } }`.
## Protection
Every request uses Homarr's existing server executor: same-origin source enforcement, network scope, DNS and redirect validation, SSRF protection, board permissions, rate and request limits, body and response limits, timeouts, and encrypted credential injection. Static headers cannot override credentials, cookies, routing, proxy, forwarding, or hop-by-hop headers.
The executor caps request bodies at 10 KiB and response bodies at 1 MiB. Parsed JSON is limited to depth 32 and 50,000 nodes;
each network hop has a ten-second timeout, unauthenticated queries follow at most three same-origin redirects, actions and authenticated queries do not follow redirects,
and the total request deadline is 45 seconds.
The limiter allows four concurrent requests per user/item and eight per definition. Per minute, a user/item can make up to 60
queries, 10 actions, or 3 DELETE actions; a definition can receive up to 240, 40, or 12 of those request categories.
Integration metadata refreshes have a separate allowance of 60 per user/item and 240 per definition per minute, and share
the same concurrency limits.
Queries default to view permission and actions to modify. DELETE always requires full permission and confirmation. Actions are never cached, retried, or run on load.
Management and runtime are intentionally separate. A Homarr administrator with board-modify permission places and
configures the widget. After placement, query and action authorization follows the request's board permission. Public
boards may execute HTTP-source queries for anonymous viewers; integration sources require an authenticated viewer with full integration access. Mutations stay authenticated. This includes shared-cache
invalidation: `RefreshButton` is disabled only without an active item or preview session, or in edit mode, while ordinary
scheduled query rendering remains available to anonymous viewers.
Responses use bounded, versioned shared-Redis cache keys. Action invalidation advances the shared version so every
Homarr replica stops serving the previous response without scanning or deleting a key prefix.
@@ -0,0 +1,58 @@
# Custom Widget troubleshooting
## Definition problems
| Symptom | Resolution |
| ------------------------ | ---------------------------------------------------------------------------------------------------------- |
| Definition unavailable | Restore or recreate the definition, or remove the unavailable board item. |
| **Migration required** | Copy the migration prompt, describe the visible behavior without secrets, and import the returned v2 JSON. |
| Invalid saved definition | Read the displayed schema errors, then recreate or import a valid definition. |
| Invalid item options | Open the board item's settings and correct values that no longer match the definition. |
Migrating a v1 definition keeps the archived v1 record and encrypted secret for rollback. The migrated v2 definition
uses the same ID and takes precedence.
## Validation errors
Start with the first diagnostic and its field path. Common causes are:
- invalid or duplicate source, request, or option IDs;
- a request referencing a missing source;
- an option default that does not match its control;
- `{param:name}` in a load query;
- missing invocation parameters;
- an invalid source or icon URL;
- a runtime component using the wrong request kind.
The Diagnostics tab also shows JSX errors, accessibility checks, and the redacted request journal.
## Request errors
Check the source URL, network scope, authentication, request method, path, body bindings, and board permission. The
journal records the request ID, method, path template, status, and duration without credentials.
For `invalid placeholder`, use `{option:name}` or `{param:name}`. Load queries can reference options only.
In multi-replica deployments, connect every Homarr replica to the same Redis database. Otherwise an action can leave a
stale cached query on another replica.
## Runtime warnings
`UNKNOWN_MANTINE_PROP` means the installed Mantine component does not document that property. Check the
[component reference](/docs/management/custom-widgets/component-reference). `BLOCKED_CAPABILITY` means the runtime rejected an unsafe component,
property, URL, or style capability.
## Workshop unavailable
Check `WORKSHOP_API_URL` and PocketBase health. Installed widgets continue to run without Workshop.
## Rollback
Preserve a database backup and the exact `SECRET_ENCRYPTION_KEY`. Roll back the Homarr application without manually
removing the v1 tables. Workshop's PocketBase data has a separate backup lifecycle.
## Report a bug
Use the [Custom Widget bug form](https://github.com/homarr-labs/homarr/issues/new?template=custom_widget_bug.yml)
with a minimal exported definition and sanitized request diagnostics. Remove credentials, private URLs, and personal data
from exports, responses, logs, and screenshots before sharing.
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

+82
View File
@@ -0,0 +1,82 @@
---
title: Manage Homarr
description: Configure boards, content, access, automation, and server-wide behavior.
---
import {
IconApi,
IconApps,
IconCertificate,
IconChecklist,
IconComponents,
IconDatabaseExport,
IconLayoutDashboard,
IconLogs,
IconPhoto,
IconPlugConnected,
IconRobot,
IconSearch,
IconSettings,
IconTerminal2,
IconUsers,
} from "@tabler/icons-react";
## Everyday configuration
<Cards>
<Card icon={<IconLayoutDashboard />} title="Boards" href="/docs/management/boards">
Create, organize, share, and configure boards.
</Card>
<Card icon={<IconApps />} title="Apps" href="/docs/management/apps">
Add the services and links shown on boards.
</Card>
<Card icon={<IconPlugConnected />} title="Integrations" href="/docs/management/integrations">
Configure reusable service connections.
</Card>
<Card icon={<IconUsers />} title="Users and groups" href="/docs/management/users">
Control access and permissions.
</Card>
<Card icon={<IconSettings />} title="Settings" href="/docs/management/settings">
Change server and user preferences.
</Card>
</Cards>
## Content and extensions
<Cards>
<Card icon={<IconPhoto />} title="Media" href="/docs/management/media">
Manage uploaded assets.
</Card>
<Card icon={<IconSearch />} title="Search engines" href="/docs/management/search-engines">
Configure search shortcuts.
</Card>
<Card icon={<IconComponents />} title="Custom Widgets" href="/docs/management/custom-widgets">
Build Custom JSX widgets.
</Card>
<Card icon={<IconRobot />} title="Assistant" href="/docs/management/assistant">
Configure Homarr's assistant features.
</Card>
</Cards>
## Operations
<Cards>
<Card icon={<IconApi />} title="API" href="/docs/management/api">
Configure API keys and use the generated reference.
</Card>
<Card icon={<IconTerminal2 />} title="Model Context Protocol" href="/docs/management/mcp">
Connect external assistants to Homarr.
</Card>
<Card icon={<IconChecklist />} title="Tasks" href="/docs/management/tasks">
Inspect scheduled and background tasks.
</Card>
<Card icon={<IconLogs />} title="Logs" href="/docs/management/logs">
Inspect application logs.
</Card>
<Card icon={<IconCertificate />} title="Certificates" href="/docs/management/certificates">
Trust certificates used by connected services.
</Card>
<Card icon={<IconDatabaseExport />} title="Backups" href="/docs/management/backup">
Export and restore Homarr data.
</Card>
</Cards>
@@ -5,94 +5,73 @@ tags:
- Connections
---
import { IntegrationRoutesDiagram } from "@site/src/components/pages/core-concepts/technical-diagrams";
# Integrations
Integrations are connections to supported third party applications.
This page will describe the process of managing integrations but the process may vary depending on your specific integration.
Check [the available integrations](/docs/category/integrations) for further information.
## Create an integration
To create an integration, you can choose the supported application from the dropdown at the top right:
An **integration** is a server-side connection from Homarr to a supported service. Integrations provide data and
actions to widgets and can be linked to apps.
![](./img/create-integration-dropdown.png)
![The integration catalog](../img/integrations-catalog.png)
Next, you'll need to fill out the required fields to configure the integration:
See the [integration catalog](/docs/integrations) for service-specific URLs, credentials, and supported
widgets.
![](./img/form-create-integration.png)
## Beyond native widgets
### Name
Must be at least 1 character long, can be chosen freely.
<Alert type="tip" title="Homarr is the front door to your homelab">
### Url
This must be the base URL of the application where Homarr should connect to.
A few examples for this field include:
- http://sabnzbd.example.com
- https://example.com/sabnzbd
Configure a supported service once, then use its API through MCP and bring its data or actions onto your dashboard
with Custom Widgets—even when Homarr has no native feature for it.
You must not append any path after the base URL. Some examples for incorrect usage:
- http://sabnzbd.example.com/settings
- https://example.com/sabnzbd/settings
</Alert>
### Secrets
An integration may or may not require secrets to function.
To process to obtain them is usually [documented in the integration pages](/docs/category/integrations).
Secrets are encrypted using a symmetric encryption and stored in the database.
To improve security, they will never be passed to the client and requests to the integrations are performed from the host where Homarr is running on.
Have your agent consult the service’s API docs and test the endpoint through [`integration_request`](../mcp#authenticated-integration-requests),
Homarr's most powerful MCP tool. Then bind the same saved integration to a
[Custom Widget source](../custom-widgets/requests-and-security#existing-integrations) to display its data or run actions.
Both reuse saved credentials and require **full integration access**. The iCalendar feed integration and TrueNAS's WebSocket
API cannot be used through these generic HTTP requests.
### Linking applications
## Browser and server routes
During the creation of an integration you can choose to add / link an application to the integration.
If you want to add one, you can simply specify the app url which will be used for opening the application from Homarr.
The linked application will also be used for any links the integration widget contains.
If you already have an application created, you can also link it to the integration by selecting it from the dropdown.
On the edit page you can always change or remove the linked application.
<IntegrationRoutesDiagram />
### Testing and saving integration
It is not allowed to create an integration without passing the test.
This is to ensure that you minimize the amount of broken applications on your Homarr instance.
The test and create button will perform a network request to the application and authenticate if required.
## Configuration
## Managing permissions
Create and manage integrations under **Management → Integrations**. Select a service, provide its base URL and required
credentials, then test the connection. Homarr does not save a new integration until the test succeeds.
On the edit page of an integration, you can manage which users / groups can
Use a URL reachable from the Homarr server or container. Unless an integration page says otherwise, provide the service
root rather than a settings or API subpage.
- **Select the integration in items:** Allows users to select the integration and showing data on their board.
- **Interact with the integration:** Allows users to perform actions on the integration, such as pausing a download.
- **Full control over the integration:** Allows users to modify the integration properties, including the URL and secrets.
Credentials are encrypted and used only by the server. Linking an app is optional; it provides the browser-facing URL
used by widgets that open the service.
![](./img/integration-permissions.png)
![Creating an integration with a server URL, API key, and linked app](./img/form-create-integration.png)
## Troubleshooting connection
The connection to your integrations can fail due to many factors. Most of the time it should show you the reason why it failed.
If it doesn't, you can follow these steps to troubleshoot the issue:
Integrations can also be created while adding content to a board. Editing a connection from a widget updates that
integration everywhere it is used.
1. Check whether you are using the correct URL and secrets.
- The URL must be the base URL of the application, **without any paths**.
- The secrets must be correct and have the correct permissions.
2. If you use https to connect to the application, check the chapter below about [certificate issues](#certificate-issues).
3. Check whether you followed the Homarr documentation and didn't skip any steps.
This is the most often mistake that create many noisy support requests and following all steps will often resolve the problems.
4. Check Homarr's logs for more information. As we have no control over breaking changes in upstream APIs and third party software,
they can break without notice in unexpected ways which can also lead to errors within Homarr. In such case, these occurrences must be reported
and fixed within the source code of Homarr.
5. Check whether the host can reach the destination hostname / IP using ``ping`` and ``curl`` or ``wget`` afterward.
Execute this command on the host machine, not inside containers, to check whether it can connect or not.
6. Check whether the container / pod can reach the destination hostname / IP. Execute the same commands in the shell inside the container / pod.
7. Check your reverse proxy / authentication proxy logs for failures / hints
8. Check your security log of tunnels and VPNs
9. Check your router for security events
10. Check your VLAN configuration and firewall rules
11. Check your DNS settings for the host machine and the containers / pods and whether they can resolve the hostnames
12. Check throughput and stability of your network connection using ``iperf3``
13. Check syslog / drivers of your OS for hints
14. Check logs of your destination applications (eg. SABnzbd)
15. Attempt to disable CSRF / tamper protections when absolutely no other workaround available -> this comes with some security implications - be careful!
Re-enable if this didn't fix the issue.
## Permissions
If none of these troubleshooting steps worked, you can request support from our team in Discord or GitHub.
| Level | Allows |
| -------- | ------------------------------------------------------------ |
| Use | Select the integration and read its data |
| Interact | Run supported actions, such as pausing a download |
| Full | Change integration settings and call arbitrary API endpoints |
### Certificate issues
![Per-integration access for users and groups](./img/integration-permissions.png)
If you are using a self-signed certificate you'll need to add it to the [trusted certificates](../certificates) in Homarr.
Most of the time you should also get a button to add the certificate automatically when you try to connect to the integration.
Please check that the certificate is the one you are expecting to prevent Man in the Middle attacks.
For some integrations, you can find a guide on how to retrieve the certificate [here](../certificates/#obtaining-certificates).
Global integration permissions apply to every integration. Resource access can instead be granted to specific users
or groups. Lists are filtered on the server and only include connections the current user can manage.
## Connection problems
If a connection test fails:
1. Check the integration page for the required base URL and credentials.
2. Test name resolution and HTTP access from the Homarr container or pod, not only from the host or browser.
3. Check Homarr and upstream-service logs, then any reverse proxy, firewall, VLAN, VPN, or DNS between them.
4. For a self-signed certificate, add the expected certificate under [Certificates](/docs/management/certificates).
Do not disable upstream security controls as a general troubleshooting step.
+36
View File
@@ -0,0 +1,36 @@
---
tags:
- Administration
- Logs
- Troubleshooting
---
# Logs
The logs page shows recent Homarr application logs and continues updating as new events occur. Use it to investigate
widget, integration, and server errors without opening the container logs separately.
![The live Logs management page](../img/logs.png)
## Opening the logs page
Navigate to **Management** > **Tools** > **Logs**. The page and widget log links are only available to users with the
**View logs** permission.
When a widget reports an error, **Check logs for more details** opens the logs page in a new tab and marks the time when
the widget displayed the error. The related server error normally appears immediately above that marker. If those logs
have already been removed from the retained history, the marker explains that they are no longer available.
## Retained and live logs
Homarr retains the latest 5,000 log events in Redis. Opening the page first loads this history and then continues with
live events without a gap. The history is bounded, so older events are removed automatically.
The history survives normal application restarts when the configured Redis instance persists its data. For complete
platform-level history, startup failures, or events older than the retained limit, use the logs provided by Docker or
your deployment platform.
## Display controls
The severity selector applies to both retained and live events. Selecting a different level redraws the existing view
using that threshold. The font-size control changes the terminal text size and is remembered in the browser.
+67 -111
View File
@@ -8,160 +8,116 @@ tags:
# Model Context Protocol (MCP)
Homarr exposes a [Model Context Protocol](https://modelcontextprotocol.io) server at `/api/mcp/mcp`, enabling AI assistants like Claude, Cursor, VS Code Copilot, and Claude Code to interact with your Homarr instance using natural language.
Connect an AI client to Homarr to manage boards, apps, integrations, and other services through MCP tools.
With MCP, you can ask your AI assistant to manage apps, integrations, users, boards, Docker containers, media servers, DNS settings, and more - all through Homarr's existing tRPC API, now exposed as 50+ AI-callable tools.
Homarr uses MCP v2 (protocol `2026-07-28`) at `/api/mcp`, with compatibility for 2025 Streamable HTTP clients.
Requests are stateless: each request authenticates independently, without an MCP session ID.
## Getting Started
<Alert type="tip" title="Homarr's most powerful MCP tool">
The MCP endpoint lives under the **API** page at `Management` → `Tools` → `API` → **MCP** tab.
[`integration_request`](#authenticated-integration-requests) calls any API endpoint on supported saved integrations using their configured
credentials. Features missing from Homarr can still be available through MCP when the integration’s API supports them.
![MCP Instructions Page](./api/img/mcp-instructions.png)
</Alert>
### 1. Create an API Key
![The AI / MCP management tab](./img/mcp.png)
Navigate to the **Authentication** tab in the API page and create an API key. API keys follow the format `<id>.<token>`.
You can also create one directly from the MCP tab if you don't have any keys yet.
## Connect a client
### 2. Choose a Transport
| Transport | Best For | Requirements |
| ------------------- | ------------------------------------------------------------ | ------------------------------ |
| **Streamable HTTP** | Cursor, Claude Desktop, VS Code Copilot, Claude Code | Direct HTTP access to Homarr |
| **STDIO** | Firewall-restricted environments, offline-compatible clients | `npx` and `mcp-remote` package |
**Streamable HTTP** is recommended for most setups. It works with all major AI clients.
### 3. Configure Your Client
Add the following to your client's MCP configuration file:
**Streamable HTTP** (recommended):
Create an API key under **Management → Tools → API → Authentication**. Add this configuration to your client,
replacing the URL and API key:
```json
{
"mcpServers": {
"homarr": {
"url": "https://your-homarr-instance.com/api/mcp/mcp",
"url": "https://homarr.example.com/api/mcp",
"headers": {
"ApiKey": "<your-api-key>"
"ApiKey": "<id>.<token>"
}
}
}
}
```
Where to place this config:
Use the complete key, including the ID, dot, and token. Keep it private and use HTTPS for remote connections.
The **AI / MCP** tab on Homarr's API page provides your endpoint, configuration, and available tools.
| Client | Config File |
| --------------- | ----------------------------------------------- |
| Cursor | `.cursor/mcp.json` |
| Claude Desktop | `claude_desktop_config.json` |
| Claude Code | `.claude/mcp.json` (or `claude mcp add homarr`) |
| VS Code Copilot | `.vscode/mcp.json` |
:::warning
Replace `<your-api-key>` with your actual API key. Never commit API keys to version control.
:::
**STDIO** (alternative):
For clients that only support STDIO, use `mcp-remote`:
```json
{
"mcpServers": {
"homarr": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://your-homarr-instance.com/api/mcp/mcp",
"--header",
"ApiKey:<your-api-key>"
]
"args": ["-y", "mcp-remote", "https://homarr.example.com/api/mcp", "--header", "ApiKey:<id>.<token>"]
}
}
}
```
This option tunnels MCP communication through STDIO using the `mcp-remote` package. Useful when the AI client cannot make HTTP requests directly.
### OAuth
## Authentication
Clients with OAuth support can authorize through OAuth 2.1 with PKCE instead of an API key.
Homarr publishes discovery metadata under `/.well-known/`.
MCP supports two authentication methods:
If your reverse proxy does not preserve the public host and protocol, set `BASE_URL` to your public origin,
such as `https://homarr.example.com`, without a path.
| Method | Description | Best For |
| -------------------- | ----------------------------------------------------- | ---------------------------------------------------------------- |
| **API Key** | Include `ApiKey: <id>.<token>` header in all requests | Scripts, CI/CD, direct client configs |
| **OAuth 2.1 + PKCE** | Full OAuth flow with dynamic client registration | MCP clients with OAuth support (e.g. `opencode mcp auth homarr`) |
## Permissions and tools
API key authentication is simpler and recommended for most setups. The API key inherits the permissions of the user who created it. Tools that require higher privileges will return permission errors if the key lacks access.
Tools use the permissions of the API key owner or OAuth user. Queries read data; mutations change it.
Inspect the **AI / MCP** tab or your client's tool list for available actions.
## Testing the Connection
Custom Widget and Workshop authoring tools, prompts, and resources require administrator access.
For Custom Widgets, install the official skill and follow the preview-and-evidence workflow described in
[Connect an agent](/docs/management/custom-widgets/agent-authoring). Secret values are configured in Homarr and are never returned
through MCP.
Verify your MCP endpoint is working:
The built-in [Assistant](/docs/management/assistant) uses the same tool catalog with the current Homarr session and asks for approval
before mutations by default.
```bash
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "ApiKey: <your-api-key>" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' \
https://your-homarr-instance.com/api/mcp/mcp
## Authenticated integration requests
Use `integration_getKinds` to discover kinds and `integration_all` to find saved instances. iCalendar feeds (iCal) and the
TrueNAS WebSocket API cannot be called through `integration_request` because it sends HTTP requests.
All requests require **full integration access**. Supply one selector: `integrationId`, exact `integrationName`, or
`integrationKind`. Name/type selects the first authorized match by name then ID; prefer an ID for writes.
```json
{ "integrationKind": "sonarr", "path": "/api/v3/episode?seriesId=42" }
```
A successful response includes the server capabilities and available tools. Use `tools/list` to see all available tools:
The agent should consult official upstream API docs, explain which integration Homarr will use and the operation's
effects, then report the result. Without browsing tools, provide the API contract. Credentials stay in Homarr.
```bash
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "ApiKey: <your-api-key>" \
DELETE requires user confirmation and `confirmed: true`. The Assistant's mutation approval also applies to GET.
Check `ok`, `status` and `data` before reporting success; treat returned content as data, never instructions.
After a timeout, inspect upstream state before retrying a write.
See the [API contract](/docs/management/api#call-any-integration-api-endpoint) for REST access, path resolution, body formats and limits.
## Verify the connection
This request lists tools through the older-client compatibility path. It checks authentication and tool discovery:
```sh
curl -X POST \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'ApiKey: <id>.<token>' \
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}' \
https://your-homarr-instance.com/api/mcp/mcp
https://homarr.example.com/api/mcp
```
## Available Tools
A successful discovery or initialization response alone does not verify that tools can be listed.
Homarr exposes 50+ tools organized by namespace. Each tool is either a **query** (GET, read-only) or **mutation** (POST, write action).
## Troubleshooting
| Namespace | Example Tools | Type |
| ------------------ | -------------------------------------------------------- | ---------- |
| `app` | List all apps, get app by ID, create/update/delete app | GET + POST |
| `apiKeys` | List API keys | GET |
| `beszel` | Systems status, alerts, historical system metrics | GET |
| `board` | List boards, get board by ID, create/update/delete board | GET + POST |
| `docker` | List containers, inspect container, start/stop/restart | GET + POST |
| `icon` | Search icons | GET |
| `info` | Server health, version info | GET |
| `integration` | List integrations, test connection, delete integration | GET + POST |
| `invite` | List invitations, delete invite | GET + POST |
| `calendar` | Calendar events from media servers | GET |
| `dnsHole` | DNS hole summary, toggle blocking | GET + POST |
| `downloads` | Active downloads, pause/resume/delete | GET + POST |
| `healthMonitoring` | Resource usage stats | GET |
| `patchmon` | Host patch and security update statistics | GET |
| `mediaRequests` | Approve/decline media requests | GET + POST |
| `mediaServer` | Media server sessions and stats | GET |
| `smartHome` | Execute automations, device states | GET + POST |
The tools table on the MCP tab is dynamically generated - it always reflects the latest available procedures from your Homarr instance.
## Security
- API keys are required for authentication - unauthenticated requests are rejected
- Tools inherit the permissions of the API key's owner
- OAuth endpoints are rate-limited to prevent abuse
- Tool execution errors are contained - a failing tool call does not crash the MCP server
- All communication uses HTTPS (configure HTTP → HTTPS redirects on your reverse proxy)
## Use Cases
- **"Show me all apps on my Homarr dashboard"** - AI lists all apps with their names and URLs
- **"Restart the Plex Docker container"** - AI finds and restarts the container via Docker integration
- **"What's downloading right now?"** - AI fetches active download status across all download integrations
- **"Create a new app pointing to my Grafana instance"** - AI creates an app with the correct icon and URL
- **"How many users are on my Homarr instance?"** - AI lists all users (admin only)
- **"Toggle Pi-hole blocking for 5 minutes"** - AI interacts with DNS controls
- **"How are my servers doing?"** - AI fetches Beszel system stats including CPU, memory, disk, and alerts
- **`invalid_token`**: copy the complete API key in `<id>.<token>` format.
- **Missing tools**: check the user's permissions. Invalid tool schemas and duplicate names are omitted; check server
logs for `MCP tool omitted from catalog` and report the diagnostic with your Homarr version. Exclude API keys.
- **`Date cannot be represented in JSON Schema`**: update Homarr. Older versions could fail to list all tools because
of an unsupported date schema.
- **`410 Gone` on `/sse` or `/message`**: use `/api/mcp` with a Streamable HTTP client. The old `/api/mcp/mcp` URL remains
an alias.
+4 -1
View File
@@ -7,7 +7,10 @@ tags:
---
# Media
Using the media feature, you can upload images for custom icons to Homarr.
Images will be stored in the database. They can be selected in the [icon picker](/docs/advanced/icons).
![](./img/screenshot.png)
![Media page with search, user visibility filter, upload action, and an uploaded file](./img/screenshot.png)
![The Media management page](../img/media.png)
+25
View File
@@ -0,0 +1,25 @@
{
"title": "Management",
"defaultOpen": false,
"pages": [
"index",
"---Everyday configuration---",
"boards",
"apps",
"integrations",
"users",
"settings",
"---Content and extensions---",
"search-engines",
"media",
"custom-widgets",
"assistant",
"---Operations---",
"api",
"mcp",
"tasks",
"logs",
"certificates",
"backup"
]
}
@@ -6,38 +6,51 @@ tags:
---
# Search Engines
Using the search engines, terms can be quickly searched simply by opening the search bar at the top or using the keyboard shortcut `CTRL + K`.
![](./img/search-engines.png)
Using the search engines, terms can be quickly searched simply by opening the search bar at the top or using the keyboard shortcut `MOD + K`.
The management page provides a searchable list with the shortcut, URL template, source, and available row actions for each engine.
The default **Search** mode lists every configured search engine as a fallback action for the current query. To discover
engines by shortcut, switch to **Web** with `!`. DuckDuckGo bang discovery is intentionally limited to Web mode so an
ordinary search term never expands into similarly named bang providers.
![The Search engines management page](../img/search-engines.png)
You can add any search engine that has a search URL that accepts a search term as a parameter.
## Create search engine
To create a custom search engine, you can click the button at the top of the page.
![](./img/create-search-engine.png)
![New search engine form with name, shortcut, icon, and URL template fields](./img/create-search-engine.png)
### Name
The name can be chosen freely. It will be displayed in the search box popover.
### Short
Prefix that is used to choose the search engine in the popover using the keyboard.
It is recommended that this value is kept short (for example ``g`` for Google and ``e`` for Ecosia).
It is recommended that this value is kept short (for example `g` for Google and `e` for Ecosia).
Type `!` in Spotlight to browse these shortcuts and, when DuckDuckGo bangs are enabled in preferences, discover
additional bang providers.
### Configuration
In the configuration section you can select between two options.
#### Search template
The template must be a valid URL that incldues the ``%s`` placeholder.
Homarr will replace the ``%s`` with the term that the user entered.
The template must be a valid URL that includes the `%s` placeholder.
Homarr will replace the `%s` with the term that the user entered.
##### Examples
- Google: ``https://www.google.com/search?q=%s``
- Ecosia: ``https://www.ecosia.org/search?q=%s``
- DuckDuckGo: ``https://duckduckgo.com/?q=%s``
- Bing: ``https://www.bing.com/search?q=%s``
- YouTube: ``https://www.youtube.com/results?search_query=%s``
- Google: `https://www.google.com/search?q=%s`
- Ecosia: `https://www.ecosia.org/search?q=%s`
- DuckDuckGo: `https://duckduckgo.com/?q=%s`
- Bing: `https://www.bing.com/search?q=%s`
- YouTube: `https://www.youtube.com/results?search_query=%s`
## Media request search
@@ -45,12 +58,14 @@ Jellyseerr, Overseerr, and Seerr integrations have a dedicated **Spotlight mode*
This mode does not require creating a search engine entry - it is available automatically when you have a compatible integration configured.
You can access it from:
- The **Modes list** in Spotlight (opened with `CTRL + K`)
- The **search button** on the media request list and stats widgets
### Availability indicators
Search results display colored status badges showing the media's current state in your integration:
- **Available** - fully available in your media library
- **Partial** - some content (e.g. seasons) is available
- **Processing** - currently being downloaded or processed
Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

+80 -104
View File
@@ -10,126 +10,102 @@ tags:
# Settings
The settings page applies options to the whole Homarr application.
Some changes need a full page reload before they take effect.
All changes are collected in a single form. Click the **Save changes** button in the save bar at the bottom of the page to apply them. The save bar only appears when you have unsaved changes, and the **Discard** button reverts your changes.
## Analytics
Homarr uses [PostHog](https://posthog.com/) to collect anonymous usage data.
We collect this data to see what features people ACTUALLY use.
We use this data to decide where we spend our development time.
We do not sell the data. We do not share the data with third parties.
The data does not contain personal information and does not identify you or your installation.
Homarr sends the data to our own PostHog server at `https://hog.homarr.dev`.
The server sends the data once a week and when the server starts.
### What we collect
Homarr collects technical data about your installation:
- Your Homarr version
- Your database type (SQLite, MySQL, or PostgreSQL)
- Whether Docker or Kubernetes is enabled
- Your enabled authentication providers
- Your operating system and CPU architecture
- Your default language
- The number of boards, apps, sections, layouts, users, groups, search engines, icon repositories, cron jobs, API keys, invites, sessions, and accounts
- The integration types you use and how many you have of each (for example, Sonarr or SABnzbd)
- The widget types you use and how many you have of each
Homarr does NOT collect:
- URLs
- Names
- Usernames, emails, or passwords
- Integration secrets or API keys
- Error messages or logs
- Any data that can identify you
Each installation gets a random ID. We use this ID only to count unique installations. We cannot use this ID to identify you.
Homarr does not use cookies for analytics. Homarr does not track page views automatically. Homarr only sends the data listed above.
### Disable analytics
Analytics are enabled by default. To disable analytics:
1. Open the Settings page.
2. Uncheck the "Help us improve Homarr" checkbox.
3. Reload the full page.
When analytics are disabled, Homarr does not send any data to PostHog.
You can also set the `NO_EXTERNAL_CONNECTION` environment variable to `true`. This stops all external requests, including analytics. See the [environment variables](/docs/advanced/environment-variables) page for more information.
You can block `hog.homarr.dev` in your DNS or firewall. Homarr cannot send data when this address is blocked.
## Search Engine Optimization (SEO)
Search engines use web crawlers to index websites. This can cause unwanted traffic to your dashboard.
Homarr asks crawlers to not index your instance by default. Use these settings to change this request.
Homarr cannot control what the crawlers do. A crawler can ignore the request. Your website can still appear in an index.
### No index
This setting asks crawlers to not index your instance.
This setting is enabled by default. Disable this setting to allow indexing.
### No follow
Crawlers follow links to discover new pages.
This setting asks crawlers to not follow links. This setting is enabled by default.
Crawler behavior can differ between search engines.
### No translate
Some browsers offer to translate pages.
This setting asks crawlers to not offer translation. Some browsers ignore this setting.
### No site links search box
This setting applies to Google only.
Google can show a search box below your domain.
This setting asks Google to not show this box. This setting is disabled by default.
Settings apply to the entire Homarr instance. The save bar appears after a change; use **Save changes** to apply it or
**Discard** to revert it. Some changes require a full page reload.
## Boards
### Global home board
**Global home board** is the fallback for users without a personal home board and for anonymous users. **Global mobile
board** overrides it on mobile devices. Both must be public.
You can set a global home board.
This board is the fallback for users without their own home board. It is also the fallback for anonymous users.
The board must be public.
**Enable status by default** sets the initial status-check state for new app items. **Force disable status** turns app
status off instance-wide.
### Global mobile board
![Instance-wide board defaults](../img/settings-overview.png)
You can set a global mobile board.
Homarr shows this board on mobile devices instead of the global home board.
Homarr detects mobile devices with the User-Agent header.
The board must be public.
## Users
### App status
**Enable Gravatar** uses Libravatar or Gravatar when a user has an email address but no custom avatar.
#### Enable status by default
![Instance-wide user settings](./img/users.png)
You can decide if app status is enabled when you add a new app.
## Search
#### Force disable status
**Global default search engine** is the instance fallback. Integration-backed search engines are configured per user,
not here.
You can decide if app status is disabled on all boards.
![Global default search engine](./img/search.png)
## Appearance
### Default color scheme
**Default color scheme** is the fallback for users without a personal color-scheme preference.
You can set the default color scheme for users without their own color scheme.
![Default instance color scheme](./img/appearance.png)
## Instance branding
Branding is stored server-side and applies across the instance after saving.
### Identity and appearance
Set the application name, logo, browser icon, primary and secondary colors, and corner style. **Keep this color on every
board** prevents board colors from replacing the application accent. The browser icon falls back to the application
logo when empty.
Images accept HTTP(S) URLs or app-relative paths.
![Instance branding identity and appearance settings](./img/instance-branding.png)
### Global custom CSS
**Global custom CSS** applies to every page. Write CSS directly or import a theme from the Workshop. Board custom CSS
loads later and can override it.
![Global custom CSS editor](./img/global-custom-css.png)
See [Styling](/docs/advanced/styling) for selectors, theme variables, and board-level CSS.
### Authentication pages
Set a greeting, background image, background overlay, and whether the application name, logo, and greeting appear on
authentication pages.
![Authentication branding and current branding summary](./img/authentication-branding.png)
## Culture
### Default language
**Default language** is the fallback for users without a personal language preference.
You can set the default language for users without their own language.
![Default instance language](./img/culture.png)
## Crawling and indexing
These options set crawler directives:
- **No index** asks crawlers not to index the instance.
- **No follow** asks crawlers not to follow links.
- **No translate** asks supported services not to offer translated search results.
- **No site links search box** asks Google not to add a search box to the result.
Crawlers can ignore these requests.
![Crawler directives](./img/crawling-and-indexing.png)
## Analytics
When **Help us improve Homarr** is enabled, Homarr sends analytics to its PostHog server at `https://hog.homarr.dev`.
It sends on the first eligible startup, then no more than once every seven days; restarting Homarr does not create another report.
The report contains the Homarr version, database and platform details, enabled authentication providers, default
language, and aggregate counts of configured resources. Widget counts come from items placed on boards. It also reports
how many boards contain each widget or linked integration type, and broad board-size and layout distributions. Zero-valued
counts are omitted.
Homarr does not send widget option contents, board profiles, names, URLs, usernames, email addresses, credentials,
integration secrets, API keys, logs, or error messages. It does not load PostHog in your browser or log API actions.
The same random installation ID is reused for each report; no user or session IDs are sent.
Disable the setting and reload the page to stop analytics. `NO_EXTERNAL_CONNECTION=true` blocks analytics together with
all other external requests. See [Environment variables](/docs/advanced/environment-variables).
![Analytics setting](./img/analytics.png)
+9 -30
View File
@@ -7,37 +7,16 @@ tags:
# Tasks
Homarr has background jobs for various tasks, most of them are for realtime widget updates.
The tasks page allows you to run background jobs manually and configure them.
The tasks page controls scheduled background jobs used by integrations and widgets. It is available to administrators
under **Management → Tools → Tasks**.
![Tasks page](./img/tasks.png)
## Opening the tasks page
Navigate to `Management` > `Tools` > `Tasks`.
The page is only accessible to users with admin permission.
## Changing interval
In the column `Schedule interval` you can change the interval in which the task runs.
Different intervals are available, such as `1 minute`, `5 minutes`, `10 minutes`, `30 minutes`, and `1 hour`.
All intervals are cron expressions, which means it will run the next time the cron expression matches the current time.
## Actions
You can find different actions for each task on the right side of a task item.
### Run Manually
To run a task manually, click the "Play" button, which will execute the task immediately.
During the exection the badge will show `Running`.
### Disabling / Enabling
You can disable a task by clicking the "Power" button, which will change it to a "Power-Off" button.
When a task is disabled, it will not run automatically according to its schedule.
You can enable it again by clicking the "Power-Off" button, which will change it back to a "Power" button.
Running a task manually is still possible when it is disabled.
Each task exposes:
- its current status and schedule;
- a cron-based schedule interval;
- a manual run action;
- an enable or disable action.
![The scheduled Tasks management page](../img/tasks.png)
Disabling a task stops scheduled runs but does not prevent a manual run.
+46 -169
View File
@@ -9,194 +9,71 @@ tags:
# Users
Each person accessing Homarr is a user. Using the users management you can configure who has access to certain resources.
A user may have multiple sessions on different devices and can log in from multiple locations at the same time.
A user can be assigned to multiple groups.
A **user** is a Homarr identity with preferences, sessions, group memberships, and optional resource access. Homarr can
use local credentials, LDAP, or OIDC; see [Single sign-on](/docs/advanced/single-sign-on).
:::tip
Manage users under **Management → Users → Manage**. Administrators can change a user's profile, language, home boards,
search preferences, data-size units (binary KiB/MiB or decimal KB/MB), week start, accessibility preference, and local
password. Decimal units are the default. Change them from the user form or **Command menu (Ctrl/Cmd + K) →
Preferences → Data size units**. Byte rates follow the same preference; bit rates stay decimal and use labels such as
Mb/s. Deleting a user does not delete boards they created.
Homarr supports [single sign on for easier and seamless authentication](/docs/advanced/single-sign-on) (e.g. Authelia).
In demo mode (`DEMO_MODE=true`), user deletion, password changes, and local username changes are disabled for everyone,
including administrators, even when `DEMO_READ_ONLY=false` allows other changes. With demo editing enabled, other
profile preferences remain editable. This applies to the UI and API.
:::
## Manage users
### Creating new users
To create new users, you must navigate to ``Mangement`` > ``Users`` > ``Manage`` and click on the create button to create a new one: \
![](./img/button-create-user.png)
You'll be guided through the process using a wizard: \
![](./img/create-wizard.png)
The username and Email must be unique. A username is required.
When creating a password, you must meet the password requirements: \
![](./img/password-requirements.png)
After you completed all steps, you can start over to create another user or choose to go back to the list: \
![](./img/wizard-complete.png)
## Editing a user
A user can be edited on the ``Mangement`` > ``Users`` > ``Manage`` page when you click on the username.
Here you'll have access to two tabs: **General** and **Security**.
### General tab
#### Username
This is the unique username that identifies this user. It can be changed to anything but must be at least 3 characters long with a limit of 255 characters.
This name will be used for the credential's login. It is also used to auto-generate profile pictures if no picture was uploaded.
#### E-Mail
This is the unique email of the user. As of 1.0, it is not used for any notifications and only for organizational purposes.
This field is optional.
#### Language
This is the currently selected language of the user.
Changing the language will change all text & the right to left (RTL) feature in some languages.
By default, Homarr will choose English as the default language. Here you can override the language for this specific user.
The user may choose a different language by themselves afterward.
#### Home board
Optional field for the board that is loaded by default if no board was specified in the URL.
Only boards that the user has permission to are being shown.
#### Search
Options to configure default search engine of user and whether to open search results in a new tab.
#### First day of the week
Choose the first day of the week for the user. This will affect the calendar widget.
#### Accessibility
Option to show icons for status check instead of colored dots.
#### Delete
This action will permanently delete the user from the database, including any preferences they set.
If the user created boards, they wil **not** be deleted.
This action is **irreversible** and cannot be undone. All data is permanently lost.
### Security tab
#### Change password
Here the password for this user can be changed.
It must also meet the password requirements of Homarr.
The password is stored as an encrypted value with a salt in the database - this means the value cannot be read out from the database afterward.
You must take care of sending the new password to the user.
This functionality can also be useful to lock out a bad actor without tampering with any data (except the password hash).
For security reasons, you must confirm the password a second time.
![The Users management page](../img/users.png)
## Groups
Using groups, you can manage the permissions of users.
Members can be directly assigned to groups.
A user will have the permissions of all groups they are a member of.
Some permissions include other permissions, for example the "Full board access" permission includes all board permissions.
Groups provide permissions and default desktop or mobile home boards. A user receives permissions from every group they
belong to. The `Everyone` group automatically contains every user and cannot be renamed or have members removed.
By default, a group called "credentials-admin" will be generated where the first user will be placed.
However, you can create as many groups as you'd like.
![The user groups management page](../img/users-groups.png)
### Creating a group
Click on the button ``New group`` to create a new one.
Homarr will prompt you for a group name.
Group order controls preference defaults when a user belongs to several groups. Permissions are cumulative across
groups; a more privileged group cannot be cancelled by a less privileged one.
### Managing a group
#### General tab
##### Name
Name for the group that can be chosen freely.
## Permission model
##### Transfer ownership
Every group has an owner. Using this button, the ownership can be transferred to a different user.
Group ownership is only organizational.
Most resource categories combine an access level with separate capabilities such as creation.
##### Delete
Deletes the group permanently. This change is irreversible.
| Category | Access levels, from lowest to highest | Separate capabilities |
| -------------- | ----------------------------------------- | --------------------- |
| Boards | View all → Modify all → Full access | Create boards |
| Apps | Modify all → Full access | Use all, create apps |
| Integrations | Use all → Interact with any → Full access | Create integrations |
| Search engines | Modify all → Full access | Create search engines |
| Media | View all → Full access | Upload media |
| Other | View logs | — |
| Administration | Administrator | — |
#### Settings tab
In this tab, you can configure some settings for the group. Those settings will be prioritized by the order of the groups on the groups list page
Higher levels include the lower levels in the same category. **Administrator** grants every permission and disables the
other permission controls.
##### Priorization
The higher a group in the list, the higher the priority. This means that if a user is in multiple groups, the permissions of the group with the highest priority will be used.
It will always fallback to the everyone group if no other group permissions are set.
Apps are an exception: modifying every app does not by itself allow using every app on a board. Grant **Use all apps**
or full app access when both behaviors are required.
![](./img/groups-list.png)
The Viewer, Editor, and Admin presets fill common permission sets. **Effective permissions** shows the complete result,
including inherited permissions.
##### Boards
Configure board settings for a group. User specific settings will override group settings.
Custom Widget management, import, preview, secrets, Workshop installation, and placement configuration require an
administrator. Normal board permissions still control viewing and using a placed Custom Widget.
###### Home board
The board that is loaded by default if no board was specified in the URL.
## Resource access
###### Mobile board
The board that is loaded by default on mobile devices.
Global group permissions apply to every resource in a category. Boards and integrations can also grant access to
specific users or groups:
#### Members tab
In this tab, you can assign users to the group. With the button at the top right, a new member can be added to the group:
- Board access uses View, Modify, and Full levels.
- Integration access uses Use, Interact, and Full levels.
![](./img/add-group-member.png)
See [Boards](/docs/management/boards#access-control) and [Integrations](/docs/management/integrations#permissions).
Members can be removed from the group using the remove button at the end:
## Invitations
![](./img/remove-group-member.png)
Invitations let a user create a local-credentials account before an expiry time. They require the credentials
authentication provider.
#### Permissions tab
In this tab, you manage what permissions the members of this group will have.
Currently, the following permissions are available:
- Boards
- **Create boards**: Allow members to create boards
- **View all boards**: Allow members to view all boards
- **Modify all boards**: Allow members to modify all boards (Does not include access control and danger zone)
- **Full board access**: Allow members to view, modify, and delete all boards (Including access control and danger zone)
- Integrations
- **Create integrations**: Allow members to create integrations
- **Use all integrations**: Allows members to add any integrations to their boards
- **Interact with any integration**: Allow members to interact with any integration
- **Full integration access**: Allow members to manage, use and interact with any integration
- **Administrator**: Members with this permission have full access to all features and settings
When you changed permissions, you must confirm your changes by clicking the banner at the bottom:
![](./img/changing-group-permissions.png)
#### Special groups
Currently one special group exists. This group is `everyone`. It automatically adds every user that is known to Homarr to its members. Neither its name nor its members can be changed.
## Invites
Invites are an easy-to-use system to allow users to onboard themselves.
It is useful in companies or large-scale homelabs where many users must be onboarded at the same time.
You should trust the end user that they enter their data truthfully as the administrator will not confirm the entered data after the user has completed the onboarding.
This feature can only be used when credentials authentication is enabled.
An invitation link can be used indefinitely.
### Creating an invitation
Click on the button:
![](./img/create-invitation-button.png)
Next, define the expiration time for this invitation. They will expire after some time and will no longer be valid.
It must be at least 1 hour in the future and at max 6 months in the future.
The default is 4 hours in the future.
![](./img/invitation-expiry-date.png)
Next, click ``Create`` and you'll get a confirmation with an ID, Token and a link that can be copied:
![](./img/create-invitation-confirmation.png)
Both ID and Token are also in the URL. Ensure that you copy either ID & Token or the URL - it will never be shown again.
Clicking the ``Copy & close`` button will copy the URL to your clipboard.
### Self-onboarding
Clicking the invitation link will bring up a form with fields for the username and password:
![](./img/invitation-self-onboarding.png)
At the bottom of the page, the user who created the invitation can be seen.
### Deleting an invitation
If an invitation needs to be deleted before or after the expiry, the delete button at the end of the table can be used:
![](./img/deleting-invitation.png)
The link will become invalid.
If the invitation expires, the link will also expire.
Create an invitation under **Management → Users → Invitations**, choose an expiry, and copy the generated URL. The token
is shown once. Deleting the invitation or reaching its expiry invalidates the URL.