Skip to content

Latest commit

 

History

History
1343 lines (970 loc) · 60.8 KB

File metadata and controls

1343 lines (970 loc) · 60.8 KB

Configuring Glance

Configure Glance itself: files, secrets, authentication, server settings, branding, pages, columns, dashboards, and widget defaults.

Glance README · Widgets · Themes · Preconfigured pages

On this page


Preconfigured page

If you don't want to spend time reading through all the available configuration options and just want something to get you going quickly you can use this glance.yml file and make changes to it as you see fit. It will give you a page that looks like the following:

Preconfigured page preview

Configure the widgets, add more of them, add extra pages, etc. Make it your own!

The config file

Auto reload

Automatic config reload is supported, meaning that you can make changes to the config file and have them take effect on save without having to restart the container/service. Reloads are transactional: Glance prepares the replacement application while the current application continues serving requests, switches to the new configuration only after it has been successfully constructed, and then retires the previous application generation. Changes to server.host or server.port are rejected during automatic reload because they change the process listener and therefore require a manual restart. Making changes to environment variables does not trigger a reload and also requires manual restart. Deleting a config file will stop that file from being watched, even if it is recreated.

Note

Glance distinguishes recoverable item-level configuration errors from structural, routing, security, persistence, and process-level failures. Recoverable errors in widgets, footer micro-widgets, analytics, themes, widget defaults, and the optional custom assets path are reported with source information where available while Glance continues with the remaining valid configuration or a safe fallback. The config:validate command remains strict and returns a failure for these errors so they are not silently accepted during validation. Malformed YAML, unresolved includes or configuration variables, invalid routing/authentication/authorization configuration, unsupported personal-state document versions, and listener-defining server failures remain fatal during startup. Corrupt or empty personal-state files are quarantined and replaced with an empty store so ancillary browser state cannot prevent startup. During automatic reload, unrecoverable candidate configurations are rejected and the currently running application generation continues serving requests.

Caution

Reloading the configuration file clears your cached data, meaning that you have to request the data anew each time you do this. This can lead to rate limiting for some APIs if you do it too frequently. Having a cache that persists between reloads will be added in the future.

Environment variables

Inserting environment variables is supported anywhere in the config. This is done via the ${ENV_VAR} syntax. Attempting to use an environment variable that does not exist is an unrecoverable configuration error: Glance will not start from that configuration, and an automatic reload will reject the candidate while the current application continues running. Example:

server:
  host: ${HOST}
  port: ${PORT}

Can also be in the middle of a string:

- type: rss
  title: ${RSS_TITLE}
  feeds:
    - url: http://domain.com/rss/${RSS_CATEGORY}.xml

Works with any type of value, not just strings:

- type: rss
  limit: ${RSS_LIMIT}

If you need to use the syntax ${NAME} in your config without it being interpreted as an environment variable, you can escape it by prefixing with a backslash ``:

something: \${NOT_AN_ENV_VAR}

Other ways of providing tokens/passwords/secrets

You can use Docker secrets with the following syntax:

# This will be replaced with the contents of the file /run/secrets/github_token
# so long as the secret `github_token` is provided to the container
token: ${secret:github_token}

Alternatively, you can load the contents of a file who's path is provided by an environment variable:

docker-compose.yml

services:
  glance:
    image: ghcr.io/samcro1967/glance:latest
    environment:
      - TOKEN_FILE=/home/user/token
    volumes:
      - /home/user/token:/home/user/token

glance.yml

token: ${readFileFromEnv:TOKEN_FILE}

Note

The contents of the file will be stripped of any leading/trailing whitespace before being used.

Including other config files

Including config files from within your main config file is supported. This is done via the $include directive along with a relative or absolute path to the file you want to include. If the path is relative, it will be relative to the main config file. Additionally, environment variables can be used within included files, and changes to the included files will trigger an automatic reload. Example:

pages:
  - $include: home.yml
  - $include: videos.yml
  - $include: homelab.yml

The file you are including should not have any additional indentation, its values should be at the top level and the appropriate amount of indentation will be added automatically depending on where the file is included. Example:

glance.yml

pages:
  - name: Home
    columns:
      - size: full
        widgets:
          - $include: rss.yml
  - name: News
    columns:
      - size: full
        widgets:
          - type: group
            widgets:
              - $include: rss.yml
              - type: reddit
                subreddit: news

rss.yml

- type: rss
  title: News
  feeds:
    - url: ${RSS_URL}

The $include directive can be used anywhere in the config file, not just in the pages property, however it must be on its own line and have the appropriate indentation.

Glance preserves source-file mappings while expanding $include directives and reports the original included filename and line for supported source-aware configuration diagnostics. Raw YAML parser failures or errors that cannot be mapped to a semantic configuration location may still be easier to inspect in the fully expanded document. In those cases, use the config:print command and pipe it into less -N:

glance --config /path/to/glance.yml config:print | less -N

This is a bit more convoluted when running Glance inside a Docker container:

docker run --rm -v ./glance.yml:/app/config/glance.yml ghcr.io/samcro1967/glance:latest config:print | less -N

This assumes that the config you want to print is in your current working directory and is named glance.yml.

Widget defaults

The optional top-level widget-defaults property lets you define shared widget settings once and inherit them across the dashboard. Existing configurations do not need to use widget-defaults; when it is omitted, existing widget syntax and built-in behavior remain unchanged.

Invalid global widget defaults are reported as recoverable configuration errors and the global defaults block is ignored for that application generation. Invalid type-specific defaults are isolated to the affected widget type so other valid defaults and explicit widget configuration remain active. config:validate remains strict and reports these errors instead of treating the configuration as valid.

Defaults can be defined globally and refined for a particular widget type:

widget-defaults:
  global:
    cache: 30m
    new-tab: true

  types:
    rss:
      cache: 15m
      collapse-after: 8
    monitor:
      timeout: 5s

Resolution and precedence

