Postmortem: We Put the Gate in the Wrong Place
TLDR
Our original paywall implementation tracked guest analysis runs inlocalStorage and overlayed a blurred canvas gate after 2 runs. This blocked users during exploration while leaving standalone export buttons completely ungated. We refactored the entire flow: deleting ~220 lines of complex run-counting and DOM-blurring code, and replacing it with a clean 2-file architecture (GxGate + GxAuth) that hooks export buttons across all client surfaces.
| Component Phase | Code base Footprint | Target Gate Location | Conversion Efficacy |
|---|---|---|---|
| Legacy Usage Gate | ~220 lines (GUEST_KEY, DOM overlays) | 3rd Analysis Run (Canvas blur) | Poor (High bounce rate) |
| Refactored Output Gate | ~60 lines (GxGate + GxAuth) | Export / Download Button | High (Captures high-intent users) |
Early paywalls block exploration while missing export triggers
Our legacy implementation tracked guest usage using a counter key in localStorage (GUEST_KEY). After two runs, _requestAnalysisPermission() intercepted the request, and _renderAnalyzePaywall() covered the canvas with a blurred gradient and sign-up prompt.
This architecture suffered from two major flaws:
- Interrupting exploration: Curiosity-driven evaluation triggered the paywall before the user derived clear value.
- Ungated exports: Users accessing tools directly on standalone pages could run analysis once and download the results freely without ever seeing a sign-in modal.
Deleting redundant usage counters reduces codebase footprint
Removing the legacy usage counter required stripping extensive tracking logic across multiple files:
Code removed from analyzePanel.js (~80 lines)
GUEST_KEY,GUEST_LIMIT_getGuestCount(),_incrementGuestCount(),_checkGuestLimit()_requestAnalysisPermission(),_renderAnalyzePaywall()- Associated blurred canvas CSS styling rules.
Code removed from os-shell.js (~140 lines)
ANALYZE_GUEST_KEY,ANALYZE_FREE_LIMITgx:request-analysispostMessage handlers_buildAuthModal()DOM construction routines- 13 redundant console log statements.
Decoupled modular architecture isolates gates from auth UIs
We replaced the legacy code with two focused, reusable modules in assets/js/:
GxGate(assets/js/ginexys-gate.js): A lightweight gate wrapper attached to export buttons that invokescheckAuth(). It handles the three-way environment resolution (VS Code extension host, OS shell iframe, standalone window).GxAuth(assets/js/ginexys-auth-modal.js): The extracted autonomous auth modal component. Self-injects intodocument.body, manages Google/GitHub OAuth, and emits standard custom events (gx:signed-in,gx:auth-modal-closed).
Legacy Monolithic Architecture:
[analyzePanel.js] ---> [os-shell.js] ---> [DOM Blur Overlay]
(Hardcoded GUEST_KEY) (~140 lines)
Decoupled Modular Architecture: [Export Click] ---> [GxGate (ginexys-gate.js)] ---> [GxAuth (ginexys-auth-modal.js)] (Environment Resolver) (Autonomous Modal) | v [gx:signed-in Event]
// Simplified Export Handler replacing 200+ lines of legacy guest counting
document.querySelector('#btn-export-pdf').addEventListener('click', async (e) => {
const auth = await GxGate.checkAuth();
if (auth.signedIn) {
executeExportPipeline();
}
});
Rule of thumb: Gate at the moment of value extraction, not during exploration. If an architectural refactor allows you to delete 200 lines of complex state-tracking code in favor of a clean event hook, do it immediately.