Strength Journeys (strengthjourneys.xyz)
Strength Journeys is a free, open-source web app to visualize your barbell lifting data from Google Sheets. Privacy-first — your lifting data is never stored on our servers. All analysis happens client-side in your browser. Chalk not included.
Powerlifters and barbell weirdos will love this app, but our real target audience is the novice. If we can help someone start barbell training and keep them going for ten years, their life and their family will be transformed. Barbell strength training is one of the most effective things you can do for your health, longevity, and quality of life. Stronger people are harder to kill, more useful in general, and tend to live longer.
- Home dashboard — activity heatmaps, PR tracking and session highlights across all your lifts (this was formerly the separate Analyzer page)
- Big four lift cards — at-a-glance dashboard showing PRs, estimated 1RM, tonnage, and recent activity for squat, bench press, deadlift, and strict press
- Visualizer — interactive line charts of your lift history over time with E1RM (estimated one-rep max) curves
- Log — record today's session set by set, writing straight back to your own sheet
- Lift Explorer — per-lift deep dive: top lifts, rep-range PRs and strength potential
- Tonnage tracking — volume analysis showing total weight moved over time
- One rep max calculator — estimate your 1RM from any rep/weight combination
- Strength levels — see how your lifts compare to strength standards
- How strong am I — percentile comparison against the lifting population
- 1000lb club calculator — track your squat/bench/deadlift total
- Warm-up sets calculator — generate warm-up ramp sets for any working weight
- Strength year in review — annual recap of your lifting highlights
- AI lifting assistant — chat-based analysis of your training data
- Gym timer — rest timer with audio cues
- Plate milestones — track the classic gym-floor one/two/three-plate milestones
- Gym playlist leaderboard — community-voted workout playlists
- Import from other apps — drag in a CSV or XLSX export from Hevy, Strong, StrongLifts, Wodify, BTWB or TurnKey. Parsing runs entirely in your browser and works without signing in; signed-in users can merge the history into their own sheet
Requires user data in a Google Sheet with columns: date, lift type, reps, weight (kg or lb).
Strength Journeys asks for exactly one Google scope: drive.file. This is Google's per-file scope, and it is the narrowest one that allows an app to write. It means:
- We can only see the sheet you hand us. Access is limited to a file you explicitly choose in the Google file picker, or one the app creates for you from the sample template. Nothing else.
- Every other file in your Drive is invisible to us. Not readable, not writable, not even listable — we cannot see that it exists. This is enforced by Google on their side, not by a promise in our code. Even where the app asks Drive for a list of your spreadsheets during setup, Google returns only the files you have already granted.
- Reads and writes both go to that one linked sheet. Reads render your charts. Writes happen only when you do something that is meant to change your data: logging a set on the log page, correcting a date typo, or merging imported history in.
- We never touch your Drive settings, folders, sharing, or any other Google service. The other two scopes we request are your email address and profile name, used to identify your account.
You can revoke access at any time from your Google account permissions, and your sheet stays exactly where it is — it is your file, in your Drive, and it remains readable without this app.
Open our sample data format in Google Sheets (click File menu, then 'Make A Copy').
Your lifting data is never stored server-side. Google Sheet reads and writes are authenticated via Google OAuth and go through a Next.js API route proxy, but the rows are parsed and analyzed entirely client-side in your browser. The app does not persist your training data in a database — your Google Sheet remains the only copy.
The server does keep a small operational record per account (sign-in timestamps, which page you signed up from, the id of the sheet you linked, and when it was last read) so that onboarding, sheet recovery, and support requests work. It holds no lifts, no weights, and no analysis.
Framework & language:
- JavaScript (no TypeScript) with JSDoc for key function documentation
- Next.js 16 (Pages Router)
- React 19
- Deployed on Vercel with Vercel Analytics
UI & styling:
- Tailwind CSS v4 with 8 custom themes via CSS variables
- shadcn/ui components (Radix primitives)
- Lucide React icons
- Motion (Framer Motion) for animations
- Embla Carousel for carousels
- next-themes for theme switching
Data visualization:
- Recharts for line, area, and bar charts
- react-calendar-heatmap for activity heatmaps
- html2canvas-pro for share-to-clipboard image capture
Auth & data:
- NextAuth.js v4 with Google OAuth
- Google Sheets API for user lifting data —
drive.filescope only, so read/write access is limited to the single linked sheet - SWR for data fetching and caching
- Vercel KV for server-side storage (playlists, leaderboard, and lightweight per-account onboarding/support metadata — never lifting data)
AI features:
- Vercel AI SDK with xAI (Grok) as the primary provider and OpenAI as fallback
- Streamdown for streaming markdown rendering
- Shiki for code syntax highlighting in AI responses
Content & SEO:
- Sanity CMS for articles
- next-seo and next-sitemap for SEO
See package.json for the full list of dependencies.
This repo has grown into a multi-tool lifting app (home dashboard, visualizer, session log, calculators, AI assistant, playlists, articles) that shares a common app shell and lifting-data pipeline.
src/pages/— Next.js Pages Router routes (tool pages, article pages, API routes)src/pages/_app.js— global providers + app layout wrapper (theme, auth, lifting data, athlete bio, timer)src/components/— feature UI and shared UIsrc/components/home-dashboard/— home dashboard cards (PRs, heatmaps, session highlights)src/components/visualizer/— charting + visualizer UIsrc/components/ui-shell/— app shell: layout, nav, footer, theme provider and backgroundssrc/components/ai-elements/— composable chat UI building blocks used by the AI assistantsrc/components/ui/— shadcn/Radix-based primitivessrc/hooks/use-userlift-data.js— central Google Sheets fetch/parse/cache context (SWR + demo mode + derived metrics)src/lib/data-sources/import-dispatcher.js— the single parsing entry point:parseData()for Google Sheets rows,parseImportedFile()for drag-and-drop CSV/XLSXsrc/lib/data-sources/— one parser per supported export format, plus shared decode/normalize helperssrc/lib/processing-utils.js— shared processing/aggregation helpers (PRs, tonnage, timing logs, unit conversion)src/pages/api/sheet/read.js— authenticated Google Sheets + Drive metadata proxysrc/pages/api/sheet/— the rest of the sheet surface: linking, provisioning, and the operation-oriented write routessrc/pages/api/auth/[...nextauth].js— NextAuth Google OAuth setup + token refreshsrc/lib/sanity-io.js— Sanity CMS fetch helpers for article pages and related content
- User signs in with Google (
next-auth) and picks a spreadsheet. use-userlift-datafetches/api/sheet/readvia SWR.- API route reads Google Sheets + Drive metadata and returns JSON.
parseData()normalizes rows into canonical lift entries.- Shared derived metrics (PRs, tonnage, lift types, session lookups) are computed once in context and consumed by pages/cards.
- Build a new tool page (or improve an existing one): start in
src/pages/<tool>.js, then add/adjust feature components undersrc/components/<feature>/ - Improve parser tolerance for real-world spreadsheets (header variations, blank-row patterns, date/weight formats):
src/lib/data-sources/strength-journeys-parser.jsand the sharedparser-utilities.js - UI polish and usability improvements (layout spacing, card composition, mobile tweaks, theme details):
src/components/,src/components/ui/,src/styles/globals.css - Add import support for another lifting app: add a parser under
src/lib/data-sources/(copy the shape ofhevy-parser.js), then register its detection inimport-dispatcher.js. There is a regression script for this —npm run validate:hevy, run against fixtures infixtures/imports/
src/lib/parse-data.jsandsrc/lib/parse-turnkey-importer.jsare thin re-exports kept for older import sites. New work should reach forsrc/lib/data-sources/directly.
stable— Production branch. Deploys to strengthjourneys.xyz.main— Development branch. Deploys to a Vercel preview URL for testing. Has informative console logging of processing timings and any errors.- Feature branches are created from
mainand deleted after merging.
Strength Journeys unites and extends features from earlier projects by the same author:
- onerepmaxcalculator.xyz — standalone one rep max calculator (predecessor to the current calculator page)
- powerlifting_strength_tracker_js — the original E1RM visualization prototype built with vanilla JS and Chart.js, which evolved into the Strength Journeys visualizer