Defaults are resolved from least specific to most specific:

built-in widget default
        ↓
widget-defaults.global
        ↓
widget-defaults.types.<widget-type>
        ↓
widget instance
        ↓
child/source setting, where supported

The most specific explicitly configured value wins. Explicit widget and child/source settings therefore continue to override inherited defaults.

For example:

widget-defaults:
  global:
    cache: 30m
  types:
    rss:
      cache: 15m

pages:
  - name: Home
    columns:
      - size: full
        widgets:
          - type: rss
            feeds:
              - url: https://example.com/news.xml

          - type: rss
            cache: 5m
            feeds:
              - url: https://example.com/updates.xml

The first RSS widget uses the RSS type default of 15m. The second uses 5m because the widget instance is more specific.

Container widgets do not implicitly pass their type defaults to their children. Each child widget resolves defaults according to its own widget type. For example, an RSS widget inside a Status Bar, Group, or Stack still resolves RSS defaults independently.

Common capabilities

The following capabilities are common to registered widgets and may be configured under widget-defaults.global or widget-defaults.types.<type>:

Name Type Description
title string Default widget title
icon string Default widget title icon
title-url string Default URL opened by the widget title
hide-header boolean Whether the widget header is hidden
css-class string Default custom CSS class
cache duration Default duration-based refresh/cache interval where the widget supports configurable caching
cache-cron string Default cron-based refresh schedule where the widget supports configurable caching
new-tab boolean Whether links governed by the widget's common link policy open in a new tab

cache and cache-cron are alternative forms of the same refresh scheduling capability and cannot both be configured at the same precedence level. A more-specific setting replaces either form inherited from a broader level. For example, a type-level cache-cron replaces a global cache, while an explicit widget cache replaces an inherited cache-cron.

cache-cron uses standard five-field cron expressions in minute, hour, day-of-month, month, and day-of-week order: minute hour day-of-month month day-of-week. Standard wall-clock descriptors such as @hourly and @daily are also supported. Seconds fields are not supported. The duration-style @every descriptor is intentionally not supported; use cache for duration-based scheduling.

Cron schedules use the Glance process timezone, which normally means the timezone configured for the Glance process or container. CRON_TZ= and TZ= prefixes are not supported.

Cron scheduling changes only the normal refresh cadence. A newly started or reloaded widget remains immediately eligible for its initial refresh. Existing refresh, retry, cancellation, degraded-state, stale-content, and live-update behavior remains unchanged.

new-tab is the canonical hierarchical setting for link destination. Existing widget-specific properties such as same-tab remain supported and are not deprecated. Where a widget or child exposes one of those existing controls, the more specific setting wins.

Capability-specific defaults

Some capabilities are meaningful only for particular widget types. They can be configured under widget-defaults.types.<type> and, where supported, directly on widget instances or their child/source entries.

Name Type Description
limit integer Maximum number of displayed items
collapse-after integer Number of visible items before the remainder is collapsed
collapse-after-rows integer Number of visible rows before the remainder is collapsed
timeout duration HTTP request timeout
allow-insecure boolean Allow invalid/self-signed TLS certificates
headers map HTTP request headers
basic-auth object HTTP Basic Authentication credentials
proxy string or object HTTP proxy configuration where supported

Applicability and inheritance scope are validated. A capability is applied only to widget types and scopes for which it has defined semantics; unsupported combinations are rejected rather than silently changing unrelated behavior.

List capabilities such as limit and collapse-after are not global defaults. They are available only for compatible widget types. basic-auth is also intentionally not global and is available only for compatible type, instance, or child/source scopes.

HTTP defaults apply only to widgets whose endpoint semantics support them. Provider-owned services do not automatically inherit generic HTTP configuration merely because they perform network requests.

Child and source settings

Some widgets contain child entries or independently configurable remote sources. Supported defaults can flow to those entries while preserving explicit child/source overrides.

For example:

widget-defaults:
  global:
    timeout: 10s
    headers:
      User-Agent: Glance

  types:
    rss:
      timeout: 5s
      basic-auth:
        username: reader
        password: ${RSS_PASSWORD}

pages:
  - name: Home
    columns:
      - size: full
        widgets:
          - type: rss
            feeds:
              - url: https://example.com/feed.xml
              - url: https://example.com/private.xml
                timeout: 15s

The first feed inherits the RSS type timeout of 5s. The second explicitly uses 15s.

Inherited HTTP headers are merged with more-specific headers, with the more-specific value winning when the same header name is configured at multiple levels. Dedicated authentication settings take precedence over an inherited or custom Authorization header.

Backward compatibility

widget-defaults is additive and optional. A valid configuration that does not use it continues to use the existing widget-specific syntax and built-in defaults. Existing names such as same-tab remain valid and do not produce deprecation warnings merely because new-tab is the canonical hierarchical capability name.

Icons

The common widget icon property adds an optional icon immediately before the widget title. It accepts a direct image URL or an icon name from one of the supported libraries using the prefixes below. The same icon syntax is also used by widget-specific item and service icons, such as Monitor entries, Bookmarks, and Docker containers.

icon: si:immich # si for Simple icons https://simpleicons.org/
icon: sh:immich # sh for selfh.st icons https://selfh.st/icons/
icon: di:immich # di for Dashboard icons https://github.com/homarr-labs/dashboard-icons
icon: hla:linux # hla for Homelab SVG Assets https://github.com/loganmarchione/homelab-svg-assets
icon: mdi:camera # mdi for Material Design icons https://pictogrammers.com/library/mdi/

Widget title icons are rendered only when the widget has a non-empty title. When title-url is configured, the icon and title are part of the same link. hide-header: true suppresses the title icon together with the header. Group child icons appear in their group tabs, while widgets inside a Stack render title icons in their normal headers.

Title icons participate in widget-defaults, so they can be configured globally, by widget type, or on an individual widget using the normal precedence rules. An explicit empty value (icon: "") suppresses an inherited title icon. Widget-specific item or service icons remain independent of the widget title icon.

