Skip to content
Access: Anonymous access. Content follows.
Reading progress is unavailable until the article can be measured.
how-the-sausage-is-made

Backtest a Sports Betting Model in Your Browser (Cornerstone)

Read the price, role, and market first How to backtest a sports betting model in the browser with TensorFlow.js. Train, evaluate, and ship a model on your own device with no upload.

8 sections

Shark Snip Editorial

House byline of the Shark Snip analytics desk — numbers sourced from the data pipeline, not vibes.

A browser backtest can be serious work. It can also be a very fast way to put a polished interface around leakage. The runtime is not the standard. The replay contract is. Whether the model runs in TensorFlow.js, Python, or a spreadsheet, the test is honest only when every prediction uses information that existed before the event and is graded against a defined market reference afterward.

The browser adds useful constraints. Data can remain on the device, the full pipeline can be packaged with the page, and a reader can rerun the same workflow without provisioning a server. None of those benefits is automatic. “Client side” is an architecture claim that must be verified, not a privacy slogan printed above a loading bar.

Start with the backtest contract

Write the contract before loading a tensor. Name the prediction target, event boundary, feature-availability rule, training window, validation window, final test window, market reference, grading policy, and random-seed policy. If one of those fields is undefined, the model is not ready to train.

The target must match the betting question. A margin model, a win-probability model, and a player-stat model produce different outputs and need different baselines. Do not train one target and grade another because the second metric looks friendlier.

The event boundary is the line the data may not cross. For a pregame model, every feature needs an “available at” timestamp earlier than the decision. Final scores, closing prices, postgame summaries, and season aggregates that include the target event all belong on the forbidden side.

Errors should name the cure

A useful browser workflow returns boundary failures as values. “Feature available after event start — remove the column or rebuild it from lagged rows” is actionable. “Training failed” is not. The same applies to missing closes, duplicate events, mixed market types, and impossible probability values.

Do not silently drop bad rows. Report how many were excluded and why. A backtest that changes its sample while hiding the exclusions cannot be reproduced, even if the model code is deterministic.

Load data with provenance attached

A file name is not provenance. The dataset should identify its source, extraction time, transformation version, row key, and time semantics. The browser may receive the data from a static asset, a download, local storage, or an application endpoint. Whatever the path, the model card should name it.

Keep raw fields separate from derived fields. A rolling statistic should document the rows it can see and the lag applied before the target event. A market feature should document the book or consensus rule and capture time. An injury feature should document the report timestamp. These details matter more than the choice of activation function.

Before training, run simple audits: event keys are unique, timestamps are ordered, labels are absent from the feature matrix, future rows cannot enter rolling windows, and missing values are handled by a declared rule. The cheapest leakage test is often reading the columns out loud and asking when each one became knowable.

Split forward, never across the future

Random shuffling is natural for many machine-learning tasks and dangerous for sports replay. Adjacent games share teams, coaching systems, injuries, and market regimes. Mixing later events into training lets the model learn from a future that the live bettor did not have.

Use an expanding or rolling time split. Train on an earlier window, tune on the next untouched window, and reserve the final window for one evaluation after the design is settled. If you keep editing features after reading the final window, it is no longer final. Promote a newer untouched window or admit that the result is exploratory.

Hyperparameter search belongs inside the training and validation loop. The browser can automate that loop, but it cannot make repeated peeking harmless. Every choice influenced by the held-out result spends information from that result.

Compare against the market on the same rows

A model metric without a baseline is hard to interpret. For probabilistic predictions, compare the model with the devigged closing market on the exact same events. For ATS grading, publish wins, losses, win rate, window, sample, grading rule, and Do not turn the result into a return claim unless actual available prices and stake rules are part of the ledger.

The closing market is not perfect truth. It is a strong, timestamped competitor. Beating a weak naive baseline while losing to the close is not a betting edge. Beating the close on a design window is not proof either; the result still has to survive the untouched test and then live pregame use.

Keep prediction quality and ticket selection separate. A model may forecast every event but recommend action only when a defined condition is met. Grade the forecasts on all eligible rows and grade the selected tickets on the declared subset. Dropping low-confidence forecasts from the metric after seeing outcomes is selection bias.

Make browser execution reproducible

