Getting started
From a downloaded binary to a goal event you can see, without waiting for a real game. About five minutes, no Home Assistant instance required for this part.
You need a terminal and a Goalfeed binary for your platform. This tutorial uses
the test-goals option, which fires a synthetic event once a minute
through the exact same code path a real goal uses — so the "success" at the
end of this page is the real pipeline, not a mockup. Full install options
(Home Assistant add-on, Docker, source) are in the install
guide; this page uses the plain binary because it needs no add-on store and no
Home Assistant instance.
1. Get a binary (about 1 minute)
Download the archive for your platform from the latest release and extract it. On Linux/macOS with the GitHub CLI installed:
# swap linux_amd64 for darwin_arm64, windows_amd64, etc. — see Install for the full list
gh release download --repo goalfeed/goalfeed --pattern "*linux_amd64.tar.gz"
tar xzf goalfeed_*_linux_amd64.tar.gz
cd goalfeed_*_linux_amd64 2>/dev/null || true
Expected result: a goalfeed binary (plus a
web/frontend/build directory bundled in the archive) in your current
directory.
2. Write a minimal config.yaml (about 1 minute)
In the same directory as the binary, create config.yaml:
watch:
nhl:
- WPG
test-goals: true
web: true
web-port: "8099"
No Home Assistant URL or token yet — that's deliberate. This step is about
proving the loop fires, not about wiring the goal horn (that's the
next page). There's no --config flag;
Goalfeed only ever looks for ./config.yaml in the working directory it's
started from — see the configuration
reference.
3. Run it (a few seconds)
./goalfeed
Expected output (real, captured — Goalfeed logs structured JSON via zap, one line per event):
{"level":"info","ts":1787264681.604558,"caller":"goalfeed/main.go:171","msg":"Puck Drop! Initializing Goalfeed Process"}
{"level":"info","ts":1787264681.604706,"caller":"goalfeed/main.go:181","msg":"Initializing Active Games"}
{"level":"info","ts":1787264681.604725,"caller":"goalfeed/main.go:192","msg":"Updating Active Games"}
{"level":"info","ts":1787264681.604807,"caller":"goalfeed/main.go:199","msg":"Checking for active NHL games"}
…
{"level":"info","ts":1787264681.6063309,"caller":"goalfeed/main.go:161","msg":"Starting Goalfeed in web mode"}
…
[GIN-debug] Listening and serving HTTP on :8099
Leave this running — it keeps polling in the foreground. Open a second terminal for the next step.
4. Watch for the test goal (up to 1 minute)
test-goals fires on a one-minute ticker
(time.NewTicker(1 * time.Minute) in main.go), so the first
one lands somewhere between 0 and 60 seconds after startup — there's no way to
make it fire sooner, and no reason to make it fire slower. Poll the app log through
the REST API:
curl -s "http://localhost:8099/api/logs?limit=1"
Expected output (real, captured from the run above — reformatted for readability):
{
"id": "1787264741605724000-TEST-",
"type": "event",
"teamCode": "TEST",
"target": "ha:event:goal",
"success": false,
"error": "refusing to send Home Assistant request: home assistant url is empty",
"timestamp": "2026-08-20T17:25:41.605724-05:00"
}
That "success": false is expected and correct — there's no
Home Assistant configured yet, so Goalfeed refused to send the request rather than
silently drop it (see Security for why). What it
proves is the whole pipeline: config loaded, the ticker fired on schedule, the event
was built, and it's queryable a second later over the REST API — the same path
a real NHL goal takes. If the bundled web UI built (step 1's release archive
includes it), you can watch the same thing happen visually: open
http://localhost:8099, click the Logs tab, and the
entry appears there within the same minute, live over the WebSocket feed, with no
page refresh.
This step doesn't depend on a real game being in progress, on any specific league
being in season, or on Home Assistant being reachable. It only depends on the
one-minute ticker, which always fires. That's why this tutorial uses
test-goals instead of "go watch for a real goal" — the latter
could mean waiting hours.
What's next
You've proven Goalfeed runs, polls, and logs an event end to end. From here:
- Point it at a real Home Assistant instance and get the goal horn and lights firing — Home Assistant automations.
- See every install channel (add-on, source, Docker's current caveats) — Install.
- Look up every config key, including the ones this page skipped (Home Assistant URL/token, other leagues) — Configuration reference.
- Something not behaving as shown above? — Troubleshooting.