Prefix an icon value with auto-invert to automatically invert it for dark themes. The si: and mdi: prefixes enable auto-inversion automatically.

The sh: and di: prefixes request SVG icons by default. If an icon is only available as a PNG, add the extension to its name. The hla: prefix uses Homelab SVG Assets, which provides SVG icons:

icon: sh:unmanic.png

Note

The icons are loaded externally and are hosted on cdn.jsdelivr.net, if you do not wish to depend on a 3rd party you are free to download the icons individually and host them locally.

Icons from the Simple icons library as well as Material Design icons will automatically invert their color to match your light or dark theme, however you may want to enable this manually for other icons. To do this, you can use the auto-invert prefix:

icon: auto-invert https://example.com/path/to/icon.png # with a URL
icon: auto-invert sh:glance-dark # with a selfh.st icon

This expects the icon to be black and will automatically invert it to white when using a dark theme.

If there is no .svg version available for a selfh.st or Dashboard icon, then you can add the image extension of the format you wish to use.

icon: sh:glance.png # use the .png version of the icon
icon: sh:glance.webp # use the .webp version of the icon

Config schema

For property descriptions, validation and autocompletion of the config within your IDE, @not-first has kindly created a schema. Massive thanks to them for this, go check it out and give them a star!

Authentication

To make sure that only you and the people you want to share your dashboard with have access to it, Glance supports local username/password authentication and OpenID Connect (OIDC). Both methods are configured through the top-level auth property and can be enabled independently or together.

For local username/password authentication:

auth:
  secret-key: # this must be set to a random value generated using the secret:make CLI command
  users:
    admin:
      password: 123456
    user:
      password: 123456

To generate a secret key, run the following command:

./glance secret:make

Or with Docker:

docker run --rm ghcr.io/samcro1967/glance:latest secret:make

OpenID Connect (OIDC)

Glance can authenticate users through an OpenID Connect identity provider. OIDC can be used by itself or alongside local username/password authentication.

auth:
  secret-key: ${GLANCE_AUTH_SECRET_KEY}
  oidc:
    issuer: https://accounts.google.com
    client-id: ${GLANCE_OIDC_CLIENT_ID}
    client-secret: ${GLANCE_OIDC_CLIENT_SECRET}
    provider-name: Google
    allowed-users:
      - user@example.com
      - another-user@example.com

issuer, client-id, and client-secret are required when OIDC is configured. provider-name is optional and controls the provider name displayed on the login page and for the signed-in user. When omitted, Glance uses a generic SSO label rather than inferring a provider name from the issuer.

Glance requests the openid and email scopes. The authorization flow uses state, nonce, and PKCE protection. Logging out ends the Glance session and returns to the Glance login page; it does not log the user out of the external identity provider.

allowed-users is optional. When omitted or empty, any identity that successfully authenticates with the configured OIDC provider can access Glance. When entries are configured, the provider must supply a verified email claim and the email address must exactly match an allowed entry, ignoring letter case and surrounding whitespace. Other identity claims are not used as authorization fallbacks.

Register the externally accessible Glance callback URL with the identity provider. For example:

https://glance.example.com/auth/oidc/callback

If Glance is hosted beneath a configured server.base-url, include that base path in the externally registered callback URL.

OIDC should be exposed through HTTPS so authentication cookies can be handled securely. When TLS terminates at a reverse proxy, configure server.proxied appropriately and use server.trusted-proxies where possible so forwarded HTTPS state is accepted only from trusted proxy peers.

Client secrets and the Glance authentication secret should not be committed directly to configuration files. Glance configuration variable substitution can be used, as shown above, to provide them through the environment or another supported secret mechanism.

OIDC configuration participates in normal Glance configuration reloads. Changes such as updating allowed-users apply to new authentication attempts without restarting Glance. Removing an identity from allowed-users does not revoke a Glance session that was already established; existing sessions remain valid until their normal expiration or invalidation. Rotating secret-key invalidates existing Glance sessions globally.

Dashboard authorization

When named dashboards are configured, Glance can restrict each dashboard to specific authenticated users or reusable groups. Dashboard authorization works with both local username/password authentication and OIDC.

auth:
  secret-key: ${GLANCE_AUTH_SECRET_KEY}

  users:
    mark:
      password-hash: ${MARK_PASSWORD_HASH}
    kellie:
      password-hash: ${KELLIE_PASSWORD_HASH}

  groups:
    family:
      users:
        - mark
        - kellie
    admins:
      users:
        - mark

  access:
    dashboards:
      Default:
        groups:
          - family
      Admin:
        groups:
          - admins
        users:
          - admin@example.com

groups defines reusable sets of authorization identities. Groups contain users directly and cannot contain other groups. Defining groups by itself does not enable dashboard authorization.

access.dashboards defines the dashboard access policy. A dashboard is accessible when the authenticated identity is listed directly under users or belongs to any group listed under groups. Direct users and groups can be combined in the same rule.

For local authentication, the authorization identity is the configured username and matching is case-sensitive. For OIDC, dashboard authorization uses the provider's verified email claim, normalized for letter case and surrounding whitespace. An OIDC identity without a verified email cannot use dashboard authorization. oidc.allowed-users remains a separate global OIDC authentication admission control: an identity must first be admitted by allowed-users, when configured, before dashboard authorization is evaluated.

Dashboard authorization is optional. When auth.access.dashboards is omitted or empty, existing authentication and dashboard behavior is unchanged. Once at least one dashboard access rule is configured, authorization is enabled and dashboards are deny-by-default: every accessible dashboard must have an explicit rule granting the authenticated identity access. Dashboard access rules require named dashboards and do not apply to legacy configurations that use standalone pages without dashboards.

Pages do not have independent access rules. A page is accessible when it belongs to at least one dashboard the authenticated identity can access. This means a page shared by multiple dashboards remains accessible through any authorized containing dashboard, while a page that belongs only to unauthorized dashboards is inaccessible. Dashboard navigation is filtered to dashboards available to the current identity.

