Zacznę od czegoś ważnego. Musisz wiedzieć, że Quality Score w Google Ads to przede wszystkim narzędzie diagnostyczne, a nie KPI sam w sobie. Google wprost mówi, że nie jest to bezpośredni czynnik w aukcji, ale jako ocena jakości reklamy w czasie rzeczywistym nadal bierze pod uwagę trzy obszary: oczekiwany CTR, trafność reklamy i landing page experience. Innymi słowy nie optymalizujesz „cyferki 1-10", ale jakość strony nadal realnie wpływa na wynik kampanii.
Jako developer masz bezpośredni wpływ na sporą część tego układu: szybkość ładowania, wygodę na urządzeniach mobilnych, message match, formularz, third-party scripts oraz to, czy po kliknięciu reklamy nie zgubisz gclid ani UTM-ów.
Co Google ocenia w Landing Page Experience?
Google nie publikuje dokładnego algorytmu, ale możemy dowiedzieć się sporo z ogólnych wskazówek, które znajdziemy w oficjalnej dokumentacji:
Użyteczność i trafność – treść strony musi faktycznie odpowiadać na to, czego użytkownik spodziewa się po reklamie i słowie kluczowym.
Łatwość nawigacji – użytkownik powinien móc łatwo znaleźć to, po co przyszedł, dlatego wszystko musi być poukładane i czytelne.
Zgodność z oczekiwaniami – reklama obiecuje jedno, a landing page powinien tę obietnicę spełnić, i dotyczy to nagłówka, oferty, ceny, CTA i całej narracji.
Przejrzystość i zaufanie – kontakt, polityka prywatności, podstawowe informacje o firmie, jasne warunki i brak podejrzanych wzorców.
Wygoda na mobile i szybkość – na urządzeniach mobilnych doświadczenie musi być szybkie, czytelne i stabilne, więc dochodzą tu jeszcze kwestie Core Web Vitals oraz praktyczny UX, czyli User Experience, opisuje całe doświadczenie użytkownika podczas korzystania z produktu..
Na sam koniec dochodzi techniczna higiena, więc działająca strona, ten sam kontekst domenowy co reklama, brak błędów 4xx/5xx, sensowna obsługa przekierowań i brak „martwych" wariantów LP.
Architektura landing page w Next.js
Static Generation – często najlepsza opcja
Jeśli landing page nie wymaga personalizacji w czasie rzeczywistym, SSG albo ISR będą zwykle najlepszym wyborem - oferują przewidywalny TTFB, czyli Time To First Byte, mierzy czas od żądania do otrzymania pierwszego bajtu odpowiedzi z serwera., łatwiejszy caching i mniej ruchomych części niż pełny SSR, czyli Server-Side Rendering, to generowanie HTML na serwerze przy żądaniu — komponent client:only je pomija i renderuje się wyłącznie w przeglądarce..
noindex ma sens tylko wtedy, gdy landing page jest naprawdę dedykowana kampanii, czyli ma warianty A/B, a zwłaszcza gdy duplikuje treść z innych URL-i (co jest bardzo szkodliwe dla SEO, czyli Search Engine Optimization, to optymalizacja strony pod widoczność w wynikach wyszukiwania.), jest krótką stroną stricte leadową albo nie chcesz, żeby konkurowała z główną ofertą w wynikach organicznych. Nie stosuj noindex jeśli LP jest wartościową, pełnoprawną stroną ofertową i ma dobrej jakości unikatową treść. Problemem nie jest sam fakt, że strona jest "reklamowa", ale czy wnosi coś wartościowego sama w sobie.
SSR nadal bywa uzasadniony, jeśli musisz pokazać dynamiczną cenę, stan magazynowy, lokalizację, język, zgodność prawną per kraj albo personalizację pod segment. Najistotniejsze nie jest to, żeby LP była „statyczna z zasady", tylko żeby była szybka, stabilna i przewidywalna.
Optymalizacja wydajności – checklist
LCP < 2.5s
Code
// 1. Hero image z priorityimport Image from "next/image";<Image src="/lp/hero-product.webp" alt="Produkt XYZ" width={1200} height={600} priority sizes="100vw" quality={85}/>;// 2. next/font obsługuje preload fontów automatycznieimport { Inter } from "next/font/google";const inter = Inter({ subsets: ["latin", "latin-ext"], display: "swap",});
Traktuj priority jak rozkaz dla przeglądarki, by skupiła wszystkie siły na jednym, kluczowym zasobie. Jeśli dasz ten sam rozkaz pięciu różnym elementom, wprowadzasz chaos i przeglądarka nie wie, który front jest najważniejszy.
CLS < 0.1
Code
// 1. Zawsze podawaj wymiary obrazków<Image width={400} height={300} ... />// 2. Zarezerwuj miejsce dla dynamicznych elementów<div className="min-h-[60px]"> {/* cookie banner space */} <CookieBanner /></div>// 3. Font display swap + size-adjustconst font = Inter({ subsets: ["latin"], display: "swap", adjustFontFallback: true, // Next.js automatycznie dopasuje fallback});
INP < 200ms
Code
// 1. Lazy load poniżej foldaimport dynamic from "next/dynamic";const Testimonials = dynamic(() => import("./Testimonials"), { loading: () => <div className="h-[400px]" />,});const FAQ = dynamic(() => import("./FAQ"), { loading: () => <div className="h-[300px]" />,});// 2. Nie wrzucaj ciężkiej pracy do handlera submit// ❌ Źleconst handleSubmit = async () => { const validated = heavyValidation(formData); // blokuje main thread await sendForm(validated);};// ✅ Dobrze — handler jest lekki, cięższa walidacja trafia na serwerconst handleSubmit = async () => { setLoading(true); await fetch("/api/leads/validate-and-send", { method: "POST", body: formData, }); setLoading(false);};
Samo async/await nie sprawia magicznie, że kod przestaje blokować główny wątek. Jeśli ciężka walidacja nadal wykonuje się synchronicznie w JS po stronie klienta, INP i tak na tym ucierpi. Jeśli naprawdę musisz robić ciężką pracę w przeglądarce, rozważ Web Workera.
Third-party scripts – nie zabijaj wydajności
Code
import Script from "next/script";// Tag pomiarowy, który musi wystartować wcześnie<Script src="https://www.googletagmanager.com/gtag/js?id=AW-XXX" strategy="afterInteractive" />// Widget supportowy, który może poczekać<Script src="https://widget.intercom.io/widget/xxx" strategy="lazyOnload" />
Nie wszystkie third-party możesz opóźniać tak samo stanowczo, ponieważ skrypt odpowiedzialny za pomiar i remarketing zwykle musi pojawić się wcześniej niż widget czatu, heatmapa czy recenzje. Tak więc, kolejność ładowania to część architektury konwersji.
Ten snippet jest dobry jako struktura, ale nie kopiuj ślepo samych "ładnych liczb", a social proof działa tylko wtedy, gdy jest prawdziwy i możliwy do obrony.
Message match – klucz do Quality Score
Message match to spójność między tekstem reklamy, a treścią landing page, dlatego jeśli reklama mówi "Tanie ubezpieczenie OC online", a LP ma headline "Kompleksowe rozwiązania ubezpieczeniowe" – message match jest generalnie do kitu.
Code
Reklama: "Kurs React dla początkujących – start w 7 dni"
↓
LP headline: "Naucz się React od zera w 7 dni" ← ✅ silny message match
LP headline: "Akademia programowania online" ← ❌ kiepski message match
W praktyce twórz oddzielne landing pages albo przynajmniej oddzielne warianty hero/message match per ad group, jeśli grupy słów kluczowych reprezentują różne intencje.
Trzymaj się zasady by zbierać tylko te dane, których naprawdę potrzebujesz na tym etapie lejka, ponieważ każde dodatkowe pole zniechęca część osób do wypełnienia formularza. Z drugiej strony zbyt krótki formularz potrafi obniżyć jakość leadów, dlatego optymalny punkt trzeba sprawdzić na własnych danych.
Do tego dochodzą rzeczy, których często brakuje w pierwszej wersji:
walidacja i sanityzacja po stronie serwera,
ochrona antyspamowa (honeypot, rate limit, captcha jeśli trzeba),
jasna informacja o polityce prywatności i zgodzie marketingowej, jeśli jest wymagana,
jeden główny CTA.
Atrybucja – zachowaj gclid i UTM-y
Landing page musi być dobry analitycznie. Klik z reklamy wpada z parametrami gclid, utm_source i utm_campaign, które warto zatrzymać przez całą sesję, żeby konwersja trafiła z pełnym kontekstem do Google Ads i CRM-a.
Wystarczą trzy nawyki, które razem łączą się w poprawną atrybucję:
zapisz gclid i kluczowe UTM-y w hidden fields formularza albo w storage pierwszej sesji, dzięki czemu przetrwają nawigację po stronie,
konwersję rejestruj po realnym sukcesie formularza, czyli po potwierdzeniu wysyłki, a nie po samym kliknięciu przycisku,
przy przekierowaniu na thank-you page przekaż parametry i dane sesji dalej, tak by atrybucja pozostała spójna na całej ścieżce.
Powyższy komponent AttributionFields działa skutecznie, jeśli formularz znajduje się na tej samej stronie, na którą trafia użytkownik. Jeśli jest wieloetapowy albo użytkownik może nawigować po stronie przed konwersją, poleganie wyłącznie na parametrach z bieżącego adresu URL jest prostą drogą do utraty atrybucji.
A/B Testing landing pages
Warianty URL
Najprostsze podejście to oddzielne strony dla każdego wariantu.
Code
/lp/kurs-react → wariant A (headline: "Naucz się React")
/lp/kurs-react-v2 → wariant B (headline: "Zostań React Developerem")
To działa, ale pamiętaj o dyscyplinie testowej i testuj jedną większą zmianę naraz. Nie mieszaj równocześnie headline'u, formularza, koloru CTA i układu sekcji, ponieważ potem nie wiesz, co naprawdę działa i ma znaczenie, a co nie.
Google Optimize replacement
Google Optimize został zamknięty w 2023, aktualne alternatywy: Optimizely, VWO lub buduj własny mechanizm z Next.js Middleware + cookies:
Maciej Sala — Product Manager i Frontend Developer z bogatym doświadczeniem w marketingu internetowym oraz SEO. Na co dzień pracuje z Reactem, Next.js i TypeScriptem, a ostatnio także z Astro i narzędziami do automatyzacji procesów AI. Sprawnie łączy perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat był związany z branżą gier wideo jako project manager i game designer. Absolwent historii na Uniwersytecie Jagiellońskim oraz studiów podyplomowych z marketingu internetowego na AGH w Krakowie. Po godzinach trenuje na siłowni, maluje figurki i rozwija własne projekty side-projecty.