Are you tired of fighting with restrictive Google Workspace calendar permissions just to see your next daily standup on your dashboard? You are not alone. Building a clean developer start page should not require exposing your private schedule to the public internet or wrestling with complex OAuth flows.
I put together a ready-to-run gethomepage/homepage dashboard config that includes a self-contained meeting countdown and live timer. It needs no API key, no public calendar, and no OAuth – it is pure JavaScript injected through Homepage's custom.js.
Point it at a service, get a clean developer start page. The bonus is a floating card that counts down to your next meeting and turns into a live "30m left" timer while it is running.
Why This Exists
Homepage's built-in Calendar widget can only read an unauthenticated .ics feed. On a Google Workspace account, the private or secret iCal address is disabled by default. Usually, only an admin can turn it on, and making your work calendar public is simply a non-starter for most professionals.
So instead of fighting the calendar, this repository ships a dependency-free timer: you declare your recurring meeting once in config/custom.js and get a live countdown on the dashboard – no keys, no sharing, and no admin approval required.
(If you do have a private .ics link, there is a ready-made block to switch to a real live feed – see the Optional section below.)
Features
- Meeting timer – counts down to the next occurrence, flips to a live "time left" timer during the meeting, then rolls to the next one.
-
Recurring & multi-meeting – per-meeting weekday rules (
[1,2,3,4,5]for weekdays, etc.) and as many meetings as you want. - Live state – a pulsing indicator and "click to join" (opens your Meet/Zoom link) while running.
- Zero credentials – no API key, no OAuth, no public calendar required.
- Docker Compose – one command to run.
- Dark, glassy theme – configured with a background image, blurred cards, and weather/system widgets.
Screenshot
Here is a look at the dashboard in action:
Zayan-Mohamed
/
homepage-dev-dashboard
A self-hosted gethomepage/homepage dashboard with a zero-dependency meeting countdown & live timer — no API key, no public calendar, no OAuth. Pure custom.js.
Homepage Dev Control Center — with a no-API-key Meeting Timer
A ready-to-run gethomepage/homepage dashboard config, plus a
self-contained meeting countdown / live timer that needs no API key, no public
calendar, and no OAuth — it's pure JavaScript injected through Homepage's custom.js.
Point it at a service, get a clean developer start page. The bonus is a floating card that counts down to your next meeting and turns into a live "🔴 30m left" timer while it's running.
Table of contents
- Why this exists
- Features
- Screenshots
- Prerequisites
- Quick start
- Repository layout
- The meeting timer
- Optional: live Google Calendar feed (no API key)
- Customizing the dashboard
- Favicon
- Troubleshooting
- Credits & license
Why this exists
Homepage's built-in Calendar widget can only read an unauthenticated .ics feed. On a
Google Workspace account the private/secret iCal address is disabled by default and only an
admin…
Prerequisites
- Docker and Docker Compose
- Port
8080free on the host (change it indocker-compose.ymlif needed)
Quick Start
git clone https://github.com/Zayan-Mohamed/homepage-dev-dashboard.git
cd homepage-dev-dashboard/
# Create your local config from the templates (these hold personal links,
# so they are git-ignored – the repo ships *.example versions).
cp config/services.yaml.example config/services.yaml
cp config/custom.js.example config/custom.js
docker compose up -d
Open http://localhost:8080, then edit config/services.yaml (your links) and config/custom.js (your meetings).
To apply config changes later:
docker compose restart homepage
Homepage hot-reloads most
config/*.yamlchanges, butcustom.js,custom.css, and the favicon are cached by the browser – do a hard refresh (Ctrl/Cmd + Shift + R) after editing.
Repository Layout
.
├── docker-compose.yml # Homepage container (port 8080 -> 3000)
├── images/ # Static assets served at /images (background, icons)
│ └── anime-bg.jpg # Dashboard background
└── config/
├── settings.yaml # Title, theme, background, layout, favicon
├── services.yaml # Service cards (Meetings, Dev, Cloud, AI, …)
├── widgets.yaml # Info widgets (weather, clock, resources, search)
├── bookmarks.yaml # Bookmark links
├── docker.yaml # Docker integration
├── custom.css # Styles for the meeting-timer card
├── services.yaml.example # Template -> copy to services.yaml
└── custom.js.example # Template -> copy to custom.js (the meeting timer)
The Meeting Timer
Configuring Your Meetings
Open config/custom.js and edit the MEETINGS array near the top:
const MEETINGS = [
{
title: "Standup",
start: "20:30", // 24-hour "HH:MM", dashboard host's local time
end: "21:15",
days: [0, 1, 2, 3, 4, 5, 6], // 0=Sun … 6=Sat. Use [1,2,3,4,5] for weekdays
join: "https://meet.google.com/your-room", // optional – card becomes clickable
},
// add more meetings as needed…
];
| Field | Meaning |
|---|---|
title |
Label shown on the card |
start |
Start time, 24-hour HH:MM
|
end |
End time, 24-hour HH:MM
|
days |
Array of weekdays it recurs on (0=Sunday … 6=Saturday) |
join |
Optional URL; while live/soon the whole card links to it (new tab) |
When several meetings are defined, a live one always wins; otherwise, the soonest upcoming meeting is shown.
How It Behaves
| Situation | Card Shows |
|---|---|
| Before the meeting |
Standup · today · 8:30 PM – starts in 2h 05m 12s
|
| During the meeting |
Standup · live – 30m 00s left (pulsing indicator) |
| After it ends | rolls forward to the next occurrence |
| No meeting scheduled | No meetings scheduled |
The card is a fixed element in the bottom-right (full-width on mobile). Restyle it in config/custom.css under the #meeting-timer selector.
Timezone Note
Times are evaluated in the timezone of the machine running the container, not your browser. If the host clock differs from where you actually are, set the container timezone in docker-compose.yml:
environment:
HOMEPAGE_ALLOWED_HOSTS: localhost:8080
TZ: Asia/Colombo # <- your timezone
Optional: Live Google Calendar Feed (No API Key)
If your Google admin enables "Share all information, but outsiders cannot change calendars", you get a Secret address in iCal format (private, not publicly discoverable, no API key).
config/services.yaml already contains a commented-out block – paste your link into url: and uncomment it:
- Upcoming:
widget:
type: calendar
view: agenda
maxEvents: 10
showTime: true
integrations:
- type: ical
url: https://calendar.google.com/calendar/ical/you%40example.com/private-XXXXXXXX/basic.ics
name: Meetings
color: green
Homepage's calendar widget supports only unauthenticated
.ics(and the arr apps) – no CalDAV, OAuth, basic-auth, or custom headers. The **public*.icsaddress works too but exposes event details to anyone with the link.
Customizing the Dashboard
-
Services / links –
config/services.yaml -
Info widgets (weather, clock, resources, search) –
config/widgets.yaml -
Title, theme, colors, background, layout –
config/settings.yaml -
Bookmarks –
config/bookmarks.yaml
See the Homepage docs for every available option.
Favicon
Set in config/settings.yaml:
favicon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/homepage.png
Prefer a PNG over SVG – Chrome renders PNG tab icons more reliably. To use your own, drop a file in images/ and reference it as favicon: /images/favicon.png.
Troubleshooting
| Symptom | Fix |
|---|---|
| Timer/favicon not updating | Hard refresh (Ctrl/Cmd + Shift + R); the browser caches both. |
| Timer never appears | Check docker compose logs homepage; confirm custom.js has no JS error. |
| Times are off by hours | Set TZ in docker-compose.yml (see Timezone note). |
| Calendar widget shows an error | The .ics URL is unreachable/private – see the calendar section above. |
| Config change not reflected |
docker compose restart homepage. |
Credits & License
- Built on gethomepage/homepage (GPL-3.0).
- Icons from homarr-labs/dashboard-icons.
- The meeting timer (
custom.js/custom.css) is provided as-is – use, fork, and adapt freely.

Top comments (0)