Change Log
Here are all the changes we made to TypoGuard Chrome extension
TypoGuard – Changelog
=====================
[v2.1.1] – 2026-08-20
———————-
BUG FIXES
– The “Did you mean?” suggestion tooltip could get stuck covering text the user was
still typing/reading. Two causes fixed in content.js’s showTooltip():
1. The tooltip is a solid, max-z-index box that always anchored below the
misspelled word whenever there was viewport room — on a long draft with many
wrapped lines that’s almost always true, so it routinely covered the following
lines of the same paragraph. Now defaults to anchoring above the word, falling
back to below only when there isn’t room above.
2. Clicking the tooltip’s own blank area (padding, header, footer — not an
actual suggestion) previously did nothing, leaving it stuck open until the
mouse moved far enough away to trigger the hover-out timer. Any such click now
dismisses the tooltip immediately.
[v2.1.0] – 2026-08-14
———————-
NEW
– Options page redesign: coral/cream “Chat Manager” visual style replacing the old
blue/white layout (full options.html/options.css rewrite). All existing element
IDs preserved so options.js’s storage sync, license activation, and usage logic
kept working unmodified.
– Added a color theme picker (Default / Blue / Dark), persisted to
chrome.storage.local (tg_color_theme), applied via [data-theme] on, with
an inline pre-paint script to avoid a flash of the default theme on load.
– Added a reusable “Upgrade to Pro” modal, opened from the sticky bottom action bar
and the legacy hidden #upgradeBtn. The pricing-tile buttons still go straight to
Lemon Squeezy checkout, no modal, since the user already picked a plan. The
modal’s CTA reuses the existing goToCheckout() helper (uid + tracking), not a
bare window.open().
– Per-site toggle rows re-templated to the new toggle-row style; kept the existing
data-domain attribute so the save handler’s storage sync logic didn’t break.
– Added a small CSS compatibility layer (–primary-color/–success-color/
–error-color/–text-secondary aliases per theme) so options.js’s existing
inline-styled feedback messages keep their color coding.
[v2.0.20] – 2026-08-02
———————-
NEW
– Rewrote the Greek Variant B paywall copy — the old text was a literal translation
and read awkwardly. New copy in UPSELL_VARIANTS.B.el (content.js, used by
showLimitBanner): title “Εξάντλησες τις 100 δωρεάν διορθώσεις σου”, body “Οι
διορθώσεις σου σταματούν μέχρι τον επόμενο μήνα…”, primary “Απόκτησε Premium”,
secondary “Καλύτερη τιμή: $49.99/έτος (−40%)”. English copy untouched.
– background.js’s OS “Limit Reached” notification was English-only. Added the same
locale detection as content.js (navigator.language -> Greek when the browser
locale is Greek) with matching Greek copy, so the notification and the in-page
banner now agree in both languages. Same checkout links and tracking as before.
[v2.0.19] – 2026-08-02
———————-
BUG FIXES
– The top-right “Monthly free corrections limit reached… Open Options” bar was a
second, older notice (__showLimitNoticeOnce -> __showPlanNotice in content.js),
completely separate from the real Variant B paywall (showLimitBanner). It fired
from the client-side pre-flight quota check (3 call sites) and never carried the
real copy, checkout links, or paywall_shown/upgrade_clicked/checkout_reached
tracking. All 3 call sites now go through showLimitBanner() via the same
12h-throttled wrapper (frequency across page loads unchanged). __showPlanNotice
itself is kept for the unrelated “AI service is busy (rate limit)” notice.
– background.js’s OS-level “Limit Reached” notification had stale “50 free
corrections” copy (real limit is 100) and no working upgrade path (click just
opened the options page).
NEW
– background.js notifications (“Limit Reached” and the periodic “Enjoying
TypoGuard?” reminder) rewritten with the Variant B offer framing, plus
Monthly/Annual buttons that open the real Lemon Squeezy checkout links
directly (uid attached) and fire upgrade_clicked/checkout_reached with plan.
[v2.0.18] – 2026-08-02
———————-
BUG FIXES
– Worker /event was silently dropping where/message on pipeline_error beacons —
only uid/event/ts/src/variant were ever written to KV. Now persisted so error
detail actually survives.
NEW
– Real Lemon Squeezy checkout URLs wired in: monthly ($6.99/mo) and annual
($49.99/yr), replacing the placeholder that pointed both paywall buttons (and
the Premium Plans cards / quick Upgrade button in options.js) at the same
monthly link. uid still attached via checkout[custom][uid].
– checkout_reached now fires for both primary (monthly) and secondary (annual)
paywall actions in content.js (previously only options.js fired it), and
upgrade_clicked/checkout_reached now carry plan: “monthly” | “annual” so
monthly-vs-annual conversion can be measured.
– Added GET /stats/errors?token= — total pipeline_error count plus
the last ~50 events (uid, where, message, timestamp), same STATS_TOKEN auth
as /stats/funnel.
[v2.0.17] – 2026-08-02
———————-
NEW
– Proxy: added a console.log(“TOKENS”, …) debug line right after the inputTokens/
outputTokens calculation in callGemini(), logging input/output/thoughts/candidates
token counts per request (visible via wrangler tail) to help verify the v2.0.16 cost fix.
[v2.0.16] – 2026-08-02
———————-
BUG FIXES
– Real Cost / analytics logging only counted candidatesTokenCount as output tokens —
thoughtsTokenCount (billed reasoning tokens from Gemini) was silently missing from
every cost calculation. outputTokens now sums candidatesTokenCount + thoughtsTokenCount.
NEW
– Proxy: disabled Gemini “thinking” mode via generationConfig.thinkingConfig.thinkingBudget
= 0. Model stays gemini-2.5-flash — no reasoning tokens spent on a plain spell-check.
– Options page header now reads its version from chrome.runtime.getManifest() instead of
a hardcoded string, so it can’t drift out of sync with manifest.json again.
[v2.0.15] – 2026-08-01
———————-
BUG FIXES
– chrome.identity.getProfileUserInfo() had no timeout in getDeviceUUID() — on
machines where the callback stalls (seen mostly on Windows, likely tied to
managed/enterprise Chrome sign-in policies), every correction request would
hang instead of falling back to a stored/random UUID. Now races a 3s timeout.
– Correction pipeline (highlightErrors, applyCorrection, applyCorrectionOverlay,
applyOverlayCorrectionByIndex, checkText’s response handler) is now wrapped in
try/catch end-to-end, so one bad DOM/Range op can no longer strand
lastCheckedText and silently stop future checks on a field. Failures are
logged to console and beaconed to the Worker as a pipeline_error event.
– FREE_LIMIT constant in background.js was stale at 50 (everywhere else uses 100).
NEW
– Paywall (100-limit) upsell rewritten as Variant B: English by default, Greek
when the browser locale is Greek — previously hardcoded to Greek for everyone.
Primary button opens the monthly checkout, secondary link opens the annual
checkout, both with uid attached.
– A/B variant infrastructure: pickVariant(uid) (returns “B” only for now, real
50/50 split commented in for later) and a variant config object. paywall_shown
and upgrade_clicked funnel events now carry a variant field through to the
Worker and KV storage, so a future A/B test can be measured.
[v2.0.14] – 2026-07-22
———————-
[v2.0.8] – 2026-05-06
———————-
BUG FIXES
– Removed unnecessary `tabs` permission from manifest — chrome.tabs.create()
does not require it. Fixes Chrome Web Store policy violation (Purple Potassium).
NEW
– Added “Disable Browser Spell Check” toggle in Settings — turns off Chrome’s
built-in red underlines on monitored fields so only TypoGuard highlights appear.
[v2.0.7] – 2026-04-28
———————-
BUG FIXES
– License key now persists correctly after extension reinstall: activation flow
now validates the existing instance first (zero slot consumption) before
attempting a fresh activation. If the stored instance is stale, the old slot
is deactivated automatically before re-activating — so users with Limit: 1
keys are never locked out after reinstall on the same Chrome profile.
[v2.0.6] – 2026-04-23
———————-
IMPROVEMENTS
– Welcome page (typoguard.vip/welcome) opens automatically on first install
for onboarding and marketing pixel tracking.
NEW
– Added `tabs` permission to support opening welcome tab on install.
[v2.0.5] – 2026-04-11
———————-
IMPROVEMENTS
– WordPress Classic Editor (TinyMCE Visual mode) now fully supported: spell
check highlights appear as red wavy underlines directly in the editor,
clicking a word shows the correction tooltip, and applying a correction
works in-place without page reload.
– Monthly corrections counter now persists across extension reinstalls —
identity.email permission used to derive a stable anonymous device UUID
(SHA-256 hash of Chrome account email, never stored or transmitted).
BUG FIXES
– Fixed: correcting one highlighted word caused all other highlights to flash
(disappear and reappear) — re-highlight after correction now skips the
remove+redraw cycle since remaining spans are already in the DOM.
– Fixed: correction tooltip position was wrong for elements inside iframes
(TinyMCE) — getBoundingClientRect() coords are now offset by the iframe’s
own position in the parent page.
– Fixed: device UUID reset on every reinstall because chrome.identity only
returns account data with the identity.email permission (not plain identity).
[v2.0.4] – 2026-04-09
———————-
IMPROVEMENTS
– Device UUID now tied to Chrome account identity (hashed email) so the free
corrections limit persists across extension reinstalls. Falls back to stored
UUID if Chrome account is unavailable.
– Greek accent marks (τόνοι) now detected as spelling errors — Gemini prompt
updated with explicit rule to treat missing accents as misspellings.
– Removed minimum text length restriction — single words and short phrases are
now spell-checked.
– Paste into a text field now immediately triggers a spell check (was already
wired but confirmed working).
BUG FIXES
– Fixed: when text changed during an API call the result was silently dropped;
now re-triggers a check automatically after 300ms.
– Fixed: Gmail AI smart-compose suggestion (“Tab to improve, Esc to dismiss”)
was being sent to the spell checker — now filtered out.
– Fixed: Cloudflare Worker analytics (agg: keys) were never written to KV
because fire-and-forget Promise.all was terminated before completion;
replaced with ctx.waitUntil() to keep the Worker alive for background writes.
– Fixed: Google Sheets importStats script failed silently from daily trigger
because SpreadsheetApp.getUi().alert() throws when there is no UI context.
– Fixed: STATS_TOKEN secret was not set in Cloudflare Worker causing all
/stats requests to return unauthorized.
[v2.0.3] – 2026-04-07
———————-
IMPROVEMENTS
– Split Gemini API keys: free users and premium users now use separate API keys
(GEMINI_API_KEY_FREE / GEMINI_API_KEY_PREMIUM) for better abuse control.
– Badge now stays in sync when the options page syncs usage from the backend
(previously could show a stale count).
– Renamed “Words Corrected” stat label to “Corrections Applied” for clarity.
– “Monthly free corrections limit reached” popup now shows at most once every
12 hours (twice a day max) instead of on every keystroke after limit is hit.
– Gmail MutationObserver: detects when Angular re-renders wipe injected error
spans during long idle sessions and automatically restores highlights from
cache — making Gmail as resilient as the overlay-based sites (Gemini, ChatGPT).
BUG FIXES
– Fixed stale Chrome toolbar badge count after options page syncs usage.
[v2.0.2] – 2026-03-XX
———————-
IMPROVEMENTS
– Proxy-based architecture: all Gemini API calls go through a Cloudflare Worker
backend; no user API key required.
– deviceUUID now saved to both chrome.storage.local AND chrome.storage.sync so
the free corrections counter survives extension reinstall.
– MV3 service worker keep-alive: 25-second ping prevents SW sleep causing silent
spell check failures after page idle.
– Focus + visibilitychange listeners reset lastCheckedText so the same text gets
re-checked after returning to a tab or field.
– Undefined response retry: if the service worker is still waking up, the check
retries automatically after 1 second.
– Reduced limit_reached pause from 24 hours to 30 minutes so the addon stays
active across long sessions.
– Added diagnostic logging when checks are skipped due to an active pause.
BUG FIXES
– Fixed Gmail multi-paragraph highlight loss: removeHighlights now scoped to the
current paragraph (scopeNode) instead of the entire compose body.
– Fixed corrections wiping all highlights in the same paragraph: highlightErrors
now defines the container before calling removeHighlights, so only the correct
scope is cleared.
– Fixed deviceUUID lost on extension reinstall (now restored from sync storage).
– Manifest: changed to https://*/* and removed all_frames:true to
reduce permission footprint for Chrome Web Store review.
[v2.0.1] – 2026-02-XX
———————-
– Initial proxy-based release replacing direct Gemini API key model.
– Support for Gmail, Gemini, ChatGPT, Claude, Facebook, Airbnb, Booking.com.
– Overlay (shadow DOM) approach for React/SPA sites to survive re-renders.
– Scope-based direct DOM injection for Gmail.
– Free plan: 50 corrections/month tracked server-side via Cloudflare KV.
– Premium plan: license key validation via LemonSqueezy.
– Per-site enable/disable toggles in options.
– Compat mode toggles for ChatGPT, Gemini, Claude.
[v2.0.0] – 2026-02-XX
———————-
– Bug Fixes
– Major Upadete to API Usage Method
– Added: api usage stats
v1.0.1 – 2026-02-XX
————————
– Bug Fixes
– Improved: spell checking speed
v1.0.0 – 2026-02-XX
————————
– Initial Release