Authorization preserves the existing dashboard routing topology. Granting access to a page through one dashboard does not create a new route for that page through another dashboard. For example, a page assigned only to an Admin dashboard does not become available at the Default dashboard's page route merely because the current user can access Admin.

After authentication, requests for unauthorized dashboards and pages return HTTP 404 so their existence is not advertised through normal dashboard routing. Unauthenticated requests continue to use the normal authentication flow.

Dashboard authorization participates in normal Glance configuration reloads. A successfully reloaded policy is used for subsequent requests from existing authenticated sessions; changing dashboard grants therefore does not require those users to sign in again. This differs from oidc.allowed-users, which controls admission when an OIDC authentication is established rather than continuously revoking existing sessions.

These rules protect dashboard and page access through the Glance UI and normal page routes. They are not a general resource-level or multi-tenant security boundary: widgets do not have independent ACLs, and widget-content APIs, live-update/SSE endpoints, static assets, and other underlying resources are not individually isolated by dashboard authorization. Do not rely on dashboard authorization to protect secrets that those resources themselves expose.

Using hashed passwords

If you do not want to store plain passwords in your config file or in environment variables, you can hash your password and provide its hash instead:

./glance password:hash mysecretpassword

Or with Docker:

docker run --rm ghcr.io/samcro1967/glance:latest password:hash mysecretpassword

Then, in your config file use the password-hash property instead of password:

auth:
  secret-key: # this must be set to a random value generated using the secret:make CLI command
  users:
    admin:
      password-hash: $2a$10$o6SXqiccI3DDP2dN4ADumuOeIHET6Q4bUMYZD6rT2Aqt6XQ3DyO.6

Preventing brute-force attacks

Glance will automatically block IP addresses of users who fail to authenticate 5 times in a row in the span of 5 minutes. In order for this feature to work correctly, Glance must know the real IP address of requests. If you're using a reverse proxy such as nginx, Traefik, NPM, etc, you must set the proxied property in the server configuration to true:

server:
  proxied: true

When set to true, Glance can use X-Forwarded-For to determine the original client address. When trusted-proxies is configured, Glance walks the forwarded chain from the direct peer toward the client, skips only explicitly trusted proxy hops, and uses the first untrusted address. Legacy proxied: true configurations without trusted-proxies retain the historical rightmost-forwarded-address behavior, so the reverse proxy must continue to normalize the header safely.

For additional protection against spoofed forwarding headers, configure trusted-proxies with the IP addresses or CIDR ranges of the reverse proxies that connect directly to Glance. When configured, forwarding headers from other peers are ignored.

Server

Server configuration is done through a top level server property. Example:

server:
  port: 8080
  assets-path: /home/user/glance-assets

Properties

Name Type Required Default
host string no
port number no 8080
proxied boolean no false
trusted-proxies list no
base-url string no
assets-path string no
personal-state object no disabled
resource-proxy object no disabled
frontend-diagnostics boolean no false

host

The address which the server will listen on. Setting it to localhost means that only the machine that the server is running on will be able to access the dashboard. By default it will listen on all interfaces. Changing this property while Glance is running requires a manual restart; an automatic configuration reload that changes it is rejected while the existing application continues running.

port

A number between 1 and 65,535, so long as that port isn't already used by anything else. Changing this property while Glance is running requires a manual restart; an automatic configuration reload that changes it is rejected while the existing application continues running.

personal-state

Optionally stores supported user-specific widget state on the Glance server instead of only in the browser. This is disabled by default and requires authentication so state can be isolated by the authenticated user identity.

server:
  personal-state:
    enabled: true
    path: /app/data/personal-state.json
Name Type Required Default
enabled boolean no false
path string when enabled

The path must be absolute. Glance creates the parent directory when the first state write occurs and writes the state file atomically with private file permissions. If an existing state file is empty or malformed, Glance quarantines it with a timestamped .corrupt-* suffix, logs the recovery, and starts with an empty store. Unsupported format versions remain fatal so an unknown or newer state format is never overwritten. Each identity may store up to 512 IDs per supported namespace and the complete persisted document is limited to 8 MiB; writes that would exceed those bounds are rejected. When running Glance in a container, place this path on a persistent writable volume if the state should survive container replacement.

When enabled, the To-do and Timer widgets use authenticated server-side state. On first use, if no server value exists for a widget, Glance migrates valid state from that browser profile's existing local storage and removes the local copy only after the server write succeeds. After migration, server state is authoritative. Disabling this feature restores the existing browser-local behavior.

Personal state is keyed by authenticated identity, widget type, and widget id; raw usernames or OIDC principals are not used as on-disk keys.

proxied

Set to true if you're using a reverse proxy in front of Glance. This will make Glance use the X-Forwarded-* headers to determine the original request details.

trusted-proxies

An optional list of IP addresses or CIDR ranges for reverse proxies that connect directly to Glance. When configured, Glance only trusts X-Forwarded-* headers when the direct peer matches one of these addresses or ranges. This prevents an untrusted client that can connect directly to Glance from spoofing forwarded request information.

Individual IPv4 and IPv6 addresses and CIDR ranges are supported. This property requires proxied to be true. If omitted, proxied: true retains the existing behavior for backward compatibility.

base-url

The base URL that Glance is hosted under. No need to specify this unless you're using a reverse proxy and are hosting Glance under a directory. If that's the case then you can set this value to /glance or whatever the directory is called. Note that the forward slash (/) in the beginning is required unless you specify the full domain and path.

Important

You need to strip the base-url prefix before forwarding the request to the Glance server. In Caddy you can do this using handle_path or uri strip_prefix.

assets-path