Record the dataset version, code version, model configuration, feature list, split boundaries, seed policy, runtime version, and evaluation output. A saved model without those fields is an artifact, not a reproducible experiment.

Exact binary equality across devices may not be realistic when hardware backends and floating-point kernels differ. Reproducibility should therefore distinguish identical inputs and configuration from acceptable numerical tolerance. Claim bit-for-bit output only after testing it across the supported runtimes.

Local storage can keep model state on the device, but the page may still fetch data or telemetry. Verify the browser's network panel, document what leaves the tab, and make publication a separate explicit action. “No upload” should describe observed behavior under the shipped configuration.

Stress the model before trusting the clean chart

Run a shuffled-label control. Performance should collapse toward the appropriate no-signal baseline. Remove the market feature and see what remains. Shift the test window. Split by season, team, favorite status, and market source when the sample supports it. Large swings are not automatically defects, but they are reasons to narrow the claim.

Audit calibration as well as rank order. A model that sorts events correctly but speaks in inflated probabilities can still recommend oversized or unjustified decisions. the calibration guide explains the reliability check; the Brier guide explains one proper scoring rule.

Keep the ugly runs. Removing a bad interval because “the league changed” requires a predeclared regime rule and a new test, not an edit to the chart after the fact.

Move from backtest to live shadow mode

The first production state should be observation, not action. Generate predictions before events, lock them with timestamps, save the available market, and grade after settlement. This creates a live-pregame sample that cannot benefit from backfill.

Only then compare the live behavior with the backtest. Differences can come from data latency, changed feature definitions, market-source drift, or an environment the training window did not represent. The right response is diagnosis, not a looser threshold.

Studio is the relevant modeling surface, the picks page is where live decisions can be inspected, and Workshop is the adjacent build context already linked by this article. Treat any interface claim as something the shipped product must demonstrate.

The watchpoint

A browser backtest earns trust when another person can identify the data, rerun the time-ordered split, reproduce the metric within the declared tolerance, and see every exclusion. The runtime makes that workflow portable. The evidence makes it real.

Frequently asked questions

Can a TensorFlow.js model trained in the browser actually compete with a Python model trained on a GPU server?
Sometimes. Small tabular models can run comfortably in a browser, while large datasets and expensive architectures may not. Compare the same data, split, seed policy, model, and metric before attributing a result to the runtime.
How do I know my browser backtest is not look-ahead leaking via shuffle?
Sort by the event’s pregame timestamp, split forward in time, and audit every feature’s availability. A random row split is not an honest substitute for replaying the order in which information arrived.
What's a realistic baseline Brier score for an NFL spread model so I know if mine is any good?
Use the devigged closing market on the exact same held-out events as the baseline. A universal score copied from another dataset is not comparable unless the label, window, exclusions, and close source match.
If everything runs on my device, where does the historical training data come from?
The application still needs a documented dataset. Local execution describes where computation happens; it does not prove where data came from or whether the page made network requests. Inspect provenance and verify the network boundary.
Share this guide Help another reader make a sharper decision.

Get picks in your inbox

One email, every slate — ranked edges, no touts. Unsubscribe any time.

Continue with evidence

Related reading and source status

Related Reads

Inside the Six-Stage Reveal When Training Finishes — on the Advanced Canvas — Shark Snip
Betting Tools

Inside the Six-Stage Reveal When Training Finishes — on the Advanced Canvas

A finished training run on /build/[slug] plays a fixed six-stage reveal, grade first, timed to the exact millisecond in the source.

Sep 11, 2026 5 min read
The Screen That Shows Your Backend Before Training Starts — on the Advanced Canvas — Shark Snip
Betting Tools

The Screen That Shows Your Backend Before Training Starts — on the Advanced Canvas

Pre-Train Preview on /build/[slug] names the exact backend a run will use, from a single side-effect-free probe, before training starts.

Sep 11, 2026 5 min read
Eight Lattice Slots, and the 56 Modules That Can Fill Them — Shark Snip
Betting Tools

Eight Lattice Slots, and the 56 Modules That Can Fill Them

The /build board holds eight fixed slots filled from a live, growing list of pieces, not a four-tier gallery.

Sep 11, 2026 6 min read

3 related posts

No data

No graded picks from this article's sources yet

No tracked source has a graded 90-day record for this sport yet. Source scorecards fill after their picks are graded. The house record is separate: see /picks.