Geekabode privacy notes (draft)
These draft notes describe the information Geekabode uses, what stays in your browser, what reaches its server and other services, and how stored records are retained. Service settings and retention that still need owner confirmation are listed below. Owner and counsel must review these notes before launch.
What stays in your browser
The calculator uses browser storage on this site's origin to save your calculator numbers, choices and sign-in records:
- Calculator numbers — one saved buyer profile holding your home price, down payment, monthly payment, location, timeline, loan term, property tax, insurance, HOA, current rent, rate, maintenance, PMI, wait horizons, rate and price changes, closing-cost and refinance-cost settings, plus flags for which values were filled in for you and which version of the assumptions produced them.
- Compare cities — the five city boxes, saved so the next visit restores the comparison.
- Theme choice — light or dark, saved when you press the theme button.
- Sign-in session — the access token, the refresh token and their expiry, plus a random lineage id and your user id once it is known. If browser storage is blocked, the session is held in memory only and disappears when the page closes.
- A one-time sign-in record — while a sign-in is in progress, a short-lived key holds the code verifier, the email address you typed and a timestamp. Records older than one hour are removed the next time a sign-in record is stored; that cleanup runs on activity, not on a clock, so a leftover record can outlive the hour if you never return.
- A sign-out marker — after sign-out, a small marker keyed to that session tells other open tabs to drop it.
Signing out clears the sign-in session while leaving your saved calculator numbers, compare cities and theme choice in place. You can clear this site's data in your browser settings. Reset clears the saved calculator profile and restores calculator defaults.
What this site's server sees
On a page load the page asks this site's own routes for market data (with your saved compare cities), housing evidence, news points, partner links, listing-search status and account configuration. When you search, the typed city or ZIP — or coordinates from the location button, rounded to two decimals before they leave the page — travels to the listing-search route together with your filters, and the typed place also travels to the property-tax route. Permission for location is only ever requested when you press that button.
The calculator math itself runs in your browser; the form is not submitted to a server to compute a scenario. Two routes do receive your numbers: the written read (described below) and the listing analysis, which sends the listing plus a subset of your figures — budget, down payment, monthly budget, rate, term, tax, insurance, HOA, maintenance and PMI. The stored row for a cached listing analysis keeps the answer, the comps and timestamps, not your buyer figures.
This code also writes a few operational lines to its own function log: analysis failures record a user id, a listing id and an attempt id. The log lines written by this code do not print your IP address. What the hosting platform records around those functions is outside this file and is listed as an open item below.
Email, sign-in and credit records
Sign-in uses your email address, sent from your browser directly to the account service as a one-time code request, or a sign-in provider when the account service offers one. This site's server never sees the code you type: it receives the token your browser already holds and reads back your id, your email address and the confirmation time. The account page then shows your id, email address, credit balance and admin flag.
Credits leave records in the database: ledger entries for the free grant and recorded charges and refunds, plus listing attempt lineage records. Every fresh listing analysis costs one credit. Exact cached rereads of a saved analysis stay free. Recorded paid attempts link the charge, any refund and the outcome, so a reversal is tied to its own charge. The one-time free grant is also recorded against a normalized form of your email address — lower-cased, with the +tag and Gmail dots removed — so it can be granted only once. How long the account service keeps your address, and what it logs, belongs to that service and is an open item below.
The written read: inputs, AI providers and stored replies
The written read is produced by third-party AI providers. Signed-in and signed-out written reads try free routes first: OpenRouter's free router or a model the operator pins, then Google Gemini's free tier, which may use the request to improve their models. They then try low-cost paid models through Vercel's AI Gateway, followed by OpenRouter's paid Auto Router. Hourly city reads try those paid Gateway models first, then the free routes, then OpenRouter's paid Auto Router. Routes without a configured credential are skipped. Which of them is live is an owner setting that the code cannot read from here, and each provider processes what it receives under its own policy.
What travels to a provider: the location text when it reads as a city or a ZIP, the timeline, the loan term, a price band instead of your exact price, a down-payment band instead of your exact amount, the names of the cost fields you left blank, scenario rows rounded to the nearest $500, the scenario basis and the public evidence items. What does not travel from this code: your email address, your user id and your IP address. The provider's key stays on the server as a request header.
A successful reply is stored server-side under a SHA-256 digest that includes the validated inputs and your account id when signed in, or an anonymous marker containing the forecast issue date when signed out. The account or anonymous marker is included in the digest; the persisted cache key does not contain your raw account id. The stored reply row holds the written read, its evidence list, the basis, the model name, the time and the disclaimer. It does not store your email address, raw IP address or raw financial form. The model's own prose can repeat the location you typed, so the stored reply may mention your city or ZIP. The same stored answer is reused for 24 hours; a cached listing analysis is reused for 30 days.
Written reads need a sign-in by default. Signed-out reads are optional and are switched off unless the operator enables them. For enabled signed-out reads, the IP-based budget identity stored in the database is a keyed HMAC-SHA-256 under a server secret, bucketed by IPv4 address or by IPv6 /64 network, with IPv4-mapped addresses folded into the IPv4 bucket. That anonymous budget is separate from the signed-in one; the stored answer and cache digest are described above.
IP addresses and the keys derived from them
The server derives a client IP address from request headers, with the connection address as a fallback. It uses that address for short-lived rate limits in the memory of a running function instance and to compute the durable keys described below. These database limit records store derived keys rather than the raw IP address. Function memory disappears when an instance is recycled; the hosting platform's own logging and retention still need owner review.
For signed-in written reads, the daily claim key is a namespaced SHA-256 digest of the verified account id (ai_user:v1:), stored with the claim time and a token. It has no IP address component: the same account keeps its daily allowance when its network changes, and separate accounts on one network have separate allowances. This digest is pseudonymous account data, not a secret. For the optional signed-out path, the IP-based budget identity uses the keyed HMAC and address buckets described above. The two paths keep separate keys and separate daily budgets. A claim stops limiting new reads after 24 hours; how long the row itself then survives is described next.
What is stored, and what actually gets deleted
- Cached answers — rows in the analysis cache hold cached listing analyses and stored written reads. A written read is reused for 24 hours; the purge function removes cache rows computed more than 30 days ago.
- Daily claims, paid-work claims and paid failures — the current purge function deletes those rows when they are more than 2 days old, in the same call as the cache cleanup.
- Attempt records — kept to link recorded charges, refunds and outcomes and prevent duplicate charges or refunds. They have no routine expiry purge.
- Credits, listing lineage, free grants and purchases — these records have no routine expiry purge. Refund-related operations can remove the affected listing unlock record.
Cleanup runs two ways. A scheduled job calls the purge function once a day. A cache write also calls it, and after a successful call a warm instance skips further calls for an hour. The purge function deletes exactly four things: cache rows computed more than 30 days ago, and paid-work claim, paid-failure and daily-claim rows more than 2 days old. It does not delete attempt records, credit ledger entries, listing unlocks, free grants or purchases. The 24-hour written-read reuse window and the 30-day listing-analysis cache window decide reuse; they do not delete a stored reply. A scheduled run that fails is retried the next day, so there is no fixed maximum age by which a row is deleted. The daily-claim cleanup depends on the latest purge migration having been applied to the live database, and whether it has been is unknown; the owner must confirm it. Daily-claim rows written by earlier code under an unsalted hash of an IP address are removed by a separate one-time migration that has not yet been applied; until then they follow the 2-day rule above. The scheduled job also depends on a cron secret being set in the live deployment, which the owner must confirm.
Other services named in the code
The site uses Vercel Web Analytics. It is cookieless and reports aggregated page views and a few anonymous interaction counts: form started, answer shown, poll answer and button clicks. No personal or financial details are sent in those events.
- Google Fonts — the page head loads the two web fonts from the Google Fonts stylesheet and its font host, so that request carries your IP address and browser user agent to Google as part of loading the fonts.
- ZillAPI, the listing data provider — the server sends a bounding box derived from the place you typed (the typed text itself is matched against a bundled index, not forwarded), the price, bed, bath and size filters, and a listing id when you analyse one home. The provider's key is a server-side header.
- U.S. Census Bureau — property-tax rates are requested with a geography code and the agency key, not with your typed text.
- FRED, the St. Louis Fed service — Freddie Mac rate series are fetched by the server with a service key.
- Public feeds — headline feeds from Realtor.com, Redfin, the U.S. Census Bureau and the Federal Reserve are read to build evidence and news points; no visitor data is part of those calls.
- Supabase — the database and the account service. Stripe — payments, which are switched off in production, so no purchase path runs on the live site today.
Each of those parties processes what reaches it under its own policy. Those policies, and the retention of everything outside this repository, are not readable from this source tree.
What the owner still needs to confirm
Before this page can be anything other than a draft, the owner must confirm each of these, because none of them is established by the tracked code:
- which AI provider keys are configured in the live deployment, and what those providers retain from a request;
- the account service's retention, backups and settings for your email address and sessions;
- the hosting platform's own request logging and retention, which sees IP addresses before this code does;
- the policies of the listing, census, feed and font services named above;
- whether every migration through the 2-day cleanup is applied to the production database;
- which partner links are live and which tracking parameters they carry;
- that payments stay switched off until the owner decides otherwise.
These privacy notes remain a draft until the owner confirms the open settings and retention questions and counsel reviews the final wording.