The path to a directory that will be served by the server under the /assets/ path. This is handy for widgets like the Monitor where you have to specify an icon URL and you want to self host all the icons rather than pointing to an external source. If a configured assets path is unavailable or is not a directory, Glance reports a recoverable configuration error, disables the custom assets path for that application generation, and continues serving the remaining dashboard. config:validate remains strict and reports the configuration as invalid.

resource-proxy

The optional resource proxy allows an HTTPS Glance dashboard to display images provided by explicitly authorized HTTP-only services without exposing the upstream resource URL or credentials embedded in that URL to the browser. The proxy is disabled when resource-proxy is omitted or when no allowed origins are configured.

server:
  resource-proxy:
    allowed-origins:
      - http://plex:32400
      - http://sonarr:8989
      - http://radarr:7878

Each entry in allowed-origins must be an HTTP origin consisting only of a scheme, host or IP address, and optional port. Matching is performed against the exact normalized origin, including the effective port. Wildcards and CIDR ranges are not supported, and configured origins cannot contain user information, paths other than /, queries, or fragments. Private and loopback addresses are permitted when explicitly configured so the proxy can intentionally reach internal services.

Custom API templates opt individual resource URLs into this behavior with the proxyURL helper:

<img src="{{ proxyURL $imageURL }}">

When $imageURL belongs to an allowed HTTP origin, proxyURL returns a Glance-local /api/resource-proxy/ URL containing an opaque identifier rather than the upstream URL. This is useful when an internal service requires credentials in an image URL: the credential-bearing upstream URL remains server-side instead of being rendered into browser HTML, browser history, or normal resource requests. Template-level proxyURL calls retain their existing passthrough behavior for URLs that are not eligible for the configured proxy. Browser-managed image surfaces apply a stricter policy: HTTPS and local relative images are rendered normally, allowlisted HTTP images are proxied, and non-allowlisted HTTP, protocol-relative, credential-bearing, or unsupported-scheme images are omitted rather than emitted as insecure browser requests. Configured branding images, icon fields, and provider images from RSS, Reddit, Twitch, and Videos use this browser-image policy automatically, alongside the existing page, widget, bookmark, monitor, footer micro-widget, Docker-label, Status Bar Custom API, and media image integrations.

The resource endpoint uses normal Glance authentication. Upstream requests use a dedicated HTTP transport that does not inherit environment proxy settings. Browser cookies, authorization, and arbitrary request headers are not forwarded upstream, and upstream cookies are not relayed to the browser. Redirects are followed only when they remain within the originally authorized origin; redirecting to another origin is rejected even when that second origin is separately allowlisted.

Proxy responses are limited to 10 MiB and supported raster image content types: JPEG, PNG, GIF, WebP, AVIF, and ICO. SVG and general-purpose HTML, XML, JSON, JavaScript, CSS, video, audio, PDF, and arbitrary binary responses are rejected. Proxy failures retain normal HTTP failure semantics while server diagnostics avoid logging the credential-bearing upstream URL.

frontend-diagnostics

Enables additional runtime diagnostics intended for development, troubleshooting, and performance investigation. It defaults to false and is not required for normal dashboard operation.

When enabled, Glance records structured browser lifecycle, error, live-update, page-loading, and performance telemetry in the server logs. Performance diagnostics include page-content and initialization timing, live widget replacement timing, browser performance snapshots, long-task observations, and page resource and DOM measurements. Backend HTTP request timing is also recorded so browser-side observations can be correlated with server-side request latency.

Validated browser telemetry is also retained in a bounded in-memory diagnostic store for the lifetime of the running application and is summarized by /api/diagnostics/report. The report includes aggregate browser activity, problem counts, a bounded recent-problem history, and up to 20 recent results from actively requested browser diagnostics without treating historical browser problems as current backend degradation. When frontend diagnostics are disabled, the report states that explicitly; when enabled but no browser telemetry has been received, it reports that state rather than implying browser health.

Enabled diagnostics also provide a typed backend-to-browser diagnostic command channel over the existing live-update connection. When dashboard authorization is configured, operator authorization means the authenticated identity can access every configured runtime dashboard. The operator-authorized POST /api/frontend-diagnostics/performance-snapshot, POST /api/frontend-diagnostics/long-task-capture, and POST /api/frontend-diagnostics/runtime-state endpoints broadcast the corresponding operation to currently connected Glance browsers and return HTTP 202 with a command ID; browser results arrive asynchronously and include that command ID for correlation in structured logs and the RECENT ACTIVE DIAGNOSTIC RESULTS section of /api/diagnostics/report. A performance snapshot reports browser performance, navigation, resource, and memory observations. Long-task capture observes long tasks for a fixed 30-second interval. Runtime state reports visibility, online and live-update connection state, and in-flight or pending live widget replacements. A request can therefore produce results from multiple connected pages or browser sessions. The command channel accepts only diagnostic operations explicitly implemented by Glance and does not provide arbitrary command arguments or remote JavaScript execution.

Go pprof endpoints are enabled at the same time on a separate loopback-only listener at 127.0.0.1:6060. The profiling listener is not registered on the normal Glance HTTP router and is therefore intended for local diagnostic access from the Glance host. The repository Makefile provides controlled capture and summary targets for development use.

Important

When installing through docker the path will point to the files inside the container. Don't forget to mount your assets path to the same path inside the container. Example:

If your assets are in:

/home/user/glance-assets

You should mount:

/home/user/glance-assets:/app/assets

And your config should contain:

assets-path: /app/assets
Examples

Say you have a directory glance-assets with a file gitea-icon.png in it and you specify your assets path like:

assets-path: /home/user/glance-assets

To be able to point to an asset from your assets path, use the /assets/ path like such:

icon: /assets/gitea-icon.png

Analytics

Glance can optionally load a web analytics provider on dashboard pages. Analytics is disabled when the top-level analytics property is omitted.

GoatCounter is currently supported:

analytics:
  provider: goatcounter
  endpoint: https://analytics.example.com

