FooGolf user guide
The guide for people who own a FooGolf device. It is written to be read by a customer, not by a developer, but the reference sections are deliberately precise enough for a technical user to debug against.
Started 2026-09-15 with the Analytics settings chapter, joined the same day by Extensions and risk. Other chapters will be added as the guide grows; the list below is the intended shape.
- Getting started — to be written
- Finding your way around — the six buttons
- Games and drills — to be written
- Players and handicaps — to be written
- Online play — to be written
- Screen casting — to be written
- Golf simulators (GSPro) — to be written
- Extensions (write your own drills in Lua) — to be written, but read the risks of running an extension first
- Analytics settings — send your shot data to your own server
- Distance calibration (Physical green) — make the predicted roll match what you measure
- Firmware updates — Settings > Settings
- Troubleshooting — to be written
Finding your way around
The device has six buttons and no touch screen, so it is worth learning what each one does once. Only three of them ever change what is on screen from a menu.
| Button | On the main menu | In a settings list or an information page |
|---|---|---|
| OK | opens the thing you are on | accepts, or opens the row you are on |
| BACK | moves one cell to the left | goes back one page |
| HOME | goes to what you are playing | goes to what you are playing |
| ▲ ▼ ▶ | move around the cells | move up and down the rows |
HOME always takes you back to your game
Wherever you are — a menu, a settings list, an About page, a scorecard — HOME takes you straight back to whatever you were playing, ready to carry on from where you left off. You never have to walk back out the way you came in. (A very small number of pages use every other button for something, so there HOME is simply the way out of that page.)
When you press HOME from the main menu you will see the menu slide across to the cell of the game or drill you are playing before it opens. That is deliberate: it shows you where on the menu your game lives, so you can find it again. Press HOME a second time if you would rather not wait.
Inside a game or drill, HOME does the opposite — it takes you to the menu, landing on that game's own cell.
BACK leaves you where you were
Backing out of a settings list returns you to the exact cell you opened it from, not to the game you are playing. So you can change one setting, come back out, and carry straight on along the row you were looking at.
The main menu is a grid
Cells are arranged in rows — FooGolf games, Lua games, Drills, Lua drills, Sim golf, Online play, Attach, Adjustments, Settings (firmware 0.8.628 and later). The two Lua rows hold the extensions you have installed (FooGolf's own Lua versions of every drill and game are on the store, and so is anything you or anyone else writes). The Lua games row ends with the Scoring cell (Stroke play / Match play / Skins); the Lua drills row only appears once a drill extension is installed. Extensions are installed, updated and removed at Settings > Manage extensions. Online play holds FooGolf network (hosting and joining); Attach holds what the device is connected to - Screen casting, your Bluetooth Launch monitor, the Camera and your Analytics endpoint; Adjustments fits the device to your set-up - Physical green (distance calibration) and Environment / club test. Each row begins with its name on the left; move onto the name with BACK. The FooGolf games row's name is the FooGolf ball logo, and pressing OK on it opens About FooGolf.
A cell with a white outline around it is the game or drill you are playing now. A cell with a dashed outline is the one OK would act on. A small yellow pencil on a cell or row means something inside it has been changed from the factory setting; open it and the last row, Non-default settings, lists exactly what — and offers Restore defaults to put the whole list back.
You can make the cells bigger or smaller at Settings > Settings > Visual settings > Cells on view (1, 2 or 3 cells across the screen; 2 is the default).
Settings
The Settings cell on the Settings row holds Game settings, Visual settings, Audio settings, Device (the sensors' Noise threshold - how far a sensor reading must move before the device treats it as a swing, shown as "noise" on the waveform pages), Over-the-air updates and About. Path/lie difficulty (Game settings) sets how wide the raised band under the path/lie arrow is on the shot readout: the higher it is, the harder it is to keep your path and lie inside the band. It lives on Game settings only, not on each drill's list.
The Dev cell (tools built for FooGolf's own bench) is hidden. A supporter may give you your device's factory access code (every device has its own); typing it at Settings > Settings > Factory access shows Dev, and Dev > Disable factory access hides it again.
Nothing plays while the device is talking
The device's own speaker is close enough to the sensors to disturb them at high volume, so the device does not watch for a putt while it is making any sound (speech, a chime, a key tick). A putt struck while it is talking is not captured - wait for it to finish.
Extensions and risk
Lua games and Lua drills grid rows; Settings → Manage extensions. Firmware 0.8.516 and later; called "scripts" until 0.8.548; the two Lua rows since 0.8.624.
Your device can run drills and games written in Lua by other people, and (firmware 0.8.630) drivers for Bluetooth launch monitors. You install one by typing its five-character share code, or pick it from Settings > Manage extensions > Available (the extensions FooGolf has approved for the public list, plus any default you removed). From then on a drill or game is a cell on your Lua games or Lua drills row like any built-in drill; a driver lets you pair its monitor (see Launch monitors below). That is genuinely useful — and it means running code you did not write, so it is worth understanding what a extension can reach before you install one.
An extension is not reviewed for you
The FooGolf extension store checks that an extension compiles and that its manifest is sane. That is all. Approval for the public list (Available) is a light look by FooGolf at the author's description — not a security audit — and a share code installs any extension at all, listed or not. Treat a share code from a stranger the way you would treat any small program from a stranger.
What an extension can do
- Own the screen, the buttons and the sound while it is the active experience, and read every shot you hit while it is running.
- Send your shots to your analytics endpoint — if you configured one. A extension declares what it claims you are aiming at, and the device forwards the shot. See the warning below.
- Write to a player's trend history for its own drill: the one number per completed round that the Trends graph shows.
- Read your players' names, handicaps and impact ratios, and your device-wide settings (stimp, path/lie difficulty, and so on).
- Keep its own settings on the device.
What an extension cannot do
- It cannot invent a measurement. Speeds, angles, path and lie all come from the device's own sensors. An extension chooses which shots it reports and what it says they were aimed at; it cannot make up the numbers.
- It cannot send anything anywhere on its own. The only outbound path is the analytics endpoint you typed in, at most one message per shot. An extension cannot open its own connection, reach the internet, or contact its author.
- It cannot touch your player list — no adding, renaming, deleting or activating players.
- A drill cannot rate you; a game can only if it says so. Only a game that declares itself handicap-modifying (its putts are straight at the hole, as in Course play - firmware 0.8.624) feeds your handicap, and only for the putts your own players hit. A badly-written or careless game that makes that claim can distort your handicap the same way a badly-written extension can distort your analytics — so the advice below applies to games too: install a handicap-modifying game only from an author you trust (FooGolf's own Course play (Lua) is one).
- It cannot brick the device. An extension that crashes ends on an error page and stops; HOME always gets you out, and removing the extension removes it completely.
Launch-monitor drivers
A driver (firmware 0.8.630) is an extension that speaks one launch monitor's Bluetooth protocol. It can only talk to the monitor you paired and report shots and a status line; it has no screen, no sound, no network and no access to your players or settings, and it runs only while a GSPro session is running. Unlike a drill, the shot numbers it reports are its own: a careless or malicious driver can send GSPro shots your monitor never measured. The device checks that each value is in a sane range, nothing more. Install drivers from authors you trust, and watch GSPro for the first few swings.
The realistic risks
Nothing dramatic — the sandbox is tight. What a poorly written or careless extension can do is quietly spoil your own data:
- Unreasonable shots in your analytics. An extension declares the target
itself. One that reports a target you were not actually putting at, or claims
the wrong distance, puts junk rows in your own data set — and you will not
notice until you go looking at it. Every forwarded row carries
"game": "extension:<id>", so you can always tell an extension's rows from a built-in game's, and filter or drop them. - Unreasonable entries in your player records. An extension writes the trend
number for its own drill. A buggy one can fill that drill's history with
nonsense. Controls → Players →
→ Delete... → Delete trend data... clears it. - A drill that simply scores wrongly and tells you you are better (or worse) than you are. There is no way for the device to check an extension's arithmetic.
Updates and default extensions
Firmware 0.8.551 and later.
Every time the device starts (after its audio pack check) it asks the extension store about each extension you have installed and brings your copies up to date: a newer version is downloaded, and an extension its author has taken down is removed. The start-up page shows the progress ("Extensions - Updating 1 of 3") and then the outcome ("2 of 2 extensions updated", "Up to date"). Your settings and trends for an updated extension are kept. Settings > Manage extensions > Check for updates does the same at any time.
FooGolf marks a few extensions as default: every device installs them at that check. You can remove one (firmware 0.8.632); FooGolf then leaves it out until you install it again from Available. Everything else in this chapter applies to them too - they run in the same sandbox with the same limits.
Installed and Available
Firmware 0.8.632 and later. Settings > Manage extensions opens with two lists, each with its count:
- Installed (N) - everything on the device. The light at the start of a row is bright green for an extension you installed and light green for a default. An amber asterisk after the name means the store has a newer version. OK on one offers Update to version N (when there is one) and Remove.
- Available (N) - what you could install. Orange: an extension you have not installed. Red: a default you removed. Purple: a new default that FooGolf flagged after your device started - it installs at the next start or Check for updates, or now from here. OK shows its details; OK again installs it.
Opening Available fetches the store's list again, so it needs WiFi to be current; without WiFi it shows the last list fetched since the device started.
Staying safe
- Install extensions from people you have some reason to trust.
- Watch the first round. Does the distance it shows match what it says, and do the scores make sense?
- If you forward shots to your own server, check what a new extension sends
before you keep its rows — filter on
gameand eyeball thetarget.distance_ftvalues. - Remove an extension you do not trust: Settings → Manage extensions → Installed, OK on it, Remove. Its settings and trend history go with it.
- Your own analytics endpoint is under your control: Settings → Analytics settings → Clear IP address stops everything, extensions included.
Analytics settings
Attach → Analytics endpoint. Firmware 0.8.525 and later; it was Settings → Analytics settings until 0.8.568, Attached software until 0.8.628.
What it does
Your device can send every shot to a server you run, on your own network, so you can keep your shot data and analyse it however you like — a spreadsheet, a database, a dashboard, a machine-learning experiment, whatever you want.
Nothing is sent until you type in an address. FooGolf does not process this data and the FooGolf cloud is not involved: the device talks straight to your server over your own home network.
Each shot is sent once, as a single JSON HTTP POST, and the device carries on immediately — forwarding never delays your putting.
Turning it on
You need a server on your home network that accepts
POST /foogolf/shot and answers with a 2xx status code. There is a
ready-to-run example at the end of this chapter.
- Make sure the device is connected to WiFi (Online → WiFi).
- Go to Attach → Analytics endpoint.
- IP address — type your server's address on your network (for example
192.168.1.50). As soon as you commit the address the device runs a connection test and shows you the result. - Port — the port your server listens on. It starts at
8080, which is the port the example server uses. - Connection test — sends a single test message. You are looking for "Endpoint reached!".
- Status — opens a page showing the endpoint, whether the last send worked, and how many shots have been sent, failed or dropped.
- Clear IP address — forgets the address and turns forwarding off again. The port is kept, so switching back on is one step.
Which shots are sent
Only shots hit at a known target, because analytics about a shot with no target would not mean anything. That is a decision each game and drill makes for itself, and it is deliberately conservative:
| Experience | Sent? | Target reported |
|---|---|---|
| Course play (stroke play / match play / skins) | Yes | the hole, at the current distance to it |
| Close-in putting | Yes | the hole, at the current distance to it |
| Lag putting | Yes | the station, at its distance |
| Metrics only | No | there is no station to aim at |
| Make distance | No | the aim is "as far as possible", not a distance |
| Arc strength consistency | No | nothing is aimed at |
| Face rotation consistency | No | nothing is aimed at |
| Face angle | No | nothing is aimed at |
| Breakout | No | nothing is aimed at |
| Swing path and lie | No | nothing is aimed at |
| Mini golf | No | the ball banks off walls, so the shot is not a straight putt at the target |
| Extensions (Lua drills and games) | If the extension says so | whatever target the extension declares — read Extensions and risk |
| GSPro / GSPro connector / Sim sharing | No | the simulator owns the shot |
In an online round a device only reports its own players' putts. A putt the device is going to ignore because it is another device's turn is never reported.
The message
One POST to http://<your address>:<your port>/foogolf/shot, with
Content-Type: application/json. A real shot looks like this (formatted here
for readability; the device sends it on one line):
{
"schema": "foogolf.shot.v1",
"type": "shot",
"device_id": "3f2b91c4-...",
"device_name": "Ferocious ferret",
"firmware": "0.8.525",
"time": 1757913600,
"uptime_ms": 412345,
"game": "lag",
"game_name": "Lag putting",
"player_id": 3,
"player_name": "Andrew",
"target": { "kind": "station", "distance_ft": 26.00, "hole": 3, "stroke": 1 },
"shot": {
"club_speed_mps": 1.830,
"ball_speed_mps": 3.020,
"impact_ratio": 1.650,
"face_angle_deg": -0.60,
"face_rotation_deg_per_in": 0.420,
"attack_angle_deg": 1.10,
"left_inner_proportion": 0.503,
"right_inner_proportion": 0.497
},
"stimp": 10
}
| Field | Meaning |
|---|---|
schema |
always foogolf.shot.v1. Check it, and ignore messages you do not recognise. |
type |
shot for a real shot, test for the Connection test message. |
device_id |
the device's permanent id. Stable for the life of the device. |
device_name |
the name shown on the device's status page. May be empty on a brand-new device. |
firmware |
firmware version that produced the message. |
time |
UNIX epoch seconds, or 0 if the device's clock has not synced yet. Use your own server clock if this is 0. |
uptime_ms |
milliseconds since the device booted. Always present, so it is the reliable way to order shots within a session. |
game |
stable identifier of the game or drill: golf_course, close, lag. An extension's rows read extension:<its share code> (firmware 0.8.553 and later; the manifest id before that), so they are always distinguishable from a built-in game's. (It was script:<its id> on firmware before 0.8.549.) New ones may appear; do not assume the list is closed. |
game_name |
the human name, for display. |
player_id |
the player's id in the device's own player list. Stable until that player is deleted. |
player_name |
that player's name. |
target.kind |
hole or station. |
target.distance_ft |
straight-line distance from the ball to the target, in feet, at the moment of the shot. |
target.hole |
hole or station number, 1-based. 0 means not applicable. |
target.stroke |
which stroke this was at that target, 1-based. 0 means not applicable. |
shot.club_speed_mps |
measured putter head speed at impact, metres per second. |
shot.ball_speed_mps |
club_speed_mps × impact_ratio. |
shot.impact_ratio |
the ball/club speed ratio the device used for this player. |
shot.face_angle_deg |
face angle at the ball. Negative = closed/left, positive = open/right. |
shot.face_rotation_deg_per_in |
face rotation through the impact gate. Positive = opening. |
shot.attack_angle_deg |
angle of attack. |
shot.left_inner_proportion, shot.right_inner_proportion |
the raw sensor proportions behind the path-and-lie readout. |
stimp |
the green speed the shot was judged on. |
x_factor |
the X factor in force (Settings → Dev → Game settings → X factor, calibrated at Adjustments → Physical green; 1.00 unless you changed it). The device's predicted roll is its model × this. Firmware 0.8.552 and later; absent before. |
The Connection test sends the same envelope with "type": "test" and none of
the game / player / target / shot fields.
Rules and restrictions
These are enforced in the device, both when you save the setting and again immediately before every single send. If a message is not arriving, work through this list first — it is almost always one of these.
Address
- Only a literal IPv4 address and a port. Hostnames are not accepted — there is nowhere to type one, and DNS is deliberately not used.
- Only private (RFC1918) addresses:
10.0.0.0/8—10.x.x.x172.16.0.0/12—172.16.x.xto172.31.x.x192.168.0.0/16—192.168.x.x- Port must be
1–65535. - Everything else is refused with an error on screen. The device never quietly clamps a value or substitutes a different one: if the address is refused, the old setting is still in force. Explicitly refused:
0.0.0.0/8(unspecified)127.0.0.0/8(loopback — that is the device, not your PC)169.254.0.0/16(link-local; means DHCP failed)224.0.0.0/4(multicast)255.255.255.255(broadcast)- any public address
- If a previously-saved address stops being allowed (after a firmware update that tightens the rules, say), it is not used and forwarding stays off.
HTTP
- Plain HTTP only. Never HTTPS. Do not put a TLS-only reverse proxy in front of the endpoint.
- Redirects are never followed. Any
3xxresponse counts as a failed send. Serve the endpoint directly at the path — no301from/to/foogolf/shot, no trailing-slash redirect, no HTTP→HTTPS redirect. This is the single most common cause of "the test says it failed but my server log shows the request arrived". - The response body is ignored entirely. Only the status code is read, and
it must be
2xx. You cannot send anything back to the device. - Connect timeout ~2 s, total request timeout ~2 s. A server that takes
longer than that to answer will look unreachable. Answer
200first and do your work afterwards. - No keepalive: each shot opens and closes its own connection.
Rate and failures
- Exactly one POST per shot. There is no polling, no heartbeat, no reconnect loop. If your server sees repeated traffic, it is not this feature.
- A send that fails is retried at most twice, after 1 s and then 3 s, and is then dropped. There is no long-term store-and-forward: a shot missed while your server was down is gone.
- The queue holds 4 shots. If it fills up (server slow or down while you keep putting), the oldest queued shot is dropped.
- Failures are silent on the device except for the status: Settings →
Analytics endpoint → Status shows
Last send failed, with the HTTP code when there was one, and the sent / failed / dropped counts. Settings → Controls → Device status carries the same line. - Sending runs on its own background task. It can never delay shot detection, the screen, or the sound.
Troubleshooting
| What you see | Almost always means |
|---|---|
| The address is refused when you commit it | It is outside 10.x / 172.16-31.x / 192.168.x. The error page names the rule. |
Cannot connect to <address>:<port> |
Nothing is listening there. Wrong IP, wrong port, server not started, server bound to 127.0.0.1 instead of 0.0.0.0, or a firewall on the server machine. |
| Connection test fails but your server log shows the request | Your server answered a 3xx or a non-2xx code. Redirects are never followed. Answer 200 on POST /foogolf/shot. |
... answered HTTP 404 |
The path is wrong. It must be exactly /foogolf/shot. |
... answered HTTP 405 |
Your route only accepts GET. Accept POST. |
... answered HTTP 500 |
Your handler threw. Answer 200 before you parse, then parse. |
| Test passes, but no shots arrive | You are in an experience that does not report (see the table above). Try Lag putting or Course play. |
| Some shots arrive, some do not | Your server is slower than the ~2 s timeout, or it was briefly unreachable and those shots were dropped after their two retries. Check the dropped count on the Status page. |
| Nothing arrives after the device's IP changed | Nothing to do with the device: give your server a fixed address (a DHCP reservation on your router). If your server's IP moves, the setting stops matching. |
| Everything worked yesterday and not today | Same cause as above nine times out of ten. Check the address on the Status page against your server's current address. |
Status says Off |
No address is set (or a saved one is no longer allowed). Re-enter it. |
An example server
Dependency-free — Python 3 only. It answers 200 immediately and appends each
shot to a CSV, which is enough to start analysing in a spreadsheet.
#!/usr/bin/env python3
"""Minimal FooGolf analytics endpoint. Run on your LAN: python3 foogolf_sink.py"""
import csv, json, os
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
PORT = 8080
CSV_PATH = "foogolf_shots.csv"
FIELDS = ["time", "uptime_ms", "device_name", "game", "player_name",
"target_kind", "distance_ft", "hole", "stroke",
"club_speed_mps", "ball_speed_mps", "face_angle_deg",
"face_rotation_deg_per_in", "attack_angle_deg", "stimp"]
class Handler(BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1" # keeps the 2 s budget comfortable
def do_POST(self):
if self.path != "/foogolf/shot":
self.send_error(404)
return
body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
# Answer FIRST: the device gives up after about two seconds.
self.send_response(200)
self.send_header("Content-Length", "0")
self.end_headers()
try:
msg = json.loads(body)
except ValueError:
return
if msg.get("schema") != "foogolf.shot.v1":
return
if msg.get("type") != "shot":
print("test message from", msg.get("device_name"))
return
t, s = msg.get("target", {}), msg.get("shot", {})
row = {
"time": msg.get("time"), "uptime_ms": msg.get("uptime_ms"),
"device_name": msg.get("device_name"), "game": msg.get("game"),
"player_name": msg.get("player_name"),
"target_kind": t.get("kind"), "distance_ft": t.get("distance_ft"),
"hole": t.get("hole"), "stroke": t.get("stroke"),
"club_speed_mps": s.get("club_speed_mps"),
"ball_speed_mps": s.get("ball_speed_mps"),
"face_angle_deg": s.get("face_angle_deg"),
"face_rotation_deg_per_in": s.get("face_rotation_deg_per_in"),
"attack_angle_deg": s.get("attack_angle_deg"),
"stimp": msg.get("stimp"),
}
new = not os.path.exists(CSV_PATH)
with open(CSV_PATH, "a", newline="") as f:
w = csv.DictWriter(f, FIELDS)
if new:
w.writeheader()
w.writerow(row)
print(row)
def log_message(self, *a):
pass # keep stdout to the shots
if __name__ == "__main__":
# 0.0.0.0, not 127.0.0.1 - the device is a different machine.
ThreadingHTTPServer(("0.0.0.0", PORT), Handler).serve_forever()
Run it, note the machine's LAN address (ipconfig on Windows, ip addr on
Linux, ifconfig on a Mac), and enter that address and 8080 on the device.
Notes and limits
-
Extensions (Lua drills and games) can forward shots since firmware 0.8.530, but only if the extension declares a target. The extension decides which shots and what they were aimed at, so read Extensions and risk before you keep a new extension's rows.
-
Shots with no target are never forwarded, by design. If you want raw per-shot measurements with no target at all, that is a different feature and it does not exist yet.
- There is no store-and-forward. If your server is down, those shots are lost. Run the server, then putt.
Distance calibration
Adjustments → Physical green (Settings → Device settings → Distance calibration until 0.8.628). Firmware 0.8.552 and later; the page below is firmware 0.8.564 and later.
What it does
Every game and drill that rolls a ball predicts how far your putt travels from three things: the club head speed the device measured, your impact ratio (ball speed divided by club head speed, a property of you and your putter) and the stimp you set. Real surfaces rarely match a model exactly, and you may not have a stimp meter at all. Distance calibration lets you measure one putt and have the device correct itself.
There are two corrections, and they suit different situations:
| X factor | Impact ratio | |
|---|---|---|
| What it is | one multiplier on every predicted distance (1.00 = the model as it is) |
the ball/club speed ratio of one player's putter |
| Who it affects | every player on the device | that player only |
| Use it when | the surface is what differs: everyone's putts are off by the same proportion | one player's putter is what differs |
| Range | 0.50 to 2.00 | 1.40 to 1.80 |
A sensible order: set the X factor first using a player whose ratio you trust, then adjust the other players' ratios one at a time.
How to use it
- Hit a putt in any game or drill. Measure how far the ball actually rolled, in feet.
- Go to Adjustments → Physical green → Calibrate from last shot. The page is headed Calibrate from last shot and shows, for that last putt: the Player and the Impact ratio and Stimp the prediction used, the measured Club speed, the X factor in force and the Predicted distance. These are there to be read — there is nothing to press on them.
- Underneath is a menu of three choices. Adjust X factor and Adjust impact ratio are greyed out and the cursor skips them until you have entered a measurement: you can see they are coming, but they have nothing to work with yet.
- Enter measured distance — type the distance you measured on the number pad (digits, one decimal point, Cancel, OK). Feet, 0.1 to 300. You come straight back to the page, and the other two choices light up.
- Choose a correction:
- Adjust X factor shows the factor that would have made the
prediction equal your measurement, next to the current one. OK
applies it, BACK keeps the old value. Either way you land back on
this page.
- Adjust impact ratio for
<name>shows the ratio that player would need, keeping the current X factor. OK changes only that player, BACK keeps their old ratio. - Hit another putt to check. A new putt replaces the last shot and clears the measured distance — so the two Adjust choices grey out again, even while you are looking at the page.
You can also type the X factor directly, at Settings → Game settings → X factor. The device never rounds or clamps a value you enter: anything outside the range is refused with a message and nothing changes. If a measurement would need a value outside the range, the page tells you what it would have needed and suggests the other correction — check the measurement and the stimp first.
About is a row of its own in Adjustments → Physical green, next to the one that opens this page.
Things to know
- The X factor is a device setting: it persists across restarts, counts as a customised setting (the yellow edit pencil on the Game settings row, where Restore defaults puts it back to 1.00), and while you host an online round your guests adopt it so everyone sees the same roll.
- The impact ratio is stored on the player record, exactly as if you had edited it under Players.
- Analytics messages carry the X factor as
x_factor(see the Analytics chapter), so a server that recomputes distances has everything it needs. - Calibrate on a flat run of typical length. A single putt is a single sample: if a second measurement disagrees, split the difference rather than chasing each one.
Online play
Several FooGolf devices can play together. One device is the host; the others join it as guests with the host's code (Online play > FooGolf network > Host details shows the code, and the host's screen flashes "Give your host code XXXX to your guests" when it starts hosting; guests use Join a host). How it behaves:
- Free ranging or linked. A device is on its own until it starts hosting or joins a host. A guest has exactly one host; a host can have any number of guests.
- Tethered guests follow the host. Guests join tethered: whatever the host starts (a drill, a game, a sim session) they start too, with the host's settings. A guest that starts something itself, or changes one of those settings by hand, becomes untethered and is back under its own control. It stays a guest, and Resume tethering (or the host's Re-tether all guests) brings it back.
- Games. When the host starts a game (Course play, Mini golf, a game extension), every tethered guest's active players are in it, up to four players in all. A host cannot start a game with more, and nobody can activate a fifth player into one. Once a shot has been hit the game is under way: nobody joins, re-tethers or changes their active players until it ends. A guest that untethers mid-game leaves it: stroke play's board shrinks, match play and skins are re-scored (one player left plays Par).
- If the host goes down (turned off, no WiFi) its guests stay linked but untethered and go back to what they were doing before; when it comes back up it re-tethers them all. If the host chooses Stop hosting, its guests are on their own again. A guest that restarts comes back linked; if the host's game was under way meanwhile it comes back untethered and does not rejoin.
- Sim sessions. Only the host (or a free-ranging device) can start GSPro; tethered guests play into the host's session from their own device.
GSPro and the FooGolf GSPro connector
What it does
The GSPro cell on the Sim golf row sends your putts into GSPro. Since 2026-09-22 there is one GSPro experience, and the recommended way to connect it is the FooGolf GSPro connector, a small open-source program that runs on the gaming PC. With it there is nothing to type on the device but a code: no IP addresses, no Windows Firewall rules, no port forwarding, and no USB cable between the device and the PC. Any device in an online-play group can aim, and every shot from the group goes to the sim in order.
The connector holds the connection to GSPro itself. It looks for a port 8888 connector first (the webcam putting listener some launch-monitor connectors provide); if one is running it uses it and never touches GSPro Connect. Otherwise it connects to GSPro Connect on port 921 and keeps that one connection open for the whole session, which is why a device restart no longer needs "Reset GSPro Connect".
Setting it up
- On the PC, download
foogolf-gspro-connector.exefromgithub.com/abraae/foogolf-gspro-connector(Releases) and run it. Windows shows "Windows protected your PC" because the program is not code-signed yet: click More info, then Run anyway. The source is public. - The connector window shows a six-character code under Connected FooGolf devices.
- Start GSPro (Open API licence) or a port 8888 connector's webcam putting. The connector's GSPro row turns green and names the port it holds.
- On the device: Sim golf > GSPro > Play. The first time it asks for the
code (type it, OK); the device remembers it, and Connector code on the
same list changes it later. Play starts a sim session: the cell reads
GSPro: Connectedwith a green light, the connector window names your device. Keep GSPro as the front window on the PC while you play; the aim keys go to whatever window is in focus.
A sim session holds the connector while it is connected, one device at a
time. Starting anything else on the device ends the session and frees the
connector. If the connector or the PC goes down mid-session the device stays
in the session, GSPro: Disconnected, and reconnects by itself the moment the
connector is back - unless another device started a sim session on it first,
in which case yours ends and the device goes back to the Metrics drill (a host
takes its tethered guests with it). A guest of another device cannot start a
sim session; tethered guests share their host's.
If you press Play while the connector is not running, the device says so and
offers [OK] to continue (firmware 0.8.628 and later): OK starts the sim
session anyway, GSPro: Disconnected, and it connects by itself once you
start the connector. The GSPro page can only be left with HOME - the
legend at the top says so.
Lag practice
The top row of the GSPro page's blue list is Lag practice (firmware 0.8.628
and later). GSPro shows you a 46-foot putt; you want a feel for 46 feet before
you hit it. Choose Lag practice and the device's screen shows nothing but the
distance of your last putt in giant figures (-- until the first one); each
putt blanks the screen, then its distance appears with rings rippling out of
the digits. These putts do not go to GSPro - they only drive this display,
and they tell you nothing about face angle, only distance. Every device in an
online group practises on its own: each sees only its own putts. The aim keys
do nothing on this page; [OK] returns to the GSPro page.
To start the connector with Windows, run it once from a terminal with
--startup on; --startup off removes it. Do not run it "as administrator".
The connector window
The window has two panels. The left one lists the parts of the integration, one row each, green when connected and red when not; the right one is the log with the newest line at the bottom. Up and Down pick a row; OK (Enter) opens a small menu for it that starts with Cancel and then lists only what applies right now.
| Row | Shows | OK menu |
|---|---|---|
| Connected FooGolf devices | The device whose sim session holds the connector, by name, "(host)" while it is hosting online play, with its guests listed underneath. "none" plus the code while no session holds it - including when the holding device was turned off or stopped answering. | Regenerate code mints a new code; a device holding the connector keeps its hold and picks the new code up by itself, anyone else needs the new code. |
| FooGolf cloud | connected, connecting or reconnecting. Stuck on reconnecting means the PC has no internet. | nothing, it reconnects by itself |
| GSPro | connected on port 921 (GSPro Connect), connected on port 8888 (a port 8888 connector), or not connected with the reason. | Connect looks for GSPro again; Disconnect drops the link and stops looking. GSPro Connect will not take another client after that until you reset it in GSPro. |
The log warns when both a port 8888 connector and GSPro Connect are reachable at the same time. Close one of them: GSPro Connect only reads the first program that connected. F10 quits.
Things to know
- A port 8888 connector takes putts only. While the connector holds port 8888 the club rows and Repeat shot leave the selector (Repeat aim, Reset aim and Mulligan stay) and launch-monitor swings are not forwarded. Start GSPro Connect instead of the port 8888 connector to get them back.
- One connector, one sim session, one GSPro. A second device that presses
Play while yours holds the connector is told "Connector in use by
" and stays where it was. Two players on two devices should be a host and a guest in online play, not two sessions. - Status (the first row of the GSPro list) shows the session, the PC, the connector, who holds it and whether GSPro is connected on the PC. "Connector online - GSPro not connected on the PC" means the connector is running but GSPro (or the port 8888 connector) is not.
- There is no other way to reach GSPro from the device: since 2026-09-23 the direct connection by IP address is gone.
- The code is the only secret. Anyone with it can start a sim session on your GSPro. Treat it like a Wi-Fi password.
- Aim taps are batched. Hammer Left twenty times and Right five times and the connector presses Left fifteen times; the batch is sent after a third of a second's pause, or every two seconds while you keep tapping.
Browser sim
Sim golf > Browser sim. Firmware 0.8.631 and later.
What it does
A golf game that runs in a web browser - on a phone, a tablet, a TV or a PC - fed by your FooGolf. The device serves the game itself over your WiFi, so there is nothing to install on the computer and no internet is needed once the game is on the device. Your putts, the club selector's shots, your guests' shots and an attached launch monitor's full swings all go to the game.
Games are extensions (kind "Browser sim game"): anyone can write one and publish it, and every game's source is open, like every other extension.
Setting it up
- Install a game: Settings > Manage extensions > Available (or Install by code). The first game also brings down the web runtime (three.js, about 170 KB) - once.
- Sim golf > Browser sim, then OK on the game. The sim page shows "Open http://:9203 in a browser".
- Open that address in a browser on the same WiFi. The page connects to the device ("Page open (1)" on the sim page) and you can play.
Things to know
- A session is connected while a page is open. With no page open the device keeps the session and says "No page open - shot not sent" when you hit one. Close the tab and open it again at any time; it reconnects by itself. At most two pages at once.
- The club selector, Repeat shot, the aim keys, Reset aim and Mulligan work as they do for GSPro - the game decides what each one means.
- Putts carry your calibration. Each putt goes to the game as ball data (ball speed = club speed x your impact ratio) together with the device's own predicted roll at the green speed the game asks for, so a game that uses it rolls the ball exactly as far as the device's own drills would.
- Guests follow a host's Browser sim like GSPro: their putts, club shots and aim reach the host's game. A guest cannot start one.
- Guest or hotel WiFi often stops devices on it talking to each other; if the page never connects, try your home network.
- Writing a game: the FooGolf emulator (dev.foogolf.nz, also dev.foogolf.com) runs the same firmware in Chrome. Sim golf > Browser sim > Game from a folder (emulator), then Load game folder... under the emulator's screen plays a game straight from your computer; Reload picks up your edits and the Monitor shot panel sends launch-monitor numbers. The developer guide is golfclaude/docs/browser-sim-design.md.
Launch monitors (Bluetooth)
Attach > Launch monitor. Firmware 0.8.630 and later (a Garmin R10 cell before).
What it does
Pair a Bluetooth launch monitor once and its full swings go into your sim - GSPro, or the Browser sim - in the same stream as your putts, so the sim sees one launch monitor. Each kind of monitor needs a driver - an extension anyone can write and publish. The Garmin Approach R10's driver is on the public list.
Setting it up
- Install the driver: Settings > Manage extensions > Available, pick the driver (its kind reads "launch monitor"), OK to install. It does not appear on the Lua rows.
- Put the monitor in pairing mode (the R10: switch it off, then hold its button until the LED is solid blue - flashing blue means it is looking for its phone and will refuse).
- Attach > Launch monitor > Pair a launch monitor: the page lists the monitors in range that an installed driver recognises, with the driver's name. OK on yours; "Paired with ..." confirms it.
- Start a sim session - Sim golf > GSPro > Play, or a game under Sim golf > Browser sim. The device connects to the monitor as the session starts - Searching, Connecting, Waking, Ready - and every swing it measures goes to the sim.
Things to know
- The monitor is connected only while a sim session is running (GSPro or the Browser sim). Leave the sim and the device lets it go; the status reads "Idle (connects in a sim session)". Bluetooth costs memory the rest of the device needs, so it is off the rest of the time. Drills and games never take a launch monitor's shots.
- One monitor at a time. Pairing another replaces the first.
- A driver error ("Driver error: ...") stops the connection until you start the next sim session; update or remove the driver if it keeps happening.
- Unpair (same menu) forgets the monitor so its own app or a PC can have it.
- A monitor paired before firmware 0.8.630 has to be paired again once its driver is installed.
Firmware updates
Your device updates itself. When it starts up, and whenever it joins your Wi-Fi, it asks FooGolf whether there is a newer version. If there is, it installs it, restarts once, and carries on — you are not asked, and there is nothing to do.
You can change that at Settings > Settings > Over-the-air updates:
| Always update | The default. A new version installs by itself at start-up or when the device joins Wi-Fi. The screen shows INSTALLING UPDATE with a progress bar, then the device restarts. It takes a couple of minutes. |
| Ask player | The device shows you the new version and waits. Press OK to install it, BACK to leave it for now. It will offer again next time it starts. |
| Disabled | New versions are never installed. |
Choose Ask player if you do not want a restart in the middle of a session — for example if the device is set up for a group and you would rather update it afterwards.
The device never checks on a timer. It checks when it starts up, when it joins Wi-Fi, and nowhere else, so an update can never interrupt play.
If a release will not install
Occasionally a release fails — a weak Wi-Fi signal during the download, or a version that does not start up properly and is automatically rolled back to the one you had. The device tries three times and then leaves that version alone. It stays completely usable, keeps checking, and installs the next release normally. You will never find it restarting over and over.
Settings > Device status shows what happened:
Auto update: Always update
v0.8.556 blocked after 3 tries
If you want it to try that version again, open Settings > Settings > Over-the-air updates and pick a mode (re-picking the one you are already on is enough) — that starts the three tries over.
Other things on this page
- Over-the-air updates counts as a customised setting when it is not on Always update: the Settings cell gets the yellow edit pencil, and Non-default settings > Restore defaults puts it back.
- Extensions update separately, at start-up, and are covered in Updates and default extensions.