⏱️ Online Stopwatch with Lap Timer
Press Start and the tool doesn't literally add up small chunks of time thirty milliseconds at a stretch. It records the exact performance.now() reading the instant you started, then on every redraw it subtracts that stored number from the current one to get elapsed time — recomputed fresh, not accumulated. That distinction matters because browsers deliberately slow down setInterval in background tabs to save battery, which is the classic way homemade timers drift or lose seconds. Because this stopwatch always derives its number from a timestamp difference instead of counting how many ticks actually fired, the displayed time snaps back to the correct value the moment you return to the tab, even after minutes away.
Stopwatch is a free browser lap timer that tracks elapsed time by comparing the monotonic performance.now() clock against a stored start timestamp, rather than counting setInterval ticks, so the number displayed stays accurate even when the browser throttles the tab's screen updates.
Private by design. This tool runs entirely in your browser — nothing you enter is uploaded or stored, and it works offline.
About
Under the hood there are three pieces of state: an accumulated `elapsed` value in milliseconds, a `startAt` snapshot of `performance.now()` taken the moment you press Start, and a boolean `running` flag. The function that produces the number on screen is simply elapsed plus, if running, the difference between right now and startAt. A `setInterval` calls that function every 30 milliseconds purely to repaint the display — the interval itself carries no timing information, it's just a refresh trigger. That's the correct way to build a stopwatch, and it directly avoids the common bug where a timer adds a fixed increment on every tick and slowly drifts once ticks get delayed, skipped, or coalesced.
That design choice is also what happens when you switch away to another tab. Browsers throttle background-tab timers to save CPU and battery — a `setInterval` set for every 30ms can be delayed to once a second or slower while the tab isn't visible. On this stopwatch that only affects how often the on-screen number gets repainted; the underlying math (current timestamp minus start timestamp, plus whatever was already banked) doesn't care how many repaints were skipped. Switch back to the tab and the very next redraw shows the exact correct elapsed time — nothing is lost or gained by the throttling, only the smoothness of watching the seconds tick by while you were looking at something else.
Using `performance.now()` instead of `Date.now()` is also the right primitive for this job, not an incidental detail. `Date.now()` reflects your system's wall clock, and wall clocks can jump — a laptop waking from sleep and resyncing with an NTP server, a manual clock change, or a daylight-saving adjustment can all make `Date.now()` leap forward or even backward mid-session. `performance.now()` is defined as a monotonic clock: it only ever counts upward at a steady rate and is unaffected by those corrections, which is exactly the guarantee a stopwatch needs and a plain wall-clock timer doesn't have.
The honest limitation is persistence, and there isn't any. This build keeps `elapsed` and the `laps` array as ordinary JavaScript variables in page memory — there is no call anywhere in the source to localStorage or to this site's own `Playground.store()` helper that other Toolio tools use to survive a reload. That means refreshing the page, closing the tab, or clicking away to another tool erases your running time and every recorded lap instantly and permanently. There's no "resume last session," nothing syncs across devices, and nothing to back up, because nothing is ever written to storage in the first place. If a lap history actually matters to you — a workout log, a set of presentation timings — copy the numbers down or take a screenshot before you navigate away, because this page will not remember them for you.
How to use
- Click "Start" — the button immediately relabels itself "Pause" and the on-screen clock begins climbing in real time, repainting every 30 milliseconds.
- Click "Lap" at any point while running to snapshot the current elapsed time; the new entry is pinned to the top of the lap list and shows both its split (time since the previous lap) and its cumulative total.
- Click the same button again, now labeled "Pause," to freeze the display — the elapsed time is preserved internally, nothing is lost, and the button reverts to "Start."
- Click "Start" once more to resume counting from exactly where you left off, not from zero.
- Click "Reset" to zero the display, clear every recorded lap, and restore both buttons to their starting labels — this is also the only way to begin a fresh session, since there's no save feature to protect the old one first.
FAQ
- How does this stopwatch actually measure time under the hood?
- It reads `performance.now()` once, the instant you press Start, and stores that number. From then on, the value on screen is just "time already banked" plus "current performance.now() minus that stored starting timestamp" — recalculated fresh on every 30ms repaint. It never simply adds a fixed +30ms to a running total on each tick, which is the shortcut that makes many homemade timers slowly drift out of sync.
- What happens to the time if I switch to another browser tab while it's running?
- Background tabs get throttled — the browser can delay a 30ms `setInterval` down to once a second or slower to save CPU and battery, so the on-screen number may appear to freeze or jump while you're away. But because this stopwatch always computes elapsed time as a timestamp difference rather than counting how many ticks fired, switching back to the tab makes the very next redraw show the exact correct elapsed time. You don't lose or gain time from the throttling — only the visual smoothness suffers while you're not looking.
- Why performance.now() instead of Date.now() — does it actually matter?
- Yes. `Date.now()` reflects your system's wall clock, which can jump forward or backward — for example right after a laptop wakes from sleep and resyncs with an NTP server, or if the system clock is changed manually. `performance.now()` is a monotonic clock that only ever increases at a steady rate and is immune to those corrections, which is exactly the property a stopwatch needs and this build uses the correct one for it.
- Does it save my elapsed time or lap history anywhere?
- No — and unlike some other Toolio tools, it doesn't use the browser's localStorage at all for this data. Everything you see exists only in the page's memory for as long as this specific tab stays open. Refresh the page, close the tab, or navigate to another tool, and your elapsed time and every lap are gone for good; there's no undo and no auto-save, because nothing is ever written to storage in the first place. Copy the numbers down or screenshot them before you leave if you need a record.
- Is there a limit on laps, and what do the two numbers on each lap row mean?
- There's no limit — the list simply grows, with the newest lap pinned to the top. Each row shows two numbers: the split, in the accent color, which is the time elapsed since your previous lap; and the total, in gray, which is the cumulative time since you pressed Start. That pairing lets you judge an individual segment — one workout interval, one section of a talk — without losing track of the overall run.
- Does this tool upload my data?
- No. Everything runs right in your browser, so your data never leaves your device — it even works offline once the page has loaded.