The endpoint is the origin of the GoatCounter site and may use HTTP or HTTPS, including an explicit port. Do not include /count, /count.js, another path, credentials, a query string, or a fragment; Glance derives the GoatCounter collection and script URLs from the configured origin.

Analytics is loaded only on normal dashboard page documents. Dashboard navigation uses normal document loads, so GoatCounter's standard page-load tracking is sufficient; widget refreshes, live widget updates, page-content requests, and SSE activity do not create analytics pageviews.

Analytics is strictly noncritical to Glance operation. Invalid analytics configuration is reported as a recoverable configuration error and analytics is disabled for that application generation; config:validate still reports the configuration as invalid. The provider script is loaded asynchronously in the browser, so an unavailable analytics service, blocked request, browser extension, or deployment policy does not prevent the dashboard from rendering or operating. Glance does not proxy analytics requests, send them through its widget lifecycle, or require an analytics API key.

If your deployment applies a Content Security Policy, allow the configured analytics origin in the directives required for its script and collection requests, typically script-src and connect-src. Glance does not weaken or generate deployment-specific CSP rules for analytics, and enabling analytics does not require unsafe-inline.

Privacy, retention, session tracking, referrer collection, user-agent collection, location-derived reporting, and other analytics behavior remain controlled by the analytics provider and its configuration.

Document

If you want to insert custom HTML into the <head> of the document for all pages, you can do so by using the document property. Example:

document:
  head: |
    <script src="/assets/custom.js"></script>

Branding

You can adjust the various parts of the branding through a top level branding property. Example:

branding:
  custom-footer: |
    <p>Powered by <a href="https://github.com/samcro1967/glance">Glance</a></p>
  logo-url: /assets/logo.png
  favicon-url: /assets/logo.png
  app-name: "My Dashboard"
  app-icon-url: "/assets/app-icon.png"
  app-background-color: "#151519"

Properties

Name Type Required Default
hide-footer bool no false
custom-footer string no
logo-text string no G
logo-url string no
favicon-url string no
app-name string no Glance
app-icon-url string no Glance's default icon
app-background-color string no Glance's default background color

hide-footer

Hides the footer when set to true.

custom-footer

Specify custom HTML to use for the footer.

logo-text

Specify custom text to use instead of the "G" found in the navigation.

logo-url

Specify a URL to a custom image to use instead of the "G" found in the navigation. If both logo-text and logo-url are set, only logo-url will be used.

favicon-url

Specify a URL to a custom image to use for the favicon.

app-name

Specify the name of the web app shown in browser tab and PWA.

app-icon-url

Specify URL for PWA and browser tab icon (512x512 PNG).

app-background-color

Specify background color for PWA. Must be a valid CSS color.

Theme

Glance includes a native theme system for customizing colors, typography, page backgrounds, headers, navigation, widgets, cards, groups and tabs, controls, footers, surfaces, and other visual presentation through YAML configuration.

A top-level theme defines the default appearance. Individual pages can provide partial theme overrides, and the theme picker can switch between the built-in Glance Dark and Glance Light themes and explicitly named user themes. Custom CSS remains available for advanced styling beyond the native theme options.

See the Themes documentation for the complete theme reference, supported values, inheritance and page overrides, theme picker behavior, custom CSS, examples, and ready-to-use themes.

Footer micro-widgets

Footer micro-widgets provide compact page-level information and shortcuts on the left and right sides of the standard Glance footer. They do not occupy page columns or count as normal page widgets.

Footer micro-widgets showing information and shortcuts on both sides of the Glance footer

max-per-side defaults to 5 and may be set from 1 through 10. Each micro-widget requires a position between 1 and max-per-side. Positions must be unique within each side; the same position may be used once on the left and once on the right.

Supported types are bookmark, clock, weather, markets, monitor, docker, and link.

Configuration

footer-micro-widgets:
  max-per-side: 5
  left:
    - type: bookmark
      position: 1
      title: GitHub
      url: https://github.com/samcro1967/glance
      icon: si:github
    - type: weather
      position: 2
      location: St. Louis, Missouri
      units: imperial
    - type: link
      position: 3
      title: Glance Docs
      url: https://github.com/samcro1967/glance/tree/main/docs
  right:
    - type: clock
      position: 1
      hour-format: 12h
      label: Local
    - type: markets
      position: 2
      markets:
        - symbol: SPY
    - type: monitor
      position: 3
      sites:
        - title: Example
          url: https://example.com

Items are displayed in position order. Footer micro-widgets are hidden at viewport widths of 1190px and below and are suppressed whenever the normal footer is hidden with branding.hide-footer.

Bookmark

Displays a titled link with an optional Glance icon.

- type: bookmark
  position: 1
  title: GitHub
  url: https://github.com/samcro1967/glance
  icon: si:github
  same-tab: false

title and url are required. icon is optional. same-tab defaults to false.

Link

Displays a simple titled link without an icon.

- type: link
  position: 3
  title: Glance Docs
  url: https://github.com/samcro1967/glance/tree/main/docs
  same-tab: true

title and url are required. same-tab defaults to false.

Clock

Displays a compact date and time. When timezone is omitted, the browser local timezone is used.

- type: clock
  position: 1
  hour-format: 12h
  timezone: America/Chicago
  label: Local

hour-format defaults to 24h and accepts 12h or 24h. timezone is optional and accepts an IANA timezone such as America/Chicago. label is optional.

Weather

Displays compact current weather using the shared Open-Meteo weather resources.

- type: weather
  position: 2
  location: St. Louis, Missouri
  units: imperial
  show-area-name: false
  hide-location: false
  url: https://example.com/weather
  same-tab: false

location is required. units defaults to metric and accepts metric or imperial. show-area-name optionally includes the returned area name, while hide-location suppresses the location line. url is optional; when configured, the entire compact weather item is clickable. same-tab defaults to false and controls whether that link opens in the current tab.

Weather refreshes on the hourly boundary and equivalent Open-Meteo requests share the existing resource cache.

Markets

Displays compact market symbols and percentage changes using the shared Yahoo Markets resources.

- type: markets
  position: 2
  markets:
    - symbol: SPY
    - symbol: QQQ
  sort-by: absolute-change
  same-tab: false

At least one market symbol is required. stocks is accepted as a compatibility alias when markets is not configured. The optional sort-by setting supports change and absolute-change; when omitted, market results retain their returned order. Each compact market item is clickable and defaults to its Yahoo Finance quote page. Link precedence is an individual market symbol-link, then the widget-level symbol-link-template, then the built-in Yahoo Finance URL. symbol-link-template may contain {SYMBOL}. chart-link-template is also supported and may contain {SYMBOL}. same-tab defaults to false and controls whether symbol links open in the current tab.

Market data uses a one-hour cache and equivalent Yahoo Markets requests share the existing resource cache.

Docker

Displays either one Docker container or a compact Docker summary using the same Docker API and container-state behavior as the Docker Containers widget.

Individual container:

- type: docker
  position: 4
  container: Glance
  sock-path: /var/run/docker.sock

Summary:

- type: docker
  position: 5
  summary: true
  sock-path: /var/run/docker.sock

Exactly one mode is required: configure container for an individual container or set summary: true. sock-path defaults to /var/run/docker.sock and also accepts a remote Docker API source. In individual mode, container matches the final displayed Docker container name after the existing Docker naming rules, including glance.name and format-container-names. Existing Docker glance.url and glance.same-tab labels control navigation. Optional name, url, and same-tab settings can override the displayed name and navigation for the micro-widget.

Summary mode displays containers in the normal running state over the total number returned after Docker filtering is applied. Docker micro-widget data uses a one-minute cache.

Monitor

Displays compact site status using the same site configuration and status behavior as the Monitor widget.

- type: monitor
  position: 3
  show-failing-only: false
  sites:
    - title: Example
      url: https://example.com

At least one site is required. Site entries use the Monitor widget site configuration. When show-failing-only is enabled and every configured site is healthy, the micro-widget displays an all-online state.

Monitor data uses a five-minute cache. Equivalent Monitor requests share cached results rather than issuing duplicate requests.

Dynamic Weather, Markets, Monitor, and Docker micro-widgets participate in the normal Glance initialization, refresh, recovery, and live-update lifecycle. Bookmark, Clock, and Link require no provider refresh.

Pages & Columns

illustration of pages and columns

Using pages and columns is how widgets are organized. Each page contains up to 3 columns and each column can have any number of widgets.

Pages

Pages are defined through a top level pages property.

When dashboards is not configured, Glance uses its standard page behavior: the page defined first becomes the home page and all pages are automatically added to the navigation bar in the order that they were defined.

pages:
  - name: Home
    icon: mdi:home
    columns: ...

  - name: Page 2
    icon: mdi:view-dashboard
    columns: ...

  - name: Page 3
    columns: ...

When named dashboards are configured, pages are still defined only once under pages, but each dashboard controls which pages appear in its navigation and in what order.

Properties

Name Type Required Default
name string yes
icon string no
slug string no
width string no
desktop-navigation-width string no
center-vertically boolean no false
hide-desktop-navigation boolean no false
show-mobile-header boolean no false
head-widgets array no
bottom-widgets array no
columns array yes

name

The name of the page which gets shown in the navigation bar.

icon

An optional icon displayed immediately before the page name in desktop and mobile navigation. The value can be a direct image URL or an icon-library reference using the si:, sh:, di:, or mdi: prefixes documented in Icons. Prefix the value with auto-invert to automatically invert the icon for dark themes where supported.

Page icons are configured directly on individual pages and do not participate in widget-defaults. Omitting icon preserves the standard text-only navigation.

slug

The URL friendly version of the title which is used to access the page. For example if the title of the page is "RSS Feeds" you can make the page accessible via localhost:8080/feeds by setting the slug to feeds. If not defined, it will automatically be generated from the title.

width

The maximum width of the page on desktop. Possible values are default, slim and wide.

desktop-navigation-width

The maximum width of the desktop navigation. Useful if you have a few pages that use a different width than the rest and don't want the navigation to jump abruptly when going to and away from those pages. Possible values are default, slim and wide.

Here are the pixel equivalents for each value:

  • default: 1600px
  • slim: 1100px
  • wide: 1920px

Note

When using slim, the maximum number of columns allowed for that page is 2.

center-vertically

When set to true, vertically centers the content on the page. Has no effect if the content is taller than the height of the viewport.

hide-desktop-navigation

Whether to show the navigation links at the top of the page on desktop.

show-mobile-header

Whether to show a header displaying the name of the page on mobile. The header purposefully has a lot of vertical whitespace in order to push the content down and make it easier to reach on tall devices.

Preview:

head-widgets

Head widgets will be shown at the top of the page, above the columns, and take up the combined width of all columns. You can specify any widget, though some will look better than others, such as the markets, RSS feed with horizontal-cards style, and videos widgets. Example:

pages:
  - name: Home
    head-widgets:
      - type: markets
        hide-header: true
        markets:
          - symbol: SPY
            name: S&P 500
          - symbol: BTC-USD
            name: Bitcoin
          - symbol: NVDA
            name: NVIDIA
          - symbol: AAPL
            name: Apple
          - symbol: MSFT
            name: Microsoft

    columns:
      - size: small
        widgets:
          - type: calendar
      - size: full
        widgets:
          - type: hacker-news
      - size: small
        widgets:
          - type: weather
            location: London, United Kingdom

bottom-widgets

Bottom widgets will be shown at the bottom of the page, below the columns, and take up the combined width of all columns. As with head-widgets, you can specify any widget, though widgets designed for wider layouts will generally work best.

Example:

pages:
  - name: Home
    columns:
      - size: small
        widgets:
          - type: calendar
      - size: full
        widgets:
          - type: hacker-news
      - size: small
        widgets:
          - type: weather
            location: London, United Kingdom

    bottom-widgets:
      - type: videos
        channels:
          - UC_x5XG1OV2P6uZZ5FSM9Ttw

Preview:

Named dashboards

Named dashboards allow the same configured pages to be organized into multiple independently addressable navigation sets.

Pages continue to be defined once under the top-level pages property. The optional top-level dashboards property selects which pages belong to each dashboard and controls their navigation order.

A page can belong to multiple dashboards. The page itself is not duplicated: each dashboard uses the same underlying page, widgets, cached data, and update lifecycle.

Example:

pages:
  - name: Home
    slug: home
    columns: ...

  - name: Page 2
    slug: page2
    columns: ...

  - name: Page 3
    slug: page3
    columns: ...

  - name: Shared
    slug: shared
    columns: ...

dashboards:
  Default:
    - home
    - page2
    - page3
    - shared

  Personal:
    - home
    - page2
    - shared

  Family:
    - home
    - page3
    - shared

Dashboard entries reference pages by their slug. If a page does not explicitly define a slug, its automatically generated slug is used.

Preview:

Default dashboard

When dashboards is configured, a dashboard named Default is required.

The Default dashboard controls the standard Glance routes. Its first page becomes the home page at /, and its pages use their normal top-level paths.

Using the example above:

/          -> Home
/page2     -> Page 2
/page3     -> Page 3
/shared    -> Shared

Only pages assigned to Default appear in the default navigation.

Named dashboard routes

Every dashboard other than Default receives its own URL prefix generated from the dashboard name.

The first page assigned to the dashboard becomes its dashboard home page.

For example, the Personal dashboard above is available at:

/personal/         -> Home
/personal/page2    -> Page 2
/personal/shared   -> Shared

The Family dashboard is available at:

/family/         -> Home
/family/page3    -> Page 3
/family/shared   -> Shared

Dashboard switcher

When named dashboards are configured, the application logo in the desktop navigation acts as a dashboard switcher.

Selecting the logo opens a menu containing all available dashboards in the same order they are defined under dashboards. The currently active dashboard is indicated in the menu.

Selecting a dashboard navigates to that dashboard's home page:

Default  -> /
Personal -> /personal/
Family   -> /family/

The switcher can be closed by selecting the logo again, clicking outside the menu, or pressing Escape. When the logo is focused using keyboard navigation, Enter or Space opens or closes the switcher.

On mobile, the available dashboards are shown with the other mobile navigation actions.

When dashboards is not configured, the application logo retains the standard Glance behavior and no dashboard switcher is shown.

Navigation within a named dashboard remains inside that dashboard. For example, selecting Shared while viewing the Family dashboard links to /family/shared rather than /shared.

A page that exists globally but is not assigned to a particular dashboard cannot be accessed through that dashboard's route.

Shared pages

Pages referenced by multiple dashboards are shared rather than copied.

For example, because shared belongs to Default, Personal, and Family, all three dashboard routes render the same configured Shared page:

/shared
/personal/shared
/family/shared

This means you do not need separate page configurations for each dashboard, and widgets retain the same caching and update behavior regardless of which dashboard is used to view the page.

Backward compatibility

The dashboards property is optional.

If it is omitted, Glance behaves exactly as it does without this feature:

  • the first configured page is the home page;
  • all configured pages appear in navigation;
  • pages use their normal top-level routes.

Existing configurations therefore continue to work without modification.

Validation

When dashboards is configured:

  • a Default dashboard is required;
  • each dashboard must contain at least one page;
  • every referenced page slug must exist;
  • the same page cannot be listed more than once in a dashboard;
  • dashboard names must generate unique URL slugs;
  • dashboard slugs cannot conflict with reserved Glance routes.

Named dashboard slugs also cannot conflict with page slugs. If a named dashboard generates the same slug as an existing page, that dashboard is ignored and a warning is logged. Glance continues running with the remaining valid dashboards and pages.

For example, if a page uses the slug personal, a named dashboard that also generates the slug personal will be ignored. The existing /personal page route remains available.

The order of pages in each dashboard determines both the navigation order and which page becomes that dashboard's home page.

Columns

Columns are defined for each page using a columns property. There are three column sizes: full, medium and small.

A small column has a fixed width of 300px. A full column takes up the remaining available width. A medium column is used for proportional layouts: three medium columns divide the available width evenly, while a medium column paired with a full column uses approximately one third and two thirds of the available width, respectively.

Pages can have up to 3 columns. Traditional layouts using only small and full columns must contain either 1 or 2 full columns. When using medium, the supported layouts are three medium columns, or one medium column paired with one full column in either order.

When the page is displayed using the mobile layout, one column is shown at a time regardless of its configured size.

Example:

pages:
  - name: Home
    columns:
      - size: small
        widgets: ...
      - size: full
        widgets: ...
      - size: small
        widgets: ...

Properties

Name Type Required
size string yes
widgets array no

The size property accepts small, medium or full.

Here are some of the possible traditional column configurations:

columns:
  - size: small
    widgets: ...
  - size: full
    widgets: ...
  - size: small
    widgets: ...
columns:
  - size: full
    widgets: ...
  - size: small
    widgets: ...
columns:
  - size: full
    widgets: ...
  - size: full
    widgets: ...

Three equal-width columns can be configured using medium:

columns:
  - size: medium
    widgets: ...
  - size: medium
    widgets: ...
  - size: medium
    widgets: ...

Preview:

A one-third/two-thirds layout can be configured with medium and full:

columns:
  - size: medium
    widgets: ...
  - size: full
    widgets: ...

Preview:

The order can be reversed to place the wider column first:

columns:
  - size: full
    widgets: ...
  - size: medium
    widgets: ...

Widgets

Widgets are the individual components used to build Glance pages. See the widget catalog and reference for available widgets, shared widget properties, examples, and configuration details.


Glance README · Widgets · Themes · Preconfigured pages · Back to top