Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →A leaderboard built on Astro, Cloudflare Workers, and D1 can store every score reliably, and related writes can be made atomic. What it cannot do on its own is show that a score was earned. D1 transactions guarantee that a group of database changes succeeds or rolls back together. They say nothing about whether the number a browser sent reflects real play.
In this guide, “verifiable” has a narrow engineering meaning: the server can check each submitted score against rules that it enforces. Cloudflare’s documentation covers deployment, SQL access, and transactions. It does not specify a protocol that proves browser-submitted scores are authentic, so that layer is a design decision you make for your own game.
As an Amazon Associate I earn from qualifying purchases.
What “verifiable” has to cover
Four properties are often grouped under “verifiable.” They are separate, and the platform provides only some of them.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
| Property | Question it answers | What the platform provides | What you build |
|---|---|---|---|
| Durability | Was the record saved? | D1 is a serverless SQL database that a Worker reaches through a binding | Schema, retention, and an export plan |
| Atomicity | Did all related rows change together? | batch() runs statements in sequence as a transaction and rolls back when one fails |
Deciding which writes belong in one batch |
| Input validity | Is the request well formed and within range? | Not provided by D1 or Workers | Type, range, and size checks in the route that receives the score |
| Score authenticity | Did the game actually produce this score under its rules? | Outside what the platform guarantees | A mechanism tied to your game’s rules, covered below |
A board with the first two properties is consistent. It becomes verifiable only when the fourth is also enforced, and that depends on the game.
#1 Best Overall
- Platform Compatibility: This PC controller is designed for Windows PC, Steam, Switch, Android, and iOS. Xbox-style asymmetric stick layout for PC gamers. Three modes cover all your devices. Please check your device compatibility before purchase
- Three Connection Modes: 2.4G wireless, Bluetooth, wired USB-C. PC gets native XInput/DirectInput. Switch pairs via Bluetooth, no adapter. This gaming PC controller switches devices seamlessly. Stable wireless minimizes random disconnects during gaming
- Hall Effect Precision: Hall effect joysticks and triggers eliminate stick drift. This gaming controller for PC delivers smooth, responsive input with no dead zones. Built for FPS, racing, and action games. Long-term precision for competitive PC gaming
- Back Buttons & Battery: Two programmable back buttons map combos and shortcuts. Textured grips with dual vibration. 1000mAh battery delivers up to 20H playtime. RGB can be turned off. A solid PC controller for gaming with custom back buttons
- ABXY Layout Switch: Press B + Minus + Plus to swap between PC and Switch modes. Features: 1000Hz polling rate, RGB lighting, turbo. Note: designed without mic jack or gyro sensor
How the pieces fit together
- Game page: a static Astro page that loads the game’s JavaScript and runs the game in the browser.
- Score endpoint: an on-demand Astro route running in a Cloudflare Worker. It validates the submission and writes it to D1.
- Leaderboard endpoint: an on-demand route that reads the top rows at request time.
- D1 database: holds every accepted submission and one best-score row per player.
- Durable Objects (optional): coordinate live match state if the game needs it. They are compared with D1 in the limits section.
The browser never receives database credentials. It sends a request to the score endpoint, and only the Worker talks to D1.
Set up the Astro project for Cloudflare
Choose a rendering mode for each page
Astro’s Cloudflare deployment guide supports full-stack applications on Workers. Cloudflare’s Astro guide says the adapter sets server output by default, and individual pages can be prerendered when they do not need on-demand rendering. A fully pre-rendered site does not need the adapter and can be deployed as static assets.
| Page or route | Rendering | Reason |
|---|---|---|
| Game page | Prerendered with export const prerender = true; |
The page shell and game assets do not change per request |
| Leaderboard display | Fetched by the browser from the leaderboard endpoint on load | Prerendered HTML would freeze the scores that existed at build time |
| Score and leaderboard endpoints | On demand (the server default) | They read or write D1 on each request |
| About or privacy page | Prerendered | No per-request data |
Install the adapter and confirm the preview
- Create the project with
npm create astro@latestand choose a template. - Install the adapter with
npm install @astrojs/cloudflare. - Register the adapter in
astro.config.mjs:import { defineConfig } from 'astro/config'; import cloudflare from '@astrojs/cloudflare'; export default defineConfig({ adapter: cloudflare(), }); - Open the Wrangler configuration that Astro generated and keep its compatibility date. Take that value from your generated file, not from an older tutorial.
- Run the local preview described in Astro’s Cloudflare deployment guide, then deploy with
npx wrangler deploy.
If hydration errors appear after deploying
Astro’s deployment guide notes that Cloudflare Auto Minify can cause client-side hydration mismatches. The documented fix is to disable Auto Minify for the site. If the browser console reports hydration mismatches after deployment, turn it off in Cloudflare’s dashboard for the site and reload.
Create the D1 database and schema
- Create the database with
npx wrangler d1 create leaderboard. The command prints the database ID you need in the next step. - Bind the database in your Wrangler configuration. The binding name is yours to choose, but the Worker code must use the same name. In TOML:
[[d1_databases]] binding = "DB" database_name = "leaderboard" # add the database_id printed by the create commandIf your project uses
wrangler.jsonc, the same entry goes in ad1_databasesarray. - Create
schema.sql:CREATE TABLE IF NOT EXISTS scores ( id INTEGER PRIMARY KEY AUTOINCREMENT, player_id TEXT NOT NULL, score INTEGER NOT NULL, submitted_at INTEGER NOT NULL ); CREATE TABLE IF NOT EXISTS best_scores ( player_id TEXT PRIMARY KEY, best INTEGER NOT NULL ); CREATE INDEX IF NOT EXISTS idx_best_scores_best ON best_scores (best DESC); - Apply the schema to the remote database with
npx wrangler d1 execute leaderboard --remote --file=./schema.sql. Use--localto apply it to the local development database instead.
The scores table keeps every accepted submission, which is what you would audit if a result were disputed. best_scores holds one row per player, and the index serves the descending sort the leaderboard performs.
Accept score submissions in a server route
The game page sends a JSON body to the score endpoint. The route validates the body and then passes the values to a write function. Validation comes first, because a transaction can only preserve what it is given.
Validate the request
export function parseSubmission(body: unknown) {
if (typeof body !== 'object' || body === null) return null;
const { playerId, score } = body as Record<string, unknown>;
if (typeof playerId !== 'string' || playerId.length === 0 || playerId.length > 32) return null;
if (typeof score !== 'number' || !Number.isInteger(score) || score < 0 || score > 1000000) return null;
return { playerId, score };
}
The 1,000,000 ceiling is only an example. Derive the real bound from your game’s rules. A range check rejects malformed input, but it cannot tell you whether a well-formed score was earned.
Write the submission with db.batch()
Bind values through ? placeholders and .bind(), never by building SQL strings from request data. The following function writes the raw submission and updates the player’s best score as one unit:
Rank #2
- With broad game support, the Logitech Gamepad F310 works with old standbys to today's biggest titles, so it's easy to set up and use with your favorite games.
- Profiler software allows the gamepad to be programmed to perform keyboard and mouse commands for games without gamepad support.* * Requires software installation.
- A familiar control layout that doesn't require a learning curve to be able to use, with all the same buttons as on an Xbox 360.
- The unique floating D-pad rests on four switches-instead of a single pivot point-making it responsive to quick changes in direction.
- The six-foot cord lets you lean back and play a comfortable distance from your PC monitor.
export async function saveScore(db: D1Database, playerId: string, score: number) {
const submittedAt = Date.now();
await db.batch([
db
.prepare('INSERT INTO scores (player_id, score, submitted_at) VALUES (?, ?, ?)')
.bind(playerId, score, submittedAt),
db
.prepare(
'INSERT INTO best_scores (player_id, best) VALUES (?, ?) ' +
'ON CONFLICT(player_id) DO UPDATE SET best = MAX(best, excluded.best)'
)
.bind(playerId, score),
]);
}
Wire the pieces together in the route in this order:
- Parse the request body as JSON and return a 400 response if parsing fails.
- Pass the result to
parseSubmissionand return a 400 response if it returns null. - Call
saveScorewith the D1 binding and catch any error. Return a 500 response so the game can show a retry message. - Return a success status only after
saveScoreresolves.
The read path is a single query against the best-score table:
SELECT player_id, best FROM best_scores ORDER BY best DESC LIMIT 10;
Serve it from the leaderboard endpoint, and have the browser fetch it on load so the displayed scores stay current.
What batch() guarantees, and what it does not
Cloudflare’s D1 documentation states the guarantee in one sentence: “Batched statements are SQL transactions.” (Cloudflare, D1 Database documentation.) In practice, the statements in a batch run in order, and a failing statement aborts the group with rollback. That keeps the raw submission and the best-score row consistent with each other, so a crash between the two writes cannot leave them out of step.
The guarantee stops there. A client that submits a fabricated 999999 through the same route is stored just as cleanly as an honest result. Everything the route accepts becomes a consistent row, so the authenticity decision has to be made before the batch is called.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Designing score authenticity
This guide does not choose a mechanism, because the right one depends on details it does not know: what the game computes, whether its outcomes are deterministic, and how much server work a single result costs. Three approaches are common, listed from the lightest to build to the heaviest. None of them is specified by Cloudflare’s documentation.
Plausibility checks and rate limits
Check that a score is achievable in the elapsed time, throttle submissions per player, and reject values above a ceiling derived from the game. These checks are cheap and catch careless or casual tampering. They do not establish that a score came from play, because anyone who can read the request format can submit a value that passes them. The daily request cap on Workers is a plan limit, not a rate-limit design, so per-player throttling still needs your own logic.
Rank #3
- Versatile compatibility: supports Xbox Series X/S, Xbox One X/S consoles and PC Win10 and above (including the game platform Steam).
- Precise control: features Hall joysticks and Hall triggers for a comfortable feeling, long service life and improved game accuracy.
- Plug and Play Convenience: Wired USB connection (removable) for easy setup and instant play without the need for additional drivers.
- Customizable experience: Includes 2 custom backbuttons that allow users to eliminate false triggers and improve their gaming experience.
- Impressive gameplay: Provides a pulsating vibration trigger and an asymmetric vibration grip motor for intense tactile feedback.
Replay verification
The client records its inputs, and the server re-runs the game from the same seed to reproduce the score. The server should issue a fresh seed for each run, so an old recording cannot be resubmitted. Replay checking requires deterministic game logic: the same inputs must produce the same result on the server and in the browser. That constrains the engine and physics code you can use unless you control the timestep and randomness yourself.
Recommended Free Tools
What it proves is narrower than its name suggests. It shows that the recorded input sequence produces the submitted score under the game’s rules. It does not show that a person pressed those keys, so a bot that sends legitimate inputs passes.
Server-authoritative simulation
The server runs the game rules itself. The browser sends inputs, and the server computes the score, so the submitted number is never trusted. This removes client-side score forgery, but it moves the game logic into the Worker and adds a workload to every submission. Replay verification carries the same cost, because it also runs the game logic inside a Worker invocation. The per-invocation CPU limit in the next section therefore applies to both. A fast-paced game that must simulate many frames per submission may not fit the Free plan’s 10 ms limit, while the Paid plan’s listed limit is 5 minutes.
Choosing a mechanism and labeling the board
- If the score can be recomputed from inputs within your per-invocation CPU budget, use server-authoritative simulation.
- If the game is deterministic but the simulation is too heavy for one request, replay verification may still fit. Its cost depends on the size of the input log and the cost of the simulation, so measure both on your own game before committing.
- If neither fits, use plausibility checks and label the board as self-reported rather than verified.
Scale and platform limits
The figures below are Cloudflare’s published limits as of the dates shown. They are useful for planning, but they describe plan allowances, not how fast your game will run.
| Limit | Workers Free | Workers Paid | Source and date |
|---|---|---|---|
| Maximum D1 database size | 500 MB | 10 GB | Cloudflare D1 limits page, last updated April 21, 2026 |
| Requests per day | 100,000 | No request limit | Cloudflare Workers limits page, last updated September 5, 2026 |
| CPU time per invocation | 10 ms | 5 minutes | Cloudflare Workers limits page, last updated September 5, 2026 |
D1 is documented as single-threaded per database: each database processes queries one at a time. Concurrent score submissions therefore queue behind each other. Batching keeps related statements together, but it does not run them in parallel. Keep the number of statements per submission small, and index the columns your leaderboard query sorts by. The D1 documentation includes a rough throughput illustration based on query duration. Treat it as arithmetic rather than a forecast for your game, because write frequency, index design, and query cost all change the outcome.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchDurable Objects or D1 for game state
Cloudflare’s storage comparison names Durable Objects as suitable for real-time collaboration, including game-server workloads, and describes D1 as a serverless SQL database. The two address different needs.
| Concern | D1 | Durable Objects |
|---|---|---|
| Fit described by Cloudflare | Serverless SQL database | Real-time collaboration, including game-server workloads |
| Natural use in this stack | Durable score records and leaderboard queries | Coordinated live game state shared by several clients |
| Limits in the storage comparison | 500 MB (Free) and 10 GB (Paid) per database, one query at a time per database | Not stated in Cloudflare’s storage comparison |
A common split, offered here as a design suggestion rather than a Cloudflare recommendation, keeps live match state in a Durable Object and writes only finished, validated results to D1.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




