README.md

September 25, 2025 ยท View on GitHub

- type: custom-api
  title: PROXMOX-VE NODES
  title-url: https://${PROXMOXVE_URL}
  cache: 1m
  url: https://${PROXMOXVE_URL}/api2/json/nodes
  allow-insecure: true
  headers:
    Accept: application/json
    Authorization: PVEAPIToken=${PROXMOXVE_KEY}
  options:
    uptime-mode: duration  # relative | duration
    collapse-after: 5
  template: | #html
    {{ $uptimeMode := .Options.StringOr "uptime-mode" "relative" }}
    {{ $collapseAfter := .Options.IntOr "collapseAfter" 3 }}
    <ul class="list list-gap-14 collapsible-container" data-collapse-after="{{ $collapseAfter }}">
      {{ range .JSON.Array "data" }}
      <li>
        <div class="server" proxmox-node="{{ .String "node" }}">
          <div class="server-info">
              <div class="server-details">
                  <div class="server-name color-highlight size-h3 text-truncate">
                    {{ .String "node" }}
                  </div>
                  <div>
                      {{ if eq $.Response.StatusCode 200 }}
                        <div data-popover-type="html">
                          <div data-popover-html>
                            {{ if eq $uptimeMode "relative" }}
                              <span {{ now.Add (duration (concat "-" (.String "uptime") "s")) | toRelativeTime }}></span>
                            {{ else }}
                              <span>{{ duration (concat (.String "uptime") "s") }}</span>
                            {{ end }}
                          </div>
                          <div>
                            {{ if ne $uptimeMode "relative" }}
                              <span {{ now.Add (duration (concat "-" (.String "uptime") "s")) | toRelativeTime }}></span>
                            {{ else }}
                              <span>{{ duration (concat (.String "uptime") "s") }}</span>
                            {{ end }}
                          </div>
                        </div>
                      {{ else }}
                        {{ .String "status" }}
                      {{ end }}
                  </div>
              </div>
              <svg class="server-icon" stroke="var(--color-{{ if eq (.String "status") "online" }}positive{{ else }}negative{{ end }})" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5">
                  <path stroke-linecap="round" stroke-linejoin="round" d="M21.75 17.25v-.228a4.5 4.5 0 0 0-.12-1.03l-2.268-9.64a3.375 3.375 0 0 0-3.285-2.602H7.923a3.375 3.375 0 0 0-3.285 2.602l-2.268 9.64a4.5 4.5 0 0 0-.12 1.03v.228m19.5 0a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3m19.5 0a3 3 0 0 0-3-3H5.25a3 3 0 0 0-3 3m16.5 0h.008v.008h-.008v-.008Zm-3 0h.008v.008h-.008v-.008Z" />
              </svg>
          </div>
          <div class="server-stats">
              <div class="flex-1">
                  <div class="flex items-end size-h5">
                      <div>CPU</div>
                      {{ if (ge (mul (.Float "cpu") 100 | toInt ) 80) }}
                      <svg class="server-spicy-cpu-icon" fill="var(--color-negative)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" >
                          <path fill-rule="evenodd" d="M8.074.945A4.993 4.993 0 0 0 6 5v.032c.004.6.114 1.176.311 1.709.16.428-.204.91-.61.7a5.023 5.023 0 0 1-1.868-1.677c-.202-.304-.648-.363-.848-.058a6 6 0 1 0 8.017-1.901l-.004-.007a4.98 4.98 0 0 1-2.18-2.574c-.116-.31-.477-.472-.744-.28Zm.78 6.178a3.001 3.001 0 1 1-3.473 4.341c-.205-.365.215-.694.62-.59a4.008 4.008 0 0 0 1.873.03c.288-.065.413-.386.321-.666A3.997 3.997 0 0 1 8 8.999c0-.585.126-1.14.351-1.641a.42.42 0 0 1 .503-.235Z" clip-rule="evenodd" />
                      </svg>
                      {{ end }}
                      <div class="color-highlight margin-left-auto text-very-compact">
                        <span>{{ mul (.Float "cpu") 100 | toInt | formatNumber }}</span> <span class="color-base">%</span>
                      </div>
                  </div>
                  <div data-popover-type="html">
                      <div data-popover-html>
                        <div>
                          <div class="flex">
                            <div class="size-h5">LOAD</div>
                            <div class="value-separator"></div>
                            <div class="color-highlight text-very-compact"><span>{{ mul (.Float "cpu") 100 | toInt | formatNumber }}</span> <span class="color-base size-h5">%</span></div>
                          </div>
                          <div class="flex margin-top-3">
                            <div class="size-h5">CORES</div>
                            <div class="value-separator"></div>
                            <div class="color-highlight text-very-compact">{{ .Int "maxcpu" }}</div>
                          </div>
                        </div>
                      </div>
                      <div class="progress-bar progress-bar-combined">
                          <div class="progress-value{{ if ge (mul (.Float "cpu") 100 | toInt) 80 }} progress-value-notice{{ end }}" style="--percent: {{ mul (.Float "cpu") 100 | toInt | formatNumber }}"></div>
                      </div>
                  </div>
              </div>
              <div class="flex-1">
                  <div class="flex justify-between items-end size-h5">
                      <div>RAM</div>
                      <div class="color-highlight text-very-compact">
                        <span>{{ mul (div (.Int "mem" | toFloat) (.Int "maxmem" | toFloat)) 100 | toInt }}</span> <span class="color-base">%</span>
                      </div>
                  </div>
                  <div data-popover-type="html">
                      <div data-popover-html>
                        <div>
                          <div class="flex">
                              <div class="size-h5">RAM</div>
                              <div class="value-separator"></div>
                              <div class="color-highlight text-very-compact">
                                <span>{{ div (.Int "mem" | toFloat) 1073741824 | toInt | formatNumber }}GB</span>
                                <span class="color-base size-h5">/</span>
                                <span>{{ div (.Int "maxmem" | toFloat) 1073741824 | toInt | formatNumber }}GB</span>
                              </div>
                          </div>
                        </div>
                      </div>
                      <div class="progress-bar progress-bar-combined">
                        <div class="progress-value{{ if ge (mul (div (.Int "mem" | toFloat) (.Int "maxmem" | toFloat)) 100 | toInt) 80 }} progress-value-notice{{ end }}" style="--percent: {{ mul (div (.Int "mem" | toFloat) (.Int "maxmem" | toFloat)) 100 | toInt }}"></div>
                      </div>
                  </div>
              </div>
              <div class="flex-1">
                  <div class="flex justify-between items-end size-h5">
                      <div>DISK</div>
                      <div class="color-highlight text-very-compact">
                        <span>{{ mul (div (.Int "disk" | toFloat) (.Int "maxdisk" | toFloat)) 100 | toInt }}</span> <span class="color-base">%</span>
                      </div>
                  </div>
                  <div data-popover-type="html">
                    <div data-popover-html>
                      <div>
                        <div class="flex">
                            <div class="size-h5">DISK</div>
                            <div class="value-separator"></div>
                            <div class="color-highlight text-very-compact">
                                <span>{{ div (.Int "disk" | toFloat) 1073741824 | toInt | formatNumber }}GB</span>
                                <span class="color-base size-h5">/</span>
                                <span>{{ div (.Int "maxdisk" | toFloat) 1073741824 | toInt | formatNumber }}GB</span>
                            </div>
                        </div>
                      </div>
                    </div>
                    <div class="progress-bar progress-bar-combined">
                      <div class="progress-value{{ if ge (mul (div (.Int "disk" | toFloat) (.Int "maxdisk" | toFloat)) 100 | toInt) 80 }} progress-value-notice{{ end }}" style="--percent: {{ mul (div (.Int "disk" | toFloat) (.Int "maxdisk" | toFloat)) 100 | toInt }}"></div>
                    </div>
                  </div>
              </div>
          </div>
        </div>
      </li>
      {{ end }}
    </ul>

Environment variables

PROXMOXVE_URL

the URL of the Proxmox VE server

PROXMOXVE_KEY

You need to generate an API token for it, follow the steps below if you don't have one

See proxmox-ve-stats widget on how to make one.


Credits

titembaataar - For testing with multiple nodes