The live funnel for lorenzosegor.com. Three pages, three files, served straight
off this repository by GitHub Pages. A push to main is a deploy: the live
pages pick it up in about a minute and there is nothing to re-paste.
funnel.js the quiz, the sales page and the £99 checkout with its two bumps
thanks.js the booking page, "You're In"
upsell.js The Buyer, the £199 one click upsell
One Custom Code element per page, and nothing else on the page. The exact
snippets are in ghl/. Do not retype them; copy the file.
| Page | Snippet | Mount | Paper |
|---|---|---|---|
| Sales | ghl/sales-page.html |
rz-mount |
#EFECE4 |
| Booking | ghl/booking-page.html |
rz-thanks-mount |
#F4F1EA |
| Upsell | ghl/upsell-page.html |
rz-upsell-mount |
#F4F1EA |
The builder’s own elements stay where they are. The sales page keeps its one step order form, the booking page keeps its calendar, the upsell page keeps its order form and its skip link. The funnel paints around all of them and drives them; it never replaces them.
The upsell page also needs GoHighLevel’s own buy button and skip link given the
custom classes rz-buy and rz-skip. The page hides them and clicks them from
its own buttons, because a one click charge has to be the builder’s element.
funnel.js the built file GitHub Pages serves. never edit by hand
src/funnel/page.css its stylesheet
src/funnel/page.html its markup
src/funnel/loader.js everything else, with a marker where each of those two go
and the same for thanks and upsell.
node tools/build.mjs --check does src/ still rebuild the built files,
byte for byte? this is the check that
matters, and it should always be green
node tools/build.mjs src/ -> the three built files
node tools/extract.mjs the three built files -> src/
node tools/preview.mjs src/ -> preview/, three pages you can open
Edit src/, then node tools/build.mjs, then commit both.
If you ever edit a built file directly, run node tools/extract.mjs straight
afterwards to pull the change back into src/, and check --check is green
before you commit. A drift between the two is how the source gets lost.
node tools/preview.mjs
then open preview/index.html, or run the renz preview server and browse to
it. Each preview is a bare document carrying the real paste snippet pointed at
the built file next door. Nothing is stubbed: the loader finds no builder app,
so it paints straight into the mount and settles, which is the path it already
takes on any page with no checkout on it.
So the preview is honest about the copy, the layout, the quiz, the scroll work and the whole sales page. It cannot be honest about the order form, the bumps or the money, because there is no checkout in it. Test those on the live page.
GoHighLevel pages are a server rendered Vue app, and the div the snippet paints into is part of the markup that app is about to take ownership of. Write into it before the app has hydrated and the hand over fails. What dies is the order form: no total, no card field, no way to pay, and not one line in the console to say so. It just quietly stops taking money.
So the funnel paints at once into a sheet of its own laid over the page, which
is what the quiz looks like anyway, and only moves into the page once the
checkout has actually drawn itself. Measured on the live pages: the order node
is present at 20 to 45ms, __nuxt.__vue_app__ at 870ms to 2.4s, the checkout
alive at 2.3 to 4.2s. The budget is 30s on a page with a checkout, because there
is nothing to lose by waiting while the man can already use the funnel.
Two things follow from that, and both have broken this page before:
window.__rzWhenSettled(fn) has fired.order form #one-step-order-DE0P7Us6ET (sales)
#one-step-order-U3AtvyuBgg (upsell)
calendar RYS7dx7Mc0qtjARUFxLP
Wistia wai638s3ie sales page film PLACEHOLDER
7ehs06hu2p booking page film PLACEHOLDER
The two Wistia ids are placeholders and currently point at real, unrelated footage. They must be replaced before this takes a real buyer.
node tools/serve.mjs 8777 & a server that answers Range, so video seeks
node tools/preview.mjs
node audit/all.mjs everything below, in one go
| What it asks | File |
|---|---|
does src/ still rebuild the built files byte for byte |
tools/build.mjs --check |
| is every id the code reaches for actually in the markup | audit/ids.mjs |
| does any rule reach two different kinds of element sharing a class, and does any selector match nothing | audit/selectors.mjs |
| anything wider than the window, past a readable measure, under a 44px touch area, or clipped | audit/layout.mjs |
| anything holding text that is never once on screen | audit/invisible.mjs |
| two lines saying the same thing in front of the same man | audit/repeats.mjs |
| every kind of man through the page: no placeholder, no undefined, and the lines that are his actually change | audit/persona.mjs |
| how it looks, a screen at a time | audit/slices.mjs then tools/montage.mjs |
Three of those exist because this page has actually shipped the fault they look for: a rule written for an image that reached a div and inverted it, a reveal whose observer could never fire, and a personalisation that silently stopped.
The one check that cannot run locally is the money. The checkout only exists on the real host, so after a push has gone out:
node audit/stress.mjs 7 390 844
node audit/stress.mjs 7 1440 900
which seeds a man, lands him on the live page, brings the checkout on screen and asks whether his name and email are in it, whether it says £99.00, whether Stripe drew, whether either bump arrived ticked, and whether anything scrolled sideways. Seven runs, because the faults that matter here are the intermittent ones.
The research, the ten call transcripts, the market report and the test harness
are not in this repository, because this repository is public. They live in
~/Documents/Renz. So does the one document that explains how the closet score
is scored, which stops working the moment it is somewhere a visitor can read it.
So do the three pages as they were originally authored, recovered from the
published artifacts and kept for history: ~/Documents/Renz/archive.