← Back to Writing
Tools

Tap-to-Track: Eight Seconds From Purchase to Spreadsheet

Every expense app I tried failed at the same moment: the one where you are standing at a counter with a receipt in your hand. Tap-to-Track is what I built instead — a Back Tap, three taps, and the entry is in a Google Sheet I own.

By Ayush·14 min read·December 2025

Expense tracking does not fail because people lack discipline. It fails at the counter. You pay for lunch, you are walking back to your desk, and logging it means unlock, find the app, wait for it to load, tap through four screens. So you tell yourself you will do it tonight, and you do not. A month later the data is gone and the habit is dead.

The commercial apps do remove that friction, but they remove it by taking something: your bank credentials, your attention through ads, or a subscription. Your spending history becomes their asset. Tap-to-Track removes the friction without taking anything. The data lives in a spreadsheet you own, the code runs in your own Google account, and the entry takes one gesture and three taps.

Time per entry
~8s
Pocket to written row, including the confirmation banner.
Third parties
None
No bank link, no vendor server, no telemetry.
Running cost
₹0
Apps Script and Sheets, both on the free tier.
Setup
~25 min
Once, following the four guides in the repository.

What the eight seconds look like

Double-tap back of phone ↓ Amount → 120 or =500/3 ↓ Category → one tap ↓ Remark → type, or skip ↓ ~2 seconds ₹166.67 → Food - Lunch (500/3) Thursday, 6 August 2026

Back Tap is the iOS gesture almost nobody uses — Settings, Accessibility, Touch, right at the bottom — and it fires a Shortcut when you tap the back of the phone twice. That is the entry point. There are three others for when the gesture is inconvenient: a home screen icon, Siri, and Control Centre. The screen never has to leave the lock.

So what? The gesture is the design, not a garnish on it. Anything that requires finding an icon has already lost to the queue behind you.

The architecture, in one line

iPhone Shortcut ──HTTPS POST──► Google Apps Script ──Sheets API──► Your Sheet JSON + token web app, runs as YOU stays private

There is no fourth box. The web app is deployed from the spreadsheet itself, so it needs no credentials to reach it — it is already inside your account. Nothing is published, nothing is hosted, nothing is shared.

The amount field does arithmetic

Real spending is rarely one clean number. A dinner gets split three ways; an invoice needs GST added; a discount comes off a quantity. So the amount field takes expressions, with correct operator precedence and optional =.

You typeLogsUse case
120120normal
=500/3166.67split three ways
=(250+130)/2190two items, split in half
=1200*18%216GST
=1500*2-3002700quantity, minus a discount
1,200 · ₹4501200 · 450commas and symbols tolerated
-50−50refund

Two lunches on the same day

The sheet holds one cell per category per day, so a second entry has to combine with the first rather than overwrite it. It does, and it keeps full precision while doing so — a plain number stays a plain number, and a cell only becomes a formula if you typed arithmetic.

Cell beforeYou enterBecomesDisplays
(empty)120120₹120
(empty)=500/3=500/3₹166.67
75120195₹195
75=500/3=75+(500/3)₹241.67
=576-50120=576-50+(120)₹646

Remarks append with a semicolon, so the day's cell carries all three descriptions. There is one level of undo, and it restores the exact prior state — including whether the cell was a number or a formula.

So what? Subtotals stay exact because the sheet keeps the arithmetic, not the rounded result. ₹166.67 three times is ₹500, not ₹500.01.

The layout of the sheet is not hardcoded

The obvious way to write to a spreadsheet is to hardcode the column: groceries go in column D. That works until somebody inserts a column, and then a month of groceries quietly lands in Transport. The script never stores a column position. On every single request it:

01
Reads the header rows of the current month's tab
Rows 2 and 3, every time — not once at deploy, and not cached.
02
Finds the column whose header text matches the category
Match by name, so inserting, reordering, or renaming columns changes nothing in the code.
03
Takes the adjacent Remarks column for the description
The pairing is positional by one step, which is the single layout rule the sheet has to keep.
04
Scans the Date column for today, in your timezone
Which is why the Google Sheets timezone setting matters, and is one of the two settings people miss.
05
Writes that one cell, and the remark beside it
Bounds-checked first. If the check fails, it aborts without writing.

Because it navigates by name, you can insert columns, reorder categories, add charts, or add whole new categories and it adapts with no code change. If the sheet stops looking like the sheet it expects, it refuses to write rather than guessing.

So what? Refusing is a feature. A tracker that silently files things in the wrong place is worse than one that stops and says so.

The spreadsheet is the actual product

The template in the repository is a complete tracker with zero data in it — every formula, chart and conditional format works, every value is blank. Twelve tabs on the Indian financial year, ten categories with sub-categories, each paired with its Remarks column. Change two cells on the Summary sheet and all twelve tabs re-date themselves; weekends turn red on their own.

Above that sits a summary dashboard — year-to-date income, expense, savings rate, best month, top category, month-over-month change, and a mid-month savings projection that weights recurring against discretionary spend — and a per-month dashboard with a category breakdown, percentage of income, and a donut chart. None of it is locked. It is a spreadsheet; extend it.

Adapting it outside India

The tab names are month names, so a different financial year is a rename plus a date-formula tweak. Categories are discovered from the headers, so a new one works immediately — just add it to the Shortcut's list too. Currency is a cell number format; the script stores plain numbers. The one thing to preserve is the three anchors it navigates by: every category column immediately followed by a column headed Remarks, and row 2 containing Date and Daily Expenditure.

The security thinking, since it is a public endpoint

The web app is deployed with access set to "Anyone", which sounds alarming and is worth being precise about: that setting governs who can call the URL, not who can read your sheet. A shared token guards it, and requests without the correct token are rejected before any sheet access happens. The URL is the only secret in the system. Treat it like a password.

No eval(). An arithmetic field is exactly where you reach for eval, and on a public endpoint that would run arbitrary code with your Drive permissions. Instead there is a hand-written recursive-descent parser behind a strict character whitelist. Any letter is rejected outright, which blocks =SUM(A1:A5), =alert(1), and every injection shaped like them.

The script cannot restructure your sheet. The executable code contains exactly two mutating calls, setValue() and setFormula(). There is no insertRow, deleteRow, insertColumn, deleteColumn, insertSheet, deleteSheet, clear, merge, appendRow or setDataValidation anywhere in the file. The worst a bug can do is write a wrong number into one cell you can undo.

So what? Auditing that list — and being able to state it in one sentence — is worth more than any amount of defensive code around a larger surface.

Which Google account to use

The script must run under an account with edit access to the sheet. It does not need to own it, but every extra party is a dependency that can break quietly.

SetupVerdict
Personal Gmail owns the sheet, same account runs the scriptBest. No dependencies.
Sheet owned by someone else, you have edit accessWorks, but breaks silently if they revoke access
Work or Workspace accountAdmins can block "Anyone" web app deployment — check first
Two accounts, one for the sheet and one for the scriptWorks, but doubles what can go wrong

On a Workspace account you find out at the deploy step: the Anyone option under "Who has access" is missing or greyed out. Build on a personal Gmail instead. And be signed into the right account before you start — creating the script under the wrong one is the single most common setup mistake.

Setting it up

About twenty-five minutes end to end, no development environment, and the repository has a guide for each stage plus a troubleshooting page covering every error the script can produce.

01
Set up the spreadsheet and script
Copy the template into your own Drive, open Extensions → Apps Script from inside it, paste in Code.gs. About ten minutes.
02
Deploy it as a web app
Deploy → New deployment → Web app, executing as yourself, access "Anyone". Copy the URL and keep it private.
03
Build the iPhone shortcuts
The guide walks it tap by tap. Paste the deployment URL into the first action and edit the category list to match your headers. About ten minutes.
04
Check the two settings everyone misses
Notifications for the Shortcuts app — without them the entry logs but you see nothing — and the Google Sheets timezone, which is what the date scan uses.
05
Wire it to Back Tap
Settings → Accessibility → Touch → Back Tap → Double Tap. That is the last time you open Settings for this.

What it deliberately does not do

No bank sync, no receipt scanning, no budget alerts. Each needs either credentials or a server, and the point is that there is neither.

Three real limitations are worth knowing before you build it. One cell per category per day — three lunches become one figure with three semicolon-joined remarks, so you cannot later ask what the second lunch on the 12th was; that granularity does not exist in the sheet's design. Renaming a category means updating the Shortcut's list, because the phone cannot know the sheet changed until it asks. And cold start: the first request after about fifteen idle minutes takes three to five seconds while Apps Script wakes up, later ones one to two. The write completes regardless — you can pocket the phone before the notification lands.

iPhone only for now. The backend is a plain HTTP endpoint, so an Android client through Tasker or HTTP Shortcuts would work; it just is not written yet.

Where the AI actually helped

I built this with Claude as a pair-programmer, and the useful part was not code generation. It was the parts of the job I would otherwise have skipped.

The recursive-descent parser is the clearest case. I knew I did not want eval; writing a correct precedence-climbing parser with a character whitelist from scratch, on a weekend, for a personal expense tracker, is exactly the kind of thing that gets abandoned in favour of the unsafe one-liner. Having a second party draft it and then argue about the edge cases — percentages, unary minus, mismatched brackets — made the safe version the cheap option instead of the expensive one.

The second case is the audit. "List every mutating call in this file, and tell me what the worst thing it can do to my spreadsheet is" is a question that takes a person an hour and a model a few seconds, and the answer is what let me write the guarantee in the section above as a fact rather than an intention. The third is the documentation: six guides, a troubleshooting page covering every error string, and a localisation guide for people outside India. Personal projects do not usually get documentation, because by the time the thing works the author no longer needs it.

So what? The tool would exist without the AI. The parser, the audit and the six guides would not — those are the parts that get cut when it is a weekend project with an audience of one.

Repository
srivastav-ayush/tap-to-track

The Apps Script backend in one file, the blank spreadsheet template, and six guides: setup, the Shortcut build, the spreadsheet, troubleshooting, settings and localisation, and how it works. MIT licensed.

github.com/srivastav-ayush/tap-to-track ↗
Built with: iOS Shortcuts (Back Tap trigger, arithmetic-aware amount entry, category picker), Google Apps Script (header-driven column discovery, bounds-checked writes, undo snapshots, script-lock concurrency), Google Sheets, and a hand-written recursive-descent arithmetic parser in JavaScript. Claude was used as a pair-programmer on the backend, the Shortcut and the documentation. Requirements: a Google account and an iPhone on iOS 15 or later; Excel is not needed — the .xlsx is only a container. Note: the web app deployment URL grants write access to your sheet. Do not publish it.