Portfolio demo ยท Landing page build and analytics
A landing page built to be measured, not just looked at.
Northfold is a fictional brand strategy studio. I wrote a brief for it, then planned, built and instrumented a single landing page whose only job is to get qualified founders to book a 20-minute call. This page explains the decisions behind it.
1. The brief I set
The visitor is a founder of a 2โ50 person business who suspects their brand is muddled, usually because something forces the issue: a website rebuild, a raise or a new offer. They arrive from a referral or a LinkedIn post, mostly on a phone, and they are deciding one thing: is this worth 20 minutes of my time?
So the page has one conversion: a fit-call request. Everything else either moves the visitor toward it or helps them rule themselves out.
2. Page logic: one question per section
Each section answers the question a visitor would have at that point in the scroll. If a section can't name its question, it gets cut.
| Section | Visitor's question | What the design does |
|---|---|---|
| Hero | What is this, and is it for me? | Outcome headline, price and duration in the first screen, one primary button. The sample deliverable shows the product instead of describing it. |
| Sound familiar? | Do they understand my problem? | Three symptoms written in the founder's language, not the studio's. |
| How it works | What actually happens, and how much of my time? | A day-by-day timeline where each stage ends in a named deliverable. |
| Is this for you? | Am I the right fit? | An explicit "not for you if" column. It trades a few clicks for better-qualified calls. |
| Pricing | What does it cost, and what's the risk? | One published price, a list of what's included and a stop-at-day-five guarantee. |
| FAQ | What's left that stops me? | Five objections from the brief, each answered in two sentences. |
| Book | How do I start? | Four fields, one optional. The copy says what happens next and how fast. |
3. Conversion decisions
- One goal, repeated where intent peaks. The same action appears in the header, the hero, after the process, on the price card and at the end, so a convinced visitor never has to scroll back.
- A sticky button on phones only. It appears once the hero has scrolled away and hides again when the form is on screen, so it never covers the form.
- The price is shown. A strategy studio that hides its price gets calls from people who can't afford it. Publishing it moves that filter onto the page.
- Inline validation that doesn't scold. Errors appear on submit, clear as soon as the field is fixed and move focus to the first problem. Every failure is tracked, so a confusing field shows up in the data.
- No fake social proof. The studio is fictional, so instead of invented testimonials the hero shows a sample of the work. On a real build this is where client logos or a named quote would go.
4. Tracking plan
Every event is pushed to window.dataLayer, so it works with Google Tag Manager as-is. Add a GA4 measurement ID to the page and the same events go to GA4 directly. Event names follow GA4's recommended naming where one exists (generate_lead).
| Event | Fires when | Parameters | Answers |
|---|---|---|---|
cta_click | Any "Book" button is clicked | location, cta_text | Which placement actually drives people to the form? |
section_view | A section is at least half visible, once per visit | section | Where do people stop reading? |
scroll_depth | 25, 50, 75 and 90% of the page | percent | Is the page too long for the people who arrive? |
faq_open | A question is expanded | question | Which objections need to move higher up the page? |
form_start | First focus inside the form | form | How many start the form but don't finish? |
form_error | A field fails validation on submit | form, field | Which field is costing us leads? |
generate_lead | The form is submitted successfully | form, reason | The conversion, broken down by why they came |
How to check it yourself
- Open the page with
?debug=1. An inspector lists each event the moment it fires. - Scroll, open a FAQ, click a button, then submit the form empty and filled in. You should see
form_errorfor each missing field, then onegenerate_lead. - On a live client build, the same check is done in GA4 DebugView or GTM Preview, and the conversion is marked as a key event before handover.
5. Speed and accessibility
- Small by default. One stylesheet, two small scripts loaded with
defer, no images in the critical path, and one display font withfont-display: swap. - Mobile first. Styles start at phone width and add columns at 720 px and 1000 px. Tap targets are at least 40 px tall and form fields 50 px.
- Accessible by structure. Real headings and landmarks, a skip link, labelled fields, errors tied to their inputs, visible focus rings and reduced motion respected.
- 43 KBfor the page's own files, compressed, fonts included
- 6requests for the page itself
- 0cookies set
- 0.00cumulative layout shift
Measured in Chromium at phone width. Fonts are self-hosted (SIL Open Font License), so there's no Google Fonts request. The host adds Cloudflare Web Analytics, a cookie-free page-view counter of about 10 KB. Event tracking stays in the page's own dataLayer until GA4 is switched on.
6. On a real project
This demo is hand-coded so every decision is visible. For a client I build on whichever platform their team will maintain, such as Webflow, Framer, WordPress or plain static hosting, and keep the same structure and tracking plan.
Before quoting I'd confirm:
- how many pages, and whether copy and designs are final
- which platform you build on and who maintains the site afterwards
- the one action each page should drive, and where leads should go (inbox, CRM, booking tool)
- which analytics stack you use, and any consent or privacy requirements
I use AI tools to speed up drafting and testing. I review every section by hand and check behaviour on phone and desktop before handover.