v0.8.0
glanceapp/glancev0.8.0May 13, 2025by svilenmarkov
AI Summary
This major release introduces authentication, theme picker, nested config includes, Docker secrets, to-do widget, head widgets, PWA configuration, and significant enhancements to multiple widgets including Docker containers, Custom API, Reddit, RSS, Monitor, and DNS Stats.
Key Highlights
- New authentication system with username/password and password hashing
- Theme picker with multiple presets
- Nested config includes with new $include syntax
- Docker secrets support in config
- To-do widget with local storage
- Head widgets for full-width widgets above columns
- Hiding widget headers
- Separate navigation and page widths
- PWA configuration options
- Docker containers widget enhancements with proxies and category
- Custom API synchronous calls and options property
- Reddit application auth support
- RSS conditional requests
- Monitor widget basic-auth and timeout
- DNS Stats Technitium support
New Features
- Authentication with username/password and password-hash
- Theme picker with presets
- Nested config includes ($include syntax)
- Docker secrets support (${secret:...})
- To-do widget
- Hide widget headers (hide-header property)
- Head widgets
- Separate desktop-navigation-width
- PWA configuration (branding)
- Docker containers customization in config
- Docker containers proxy support
- Docker containers category property
- Custom API synchronous API calls
- Custom API options property
- Reddit application authentication
- RSS conditional requests (ETag/Last-Modified)
- Monitor basic-auth
- Monitor timeout
- DNS Stats Technitium support
Full Release Notes
Another big update is here! This one includes authentication, a theme picker, new customization options, a to-do widget and lots of improvements to existing widgets. Before we get to details of all that...
## Feedback wanted
Deciding what features to add to a project like this is no easy task. Most self-hosted services focus on doing one thing and adding features around that thing, but with a personal dashboard/feed aggregator you can practically display _anything_, so how do you decide what does and doesn't belong? So far I've been prioritizing feature requests with a high number of upvotes and those I believe fit with the vision of the project, although admittedly Glance has deviated quite a bit from its initial purpose.
As with almost all communities, a minority of people are very vocal about their wants and needs, while the majority are just riding along. Rather than guessing what the community as a whole would benefit from the most moving forward, I thought I could just ask through a short survey.
[Link to the survey](https://docs.google.com/forms/d/e/1FAIpQLSdoNDjJYugVm6kb2NpVO5QO1inGbEeuydkta-XEIMRbgYIsXg/viewform)
It's entirely anonymous, should only take about 1 to 3 minutes to complete, and I'd be happy to share the results once there are enough responses. Thank you to those who take the time to fill it out.
## Jump to section
* [Community widgets](#g-rh-1)
* [New logo](#g-rh-2)
* [New features](#g-rh-3)
- [Nested config includes and new include syntax](#g-rh-4)
- [Using Docker secrets within the config](#g-rh-5)
- [Theme picker](#g-rh-6)
- [Authentication](#g-rh-7)
- [To-do widget](#g-rh-8)
- [Hiding widget titles](#g-rh-9)
- [Head widgets](#g-rh-10)
- [Separate navigation and page widths](#g-rh-11)
- [PWA configuration](#g-rh-12)
* [Widget enhancements](#g-rh-13)
- [[Docker containers] Container customization in the config, support for proxies, `category` and `format-container-names` properties](#g-rh-14)
- [[Custom API] Synchronous API calls and `options` property](#g-rh-15)
- [[Reddit] Support for application auth](#g-rh-16)
- [[RSS] Conditional requests](#g-rh-17)
- [[Monitor] `basic-auth` and `timeout` properties](#g-rh-18)
- [[DNS Stats] Support for Technitium](#g-rh-19)
## <a id="g-rh-1"></a> Community widgets
If you weren't aware, there's now [a repository for widgets made by the community](https://github.com/glanceapp/community-widgets) with 40+ widgets available so far. Most are made using the `custom-api` widget, so adding them is as simple as copying them into your `glance.yml`. It's a great place to find new widgets, and if you have a widget that you think others would benefit from, please consider sharing it there. Thank you to everyone who has contributed!
## <a id="g-rh-2"></a> New logo
Big thanks to @Tom607 for offering help with the logo and going over dozens of different iterations!

I believe it does a great job at conveying the widgety layout of Glance, while also being simple and clean, as is the rest of the design language.
## <a id="g-rh-3"></a> New features
### <a id="g-rh-4"></a> Nested config includes and new include syntax
Up until now, you could only use the `!include` directive in your `glance.yml` file, but not within any of the included files. This has been changed so that you can includes files from within included files as many times as you need, meaning you can have a separate file for each page, a separate file for each column, and even a separate file for each widget if you wanted to:
```
glance.yml
├── home.yml
│ ├── column1.yml
│ │ ├── widget1.yml
│ │ └── widget2.yml
│ └── column2.yml
│ ├── widget3.yml
│ └── widget4.yml
```
In addition, the `!include` directive can now instead be written as `$include`. The reason for this change is that it turns out `!include`, with the way it was used in Glance, is not actually valid YAML (whoops), meaning it makes YAML validators and syntax highlighters angry. The new `$include` syntax is valid YAML and will be the preferred syntax moving forward. You can also add a `-` at the beginning of a line when including array items, since that's the expected syntax for YAML arrays.
Before:
```yaml
theme:
!include: theme.yml
pages:
!include: home.yml
!include: homelab.yml
!include: startpage.yml
```
Now:
```yaml
theme:
$include: theme.yml
pages:
- $include: home.yml
- $include: homelab.yml
- $include: startpage.yml
```
<br>
### <a id="g-rh-5"></a> Using Docker secrets within the config
Along with environment variables, you can now use [Docker secrets](https://docs.docker.com/compose/how-tos/use-secrets/) in your config file using the following syntax:
```yaml
token: ${secret:github_token} # Reads the contents of /run/secrets/github_token
token: ${GITHUB_TOKEN} # Environment variable
```
(thanks @gomeology)
<br>
### <a id="g-rh-6"></a> Theme picker
You can now define multiple theme presets and switch between them in the UI, no more config changes needed to change the theme!

<details>
<summary>View config</summary>
```yaml
theme:
presets:
neon-focus:
background-color: 255 14 6
primary-color: 156 50 65
negative-color: 342 65 65
contrast-multiplier: 0.9
text-saturation-multiplier: 0.8
gruvbox-dark:
background-color: 0 0 16
primary-color: 43 59 81
positive-color: 61 66 44
negative-color: 6 96 59
catppuccin-macchiato:
background-color: 232 23 18
contrast-multiplier: 1.2
primary-color: 220 83 75
positive-color: 105 48 72
negative-color: 351 74 73
peachy:
light: true
background-color: 28 40 77
primary-color: 155 100 20
negative-color: 0 100 60
contrast-multiplier: 1.1
text-saturation-multiplier: 0.5
```
</details>
Glance will include its own default dark and light themes in the list of presets, which you can override by using the `default-dark` and `default-light` keys.
(thanks @hecht-a)
<br>
### <a id="g-rh-7"></a> Authentication
You can now add authentication via username and password:

```yaml
auth:
secret-key: # this must be set to a random value generated using the secret:make CLI command
users:
admin:
password: ${ADMIN_PASSWORD}
```
While there is support for multiple users, you cannot customize the dashboard per user at this time, so all users will see the same dashboard.
To generate the secret key, use the `secret:make` CLI command:
```bash
docker run --rm glanceapp/glance secret:make
```
Or with the binary:
```bash
/opt/glance/glance secret:make
```
If you do not want to store plain passwords in environment variables or in files, you can hash your password and provide it via the `password-hash` property instead:
```yaml
auth:
secret-key: # this must be set to a random value generated using the secret:make CLI command
users:
admin:
password-hash: $2y$10$...
```
To hash your password, use the `password:hash <password>` CLI command:
```bash
docker run --rm glanceapp/glance password:hash mypasswordishunter2
```
Or with the binary:
```bash
/opt/glance/glance password:hash mypasswordishunter2
```
<br>
### <a id="g-rh-8"></a> To-do widget
A fairly simple to-do widget with the ability to add, edit, reorder and delete tasks:

```yaml
- type: to-do
```
There are a number of keyboard shortcuts available that make it easier to use, which you can find over at the [config docs](https://github.com/glanceapp/glance/blob/main/docs/configuration.md#todo).
The tasks are stored in the browser's local storage, so they won't be available on all devices. If you want to add multiple todo widgets, you must specify a unique `id` for each one:
```yaml
- type: to-do
title: Work tasks
id: work
- type: to-do
title: Personal tasks
id: personal
```
(thanks @AMS003010)
<br>
### <a id="g-rh-9"></a> Hiding widget headers
A fairly simple addition, but one that's been requested quite a few times - you can now hide widget headers by setting the `hide-header` property to `true`:
```yaml
widgets:
- type: calendar
hide-header: true
```
If you do this for all widgets, you get something like this:

Note that you cannot hide the header of the group widget since it's used to switch between each widget.
<br>
### <a id="g-rh-10"></a> Head widgets
You can now define "head widgets" on each page, which are basically widgets that sit above all columns and take up the full width. Combined with the `hide-header` property, you get something like this:

<details>
<summary>View config</summary>
```yaml
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
```
</details>
This works well for displaying mostly horizontal widgets such as the videos widget, RSS widget with `horizontal-cards` style, or widgets which span their items horizontally, such as the markets widget.
<br>
### <a id="g-rh-11"></a> Separate navigation and page widths
You can now have different desktop navigation and content widths:
```yaml
pages:
- name: Home
width: slim
desktop-navigation-width: wide
columns:
...
```
By default `desktop-navigation-width` will inherit the value of `width`, but can explicitly be set to a different value (`default`, `slim` or `wide`). Using this property, if one of your pages has a different width than the rest, you can set the navigation to be the same width as the rest of the pages, meaning no more jankiness when switching between pages of different widths!
<br>
### <a id="g-rh-12"></a> PWA configuration
You can now configure PWA things such as the app name, icon and theme color:
```yaml
branding:
app-name: Not Glance
app-icon: /assets/path/to/icon.png
app-background-color: '#000000' # ideally in hex format, since support for other formats is inconsistent between browsers
```
(thanks @dvdpearson)
<br>
## <a id="g-rh-13"></a> Widget enhancements
### <a id="g-rh-14"></a> [Docker containers] Container customization in the config, support for proxies and `category` property
Instead of using docker labels to customize the containers, you can now do so within your `glance.yml`:
```yaml
- type: docker-containers
containers:
container_name_1:
name: Container Name
description: Description of the container
url: https://container.domain.com
icon: si:container-icon
hide: false
container_name_2:
name: Other Container Name
description: Other description of the container
url: https://other-container.domain.com
icon: si:container-icon
hide: false
```
(thanks @mike391)
<br>
You can now also specify a [proxied docker socket](https://github.com/Tecnativa/docker-socket-proxy) URI instead of a path to a socket file:
```yaml
- type: docker-containers
sock-path: http://docker-socket-proxy:2375 # tcp:// also works
```
(thanks @retmas-gh)
<br>
The new `category` property allows you to split up categories of containers into different widgets:
`glance.yml`:
```yaml
# This will only list containers which have the glance.category label "tools"
- type: docker-containers
title: Tools
category: tools
# This will only list containers which have the glance.category label "arr"
- type: docker-containers
title: Arr
category: arr
```
`docker-compose.yml`:
```yaml
services:
my-container:
image: my-image
labels:
glance.category: tools
my-other-container:
image: my-image
labels:
glance.category: arr
```
(thanks @shareef945)
<br>
### <a id="g-rh-15"></a> [Custom API] Synchronous API calls and `options` property
So far you could only run asynchronous API calls, meaning you couldn't use the result of one API call in another. There is now support for synchronous API calls within the template itself:
```yaml
- type: custom-api
url: https://api.example.com/get-id-of-something
template: |
{{/* The ID is taken from the first API call */}}
{{ $theID := .JSON.String "id" }}
{{/* Then used in the second API call */}}
{{
$something := newRequest (concat "https://api.example.com/something/" $theID)
| withParameter "key" "value"
| withHeader "Accept" "application/json"
| getResponse
}}
{{ $something.JSON.String "title" }}
```
You can optionally add query parameters using `withParameter`, headers with `withHeader`, and turn the request method into `POST` with a string body via `withStringBody`. This also means that you can conditionally execute requests within if statements, unlike with the `subrequests` property which executes all requests every time the cache expires.
In addition, the `url` property is now optional, meaning you can execute requests solely within the template. This is useful if you need to supply dynamic parameters to the endpoint:
```yaml
- type: custom-api
title: Events from the last 24h
template: |
{{
$events := newRequest "https://api.example.com/events"
| withParameter "after" (offsetNow "-24h" | formatTime "rfc3339")
| getResponse
}}
{{ if eq $events.Response.StatusCode 200 }}
{{ range $events.JSON.Array "events" }}
<div>{{ .String "title" }}</div>
<div {{ .String "date" | parseTime "rfc3339" | toRelativeTime }}></div>
{{ end }}
{{ else }}
<p>Failed to fetch data: {{ $events.Response.Status }}</p>
{{ end }}
```
There's a new `options` property which allows you to specify configurable options within the widget, rather than within the template.
<details>
<summary>View example</summary>
Instead of defining options within the template and having to modify the template itself like such:
```yaml
- type: custom-api
template: |
{{ /* User configurable options */ }}
{{ $collapseAfter := 5 }}
{{ $showThumbnails := true }}
{{ $showFlairs := false }}
<ul class="list list-gap-10 collapsible-container" data-collapse-after="{{ $collapseAfter }}">
{{ if $showThumbnails }}
<li>
<img src="{{ .JSON.String "thumbnail" }}" alt="" />
</li>
{{ end }}
{{ if $showFlairs }}
<li>
<span class="flair">{{ .JSON.String "flair" }}</span>
</li>
{{ end }}
</ul>
```
You can use the `.Options` object to retrieve and define default values for these variables:
```yaml
- type: custom-api
template: |
{{ $collapseAfter := .Options.IntOr "collapse-after" 5 }}
{{ $showThumbnails := .Options.BoolOr "show-thumbnails" true }}
{{ $showFlairs := .Options.BoolOr "show-flairs" false }}
<ul class="list list-gap-10 collapsible-container" data-collapse-after="{{ $collapseAfter }}">
{{ if $showThumbnails }}
<li>
<img src="{{ .JSON.String "thumbnail" }}" alt="" />
</li>
{{ end }}
{{ if $showFlairs }}
<li>
<span class="flair">{{ .JSON.String "flair" }}</span>
</li>
{{ end }}
</ul>
```
This way, you can optionally specify the `collapse-after`, `show-thumbnails` and `show-flairs` properties in the widget configuration:
```yaml
- type: custom-api
options:
collapse-after: 5
show-thumbnails: true
show-flairs: false
```
Which allows you to reuse the same template multiple times with different options:
```yaml
# Note that `custom-widgets` isn't a special property, it's just used to define the reusable "anchor", see https://support.atlassian.com/bitbucket-cloud/docs/yaml-anchors/
# The contents of the widget could also be included from its own file
custom-widgets:
- &example-widget
type: custom-api
template: |
{{ .Options.StringOr "custom-option" "not defined" }}
pages:
- name: Home
columns:
- size: full
widgets:
- <<: *example-widget
options:
custom-option: "Value 1"
- <<: *example-widget
options:
custom-option: "Value 2"
```
Currently, the available methods on the `.Options` object are: `StringOr`, `IntOr`, `BoolOr` and `FloatOr`.
</details>
<br>
### <a id="g-rh-16"></a> [Reddit] Support for application auth
Instead of using a proxy to bypass Reddit's restrictions of VPS IPs, you can now use your own Reddit application credentials to authenticate with Reddit's API:
```yaml
- type: reddit
subreddit: technology
app-auth:
name: ${REDDIT_APP_NAME}
id: ${REDDIT_APP_CLIENT_ID}
secret: ${REDDIT_APP_SECRET}
```
To create an app on Reddit, go to [this page](https://ssl.reddit.com/prefs/apps/).
(thanks @s0ders)
<br>
### <a id="g-rh-17"></a> [RSS] Conditional requests
RSS feeds are usually the slowest widgets to load, leading to longer than necessary loading times. To help with this, the RSS widget now supports conditional requests, meaning it will use either the `ETag` or `Last-Modified` headers provided by the server, if available, to conditionally request the feed only if it has changed since the last request. This should speed things up in some cases and make sysadmins a little happier.
(thanks @charlesharries)
<br>
### <a id="g-rh-18"></a> [Monitor] `basic-auth` and `timeout` properties
The monitor widget now has support for basic authentication and a timeout property:
```yaml
- type: monitor
cache: 1m
title: Services
sites:
- title: Jellyfin
url: https://jellyfin.yourdomain.com
icon: si:jellyfin
timeout: 10s
- title: Gitea
url: https://gitea.yourdomain.com
icon: si:gitea
basic-auth:
username: ${GITEA_USERNAME}
password: ${GITEA_PASSWORD}
```
(thanks @logoff, @ejsadiarin and @FabianK3)
<br>
### <a id="g-rh-19"></a> [DNS Stats] Support for Technitium
The DNS stats widget now has support for [Technitium DNS](https://technitium.com/dns/):
```yaml
- type: dns-stats
service: technitium
token: ${TECHNITIUM_TOKEN}
```
(thanks @anarqist and @KevinFumbles)
<br>
## Fixes
* Fixed an issue with the weather widget where some locations were not being returned properly (thanks @MooToYou)
* Fixed an issue with some widgets where user-provided URLs were being escaped when they shouldn't be (thanks @Kamalaja)
<br>
## Thank you
Thank you to everyone who has continued to [sponsor](https://github.com/sponsors/glanceapp) the project, and to those who have contributed in any way. I really appreciate it!
<br>
## Merged PRs
* Added Technitium Service Option to DNS-Stats Widget by @KevinFumbles in https://github.com/glanceapp/glance/pull/339
* feat(monitor): add basic-auth feature for protected sites by @ejsadiarin in https://github.com/glanceapp/glance/pull/367
* feat: add parameters and array parameters support by @ralphocdol in https://github.com/glanceapp/glance/pull/378
* fix: full width clickable link for monitor-site by @ralphocdol in https://github.com/glanceapp/glance/pull/405
* feat: custom-api multiple API queries by @ralphocdol in https://github.com/glanceapp/glance/pull/385
* make title-url of pihole and pihole-v6 default to /admin by @ralphocdol in https://github.com/glanceapp/glance/pull/466
* Add bing and perplexity as search engines by @jpinz in https://github.com/glanceapp/glance/pull/476
* Add Kagi and Startpage as search engines by @stripedew in https://github.com/glanceapp/glance/pull/480
* Add replaceMatches function to custom-api by @ralphocdol in https://github.com/glanceapp/glance/pull/542
* Add filter on already seen links for RSS feeds by @HtFilia in https://github.com/glanceapp/glance/pull/494
* added unique to filter arrays with unique items in custom-api by @ralphocdol in https://github.com/glanceapp/glance/pull/580
* [sensors] allow sensor readings when there are warnings by @anxdpanic in https://github.com/glanceapp/glance/pull/583
* Support embed icons on bookmarks URLs by @hitalos in https://github.com/glanceapp/glance/pull/578
* Dynamize manifest.json with configurable options by @dvdpearson in https://github.com/glanceapp/glance/pull/602
* update error reporting for custom-api JSON validation by @anxdpanic in https://github.com/glanceapp/glance/pull/594
* Feat: Added support for configuring Docker containers through glance.yaml instead of labels by @mike391 in https://github.com/glanceapp/glance/pull/453
* Minor design tweak, polishing up the polyline corners by @mmshivesh in https://github.com/glanceapp/glance/pull/623
* feat: Use conditional requests for RSS feeds by @charlesharries in https://github.com/glanceapp/glance/pull/462
* feat: theme switcher by @hecht-a in https://github.com/glanceapp/glance/pull/299
* v0.8.0 by @svilenmarkov in https://github.com/glanceapp/glance/pull/648
## New Contributors
* @KevinFumbles made their first contribution in https://github.com/glanceapp/glance/pull/339
* @ejsadiarin made their first contribution in https://github.com/glanceapp/glance/pull/367
* @jpinz made their first contribution in https://github.com/glanceapp/glance/pull/476
* @stripedew made their first contribution in https://github.com/glanceapp/glance/pull/480
* @HtFilia made their first contribution in https://github.com/glanceapp/glance/pull/494
* @anxdpanic made their first contribution in https://github.com/glanceapp/glance/pull/583
* @hitalos made their first contribution in https://github.com/glanceapp/glance/pull/578
* @dvdpearson made their first contribution in https://github.com/glanceapp/glance/pull/602
* @mike391 made their first contribution in https://github.com/glanceapp/glance/pull/453
* @mmshivesh made their first contribution in https://github.com/glanceapp/glance/pull/623
* @charlesharries made their first contribution in https://github.com/glanceapp/glance/pull/462
**Full Changelog**: https://github.com/glanceapp/glance/compare/v0.7.13...v0.8.0