Last updated: September 5, 2026
A flattering number costs you a club on a par 3. So this page lists the thirteen places where the free tools on this site show you a number and decline to grade it, guess at it, or invent it, with the exact sentence you will see and the automated test that keeps it that way.
The useful question to ask any app that reads your golf data is not "is it accurate". It is "what does it do when it does not know". Accuracy is a claim. A refusal is something you can go and find on the page, today, with your own export. Every row below names its receipt, and the last section says what the honest blank costs us.
Each row has four parts: the easy move most tools make, what happens on ours instead, the sentence you actually see, and how to check it. The tests are real files in the codebase and run with the project's test suite, so a refusal that stops holding shows up as a red test. The check in row 13 goes further and runs inside every production build.
The easy move. Your Trackman or Garmin export carries a column that says Estimated beside some spin numbers. Most golfers never look at it, and a spin verdict looks decisive, so grade it anyway.
What happens instead. The decoder reads that column. If any shot in a club's group is marked Estimated, the whole average is treated as an estimate: the number is printed and no verdict is put on it, with no device picker needed.
The sentence you see. "…and this page will not put a verdict on it. Your export marks this spin number as estimated by the device rather than measured. Comparing an estimate to a benchmark tells you about the estimate, not about your swing."
How you can check. Locked by automated tests named decodeRead.test.ts ("the export's own Spin Rate Type: Estimated gates spin with no device picked") and launchMonitorParse.devices.test.ts ("any single Estimated shot makes the group average an estimate").
The easy move. You picked your launch monitor and where you hit, and one of the numbers on screen is one that unit models on that setup: spin on a radar unit indoors, carry on a camera unit into a screen. Grade it against the well struck window anyway, because a window is a window.
What happens instead. The decoder asks the same device map the accuracy tool is built on. A metric that map files as modeled or not available is shown with its value and no verdict, because a benchmark comparison against an estimate is a comparison against the maker's algorithm, not against you.
The sentence you see. "On the setup you picked, your device does not measure this." followed by the same closing line as row 1.
How you can check. Locked by automated tests named decodeRead.test.ts ("a device that models spin gets its value shown and no verdict" and "a metric the device does not produce at all is not graded either") and deviceTrust.test.ts ("metricIsVerdictGrade opens up when no device is picked and closes on an estimate"). Open the accuracy tool link above and the Garmin R10 indoor row is already selected: spin reads MODELED. The same link works for any unit on the map, for instance the Rapsodo MLM2PRO, whose spin on a plain ball is filed as not available rather than estimated.
The easy move. You hit range balls into a net and uploaded the file. The averages are right there, so grade them, and let the golfer work out later that the ball was the variable.
What happens instead. Tell the decoder the ball was a range ball or a limited flight ball and every verdict on the page is withdrawn. The averages stay. Nothing is graded, because a range ball moves spin by more than any benchmark window is wide, so every verdict would be a verdict about the ball.
The sentence you see. "Range balls spin hundreds to well over a thousand rpm differently from the ball you play, which is wider than these windows are. The averages are below, but this page will not grade them."
How you can check. Locked by automated tests named decodeRead.test.ts ("range balls suspend every verdict and say why" and "limited flight balls do the same with their own reason").
The easy move. The benchmark table has one wedge row and its launch window belongs to the pitching wedge. Read a 54 degree wedge against it anyway, and on real data the sand wedge reads launch HIGH, which looks like a finding.
What happens instead. A gap, sand or lob wedge, or a wedge of unknown loft, shows its launch angle with no verdict. Only a club the export names as a pitching wedge, or one you pick as a pitching wedge, gets launch graded. Smash, spin and descent are still read on every wedge.
The sentence you see. "…and this page will not put a verdict on it. The benchmark table states a launch window for the pitching wedge only. Grading a higher lofted wedge against it would be a verdict about the loft, not about the strike."
How you can check. Locked by automated tests named decodeRead.test.ts ("a 54 Wedge label shows launch without a verdict, with the table reason, and never takes the top slot" and "lofts above 47° and unnamed wedges are withheld"). The sample session on the decoder is three real clubs of my own, and its 54 wedge shows exactly this.
The easy move. A modern 7 iron at 28 degrees carries a classic 6 iron's loft, so it spins and launches lower by design. Grade it against the 7 iron row anyway and call the spin LOW, which is wrong for the club and flattering for the app, since a LOW verdict is a finding.
What happens instead. Tell the decoder your set is strong lofted, or the exact degrees, and the iron is read against the next row up, the 5 or 6 iron window, and the read says so. Leave the loft unknown and a number that would be healthy on the stronger row becomes a question, not a verdict. A number that is out of band on both rows is called decisively whatever the loft. The adjacent row is the table's own row: the decoder never interpolates a band in between. The coach reads strong lofts the same way.
The sentence you see. "Your 7 iron is 28°, which is about a classic 5 or 6 iron loft, so this reads against the 5 or 6 iron band." Or, with the loft unknown: "What loft is your 7 iron? Answer that and the next read is decisive."
How you can check. Locked by automated tests named decodeRead.test.ts ("strong: the same shot reads healthy against the 5 or 6 iron row and SAYS the adjustment", "a low spin that fits the stronger row asks for the loft instead of calling it LOW", and "a club with no stronger row in the table never shifts, whatever the loft").
The easy move. The file has no club column. The carry averages 165, so it was probably a 6 iron. Guess, and grade the guess.
What happens instead. The decoder shows zero verdicts and asks. Carry alone cannot name a club, since 165 is a 6 iron for one golfer and an 8 iron for another, so until you pick the club from the list nothing is graded.
The sentence you see. "This export has no club labels. Which club was this set?"
How you can check. Locked by an automated test named decodeRead.test.ts ("pasted (no fileName) single group labels Session, needsClubPick, zero verdicts"). Paste a few rows out of a spreadsheet with no club column and watch the picker appear before any verdict.
The easy move. GSPro's community export shares column names with another device's export. Match the ones that fit, fill the rest, and produce a read that is wrong in ways the golfer cannot see.
What happens instead. The parser recognizes the GSPro header shape and declines to read it at all until a real export has been verified against the device. You get a plain failure message and a list of the usual reasons, not a half right read.
The sentence you see. "That did not read as launch monitor data" and, in the list beneath it, "GSPro range exports are not supported yet."
How you can check. Locked by an automated test named launchMonitorParse.devices.test.ts ("GSPro community CamelCase unspaced names return ok false").
The easy move. Flag every pair closer than 10 yards. It is the number most gapping calculators use, and it needs no data beyond a yardage card.
What happens instead. The gapping tool compares each pair's gap to the scatter of that pair. When you supplied three or more shots for both clubs the scatter is yours and the flag says MEASURED. When one club did, MIXED. When neither did, ASSUMED, and the assumption, 5 percent of carry, is cited on the page to a public source along with the opposing figure from a test professional, so you can see how much the assumption swings. An assumed flag is framed as a question, not a verdict.
The sentence you see. A measured flag names the pair and the gap, then ends "…threshold measured from your own shots: on any single swing you cannot tell these two apart." The assumed note ends "So an assumed flag is a question, not a verdict. Manual entry buys you a question. A launch monitor CSV buys you an answer."
How you can check. Locked by automated tests named gapping.test.ts ("ASSUMED: two single entries carry an assumed threshold and say so", "MEASURED: real shots can CLEAR a pair the assumption would have flagged", "never invents a threshold", and "every scatter source is a public URL a reader can check, not an internal document") and carryStats.test.ts ("names MEASURED only when BOTH sides brought their own scatter").
The easy move. Your file has a total distance column and it is the bigger number. Use it. Golfers like bigger numbers.
What happens instead. The gapping tool ignores the total column and says so. Total is carry plus a bounce and a roll the monitor calculated rather than watched, and only the measured part tells you which club covers a number.
The sentence you see. "Your file has a total distance column and this page ignored it. Total is carry plus a bounce and a roll that your launch monitor did not watch, it calculated. Carry is the part that was measured, and it is the only part that tells you which club covers a number."
How you can check. Locked by an automated test named gapping.test.ts ("says why a total distance column was ignored").
The easy move. A wedge matrix built from typed averages has no scatter to work with. Assume one quietly, flag the close cells, and let the flags look measured.
What happens instead. The wedge chart gives a cell a standard deviation only once you have entered three or more shots for it, the same three shot floor the gapping tool uses. Below that the cell keeps its average and reports no scatter, and any flag that leans on the assumption says so out loud.
The sentence you see. "Neither cell has enough shots to measure your scatter, so this page assumes a typical 2.1 yards a cell, which puts the pair about…" and, after the threshold, "…apart before they count as different shots. Enter a few carries in either cell for a measured read."
How you can check. Locked by automated tests named wedgeMatrix.test.ts ("never invents an SD: every flag threshold traces to measured shots or the cited assumption") and carryStats.test.ts ("is three, and both pages agree on it").
The easy move. Most makers publish no accuracy figure at all. Borrow one from a review site's test, print it as the device's accuracy, and the page looks complete.
What happens instead. On Which of your launch monitor numbers are real? a band appears only when the maker published it. Where the maker publishes none the page says so. Where a maker's own pages contradict each other, the contradiction is printed rather than resolved. And every device section carries the month its claims were last checked, because hardware ships new firmware and new tiers and you are owed the age of the claim.
The sentence you see. "The maker publishes no accuracy figure for this." and "Claims last checked against the maker's own pages in August 2026." and, on three devices, "Sources disagree, so we are not picking a side:".
How you can check. Locked by automated tests named deviceTrust.test.ts ("every bandSource resolves to a VENDOR source, a third party test may never fill a band" and "every device has a label, family, headline, a verified stamp, and at least one variant") and trustStatic.test.ts ("carries the last checked stamp for every device" and "prints the unresolved vendor source conflict instead of resolving it").
The easy move. You uploaded a driver, a 9 iron and a 54 wedge. Print "7 clubs missing", or worse, call the 100 yard hole between the driver and the 9 iron a gapping problem.
What happens instead. The decoder's ladder names each slot that sits between two clubs you did hit, in gray, and claims nothing across it. A slot that could be a 4 iron or a 4 hybrid is written as both. A count is never printed, because a count reads as a verdict on your bag when it is only a fact about one afternoon's upload.
The sentence you see. On the decoder's sample session, a driver, a 9 iron and a 54 wedge: "3W · 5W · 4i / 4H · 5i · 6i · 7i · 8i not in this session" and "PW · GW not in this session".
How you can check. Locked by automated tests named sessionRead.test.ts ("never prints a count of missing clubs" and "names the skipped slots between two present clubs, including the ambiguous 4i / 4H slot").
The easy move. End every read with a drill. A prescription makes a single session tool feel like a coach, and nobody checks whether the drill fits a pattern the tool has never seen.
What happens instead. The decoder, the gapping tool and the wedge chart read one session and say what a number is consistent with. None of them tells you what to do to your swing, because one afternoon of numbers cannot separate your usual miss from a one off, or a new number from a normal one. What to do about it is the coach's job, and the coach's instruction layer is kept out of the free tools by a build step that fails if it ever enters one of their bundles.
The sentence you see. "What to do about it is the coach’s job. Three free messages, and Chip reads this same file." and "This read is one session against fixed benchmarks. It does not know your typical shot, your misses, or what you changed last week."
How you can check. Locked by an automated test named gapping.test.ts ("never prescribes: no generated string tells the golfer what to do to their swing") and by the build step above.
The rows above are gates in code. The coach, Chip, is a language model working from instructions and from your own session history, so its rules are a different kind of thing. They are instructions, not automated gates, and they are not counted among the thirteen refusals. Three of them are worth knowing before your first session:
Every row on this page makes the free tools look thinner in a screenshot. A competing app can print a confident word in every box, and next to that our decoder has a number with no verdict under it and a question about your loft. I chose that, and it costs us on the day a golfer compares two tabs. I think the trade is right because sooner or later a golfer catches an app being wrong about something they know for certain, the shank they felt in their hands or the driver that has never once carried 260, and after that moment nothing else the app says gets believed, including the parts that were right. A question about your loft cannot produce that moment. A verdict can.
I am a golfer chasing single digits. I bought a simulator for the garage, and it gave me more launch monitor data than I could turn into a better swing. A lesson gave me one great read, and then I was on my own again, trying to remember on Saturday what a coach had seen on Tuesday, going back to the numbers, watching more videos, and spiraling. What I wanted was a coach that remembered where my game had been, could read where it is right now from my own numbers, and would tell me what to work on next.
That is why Fore-ward Thinking coaches from measured data and not from swing video. The numbers are what I have after every session, and memory of them across sessions is the thing a lesson could not give me. The free tools on this site are the reading half of that, given away. The coach is the remembering half. If a row on this page is ever wrong, tell me through the feedback button in the app, and I will fix the code, not the wording.
Andrew Feaman, founder
Settled. These exist today and are what the site is judged on:
Deliberately not. Not on the roadmap, and not because we ran out of time:
See what memory does with your numbers
Why does the decoder show a number but no verdict on it?
Because the number was not measured, or the benchmark table states no window for it. Spin your device marks estimated, a metric your setup models, the launch angle of a gap or sand wedge, and every club hit with range balls all show their averages with no verdict. Comparing an estimate to a benchmark tells you about the estimate, not about your swing.
Does refusing to grade mean these tools show me less than other apps?
On day one, yes, in a few specific places. You will see a number with no verdict where another app prints a confident word, and a question about your loft where another app prints LOW. In exchange, every verdict you do see rests on a window the benchmark table actually states, and once you have told the decoder your device and ball, on a number that was measured.
Why will the gapping tool not call a 12 yard gap a gap?
Because a gap is only real when it is wider than the shot to shot scatter of the two clubs. Two clubs that each scatter 8 yards need about 11 yards between them before a single swing can tell them apart. The tool uses your own scatter when you supply three or more shots per club and a cited 5 percent assumption when you do not, and every flag says which of the two it used.
How can I check any of this myself?
Every sentence quoted on this page is visible today on the free tool it belongs to, so paste your own export into the decoder or the gapping tool and read what comes back. Each refusal is also locked by an automated test in the codebase, named beside it, that goes red if the behavior changes. Every device section on the accuracy tool carries the month its claims were last checked against the maker's own pages.
What does Fore-ward Thinking deliberately not do?
It does not analyze swing video, it is not a shot tracker or an on course GPS, it is not an app store download, and it never grades a number your launch monitor did not measure. It coaches from launch monitor data, range sessions and on course results, and it remembers them across sessions. If you want frame by frame video, pair it with a video tool.
Keep going:
Paste a CSV export and get your biggest opportunity named against the well struck window it missed.
How to build a dispersion picture from your carries, why the spread decides which gaps are real, and why the tightest pattern of the day can still be the worst one.
Check the actual lofts before you switch: why distance iron misses run long, what bending weak really buys, and the fix menu in order of cost.
The across sessions layer: the order improvement actually shows up in, the six line log that makes a trend readable a month later, why one session is noise, which platforms forget your shots, and the honest limit of pasting a CSV into an AI.