Przejdź do treści

Audyt techniczny SEO i wydajności Inspektomat.pl — problemy, priorytety i wdrożenia

Maciej Sala

Founder StriveLab

17 min czytaniaAktualizacja

Szybka odpowiedź: co wykazał audyt techniczny SEO i wydajności Inspektomat.pl?

  • Problemem była wydajność na telefonie, ponieważ kategorie SEO, Ułatwienia dostępu i Sprawdzone metody miały po 100 punktów na obu urządzeniach.
  • Największy koszt generował prefetch tras, których użytkownik nie wybrał: 45 żądań i ok. 444 KiB, czyli prawie jedna trzecia transferu.
  • Główny obraz (hero), czyli element LCP, pobierał się w pełnym rozmiarze, bo przy images.unoptimized: true komponent next/image nie generuje srcset.
  • Mapa ładowana bez przewinięcia dokładała ok. 291 KiB kafelków przy wejściu, ale HAR wykazał, że nie opóźniała pobrania głównego obrazu, więc ostatecznie dostała średni priorytet.
  • Po dwóch etapach wdrożeń transfer strony głównej spadł o 65%, a wynik mobilny wzrósł z 66 do 94 punktów. Pozostały LCP 2,85 s ogranicza przepustowość: obraz dzieli łącze z prawie 400 KiB JavaScriptu, fontów i CSS.

Inspektomat.pl: serwis w Next.js i zakres audytu

Inspektomat.pl to ogólnopolski katalog firm wykonujących przeglądy instalacji i budynków, w którym użytkownik wybiera miasto i usługę, przechodzi do ofert lub zapoznaje się z rozbudowanym poradnikiem. Strona główna witryny łączy więc treść informacyjną z elementami interaktywnymi, czyli selektorem usług, kartami, mapą oraz FAQ. Sam projekt został oparty na Next.js i jest eksportowany do statycznego HTML. Treść jest w związku z tym gotowa przed wizytą użytkownika i robota, więc jest to dobra podstawa pod , ale to oczywiście nie przesądza o tym, ile pracy przeglądarka wykona po wejściu na stronę: obrazy, style i skrypty nadal trzeba pobrać, a komponenty uruchomić.

Strona główna Inspektomat.pl: menu usług, główny obraz z wyszukiwarką miasta i karty rozwiązań dla typów nieruchomości

Strona główna Inspektomat.pl na komputerze. Główny obraz z wyszukiwarką miasta to element LCP, a karty rozwiązań prowadzą do podstron, które wcześniej pobierały się z wyprzedzeniem.

Ogólny zakres takiego audytu opisuję w artykule co obejmuje audyt techniczny SEO. W tym przypadku audyt opierał się na pięciu źródłach:

  1. PageSpeed Insights z 23 i 26 października 2026 r. — wynik produkcyjny przed zmianami i po każdym z dwóch etapów wdrożeń,
  2. — dane rzeczywistych użytkowników (w tym przypadku na poziomie całej domeny),
  3. nagrania HAR przed zmianami i po nich — pełna lista żądań z czasami i inicjatorami,
  4. przegląd kodu — żeby wyjaśnić, dlaczego zasoby pobierają się tak, jak pokazuje HAR,
  5. lokalne pomiary Lighthouse przed zmianami i po nich, plus testy funkcjonalne.
Diagram
Przebieg audytu: pomiar, diagnoza, dwa etapy wdrożeń z pomiarem po każdym z nich i diagnoza pozostałego LCP.

Audyt SEO: indeksacja bez zastrzeżeń, problemem wydajność mobilna

Kategorie SEO, Ułatwienia dostępu i Sprawdzone metody w PageSpeed Insights wykazały po 100 punktów zarówno na komputerach, jak i na telefonach, czyli automatyczny audyt nie wskazał problemów z indeksowalnością ani podstawowymi elementami strony.

Technicznie istotne dla widoczności okazały się trzy rzeczy:

  1. Doświadczenie na telefonie. Google indeksuje strony w wersji mobilnej, a są częścią sygnałów jakości strony (page experience). Rozjazd między 99 a 66 punktami i 6,9 s w teście mobilnym to główny problem, na który wskazywał audyt.
  2. Treść musi zostać w HTML. Każda zmiana wydajnościowa, czy to przeniesienie układu do CSS, leniwe ładowanie, czy wydzielenie FAQ, była sprawdzana pod kątem tego, czy pełna treść nadal trafia do statycznego HTML. Innymi słowy, nie chowałem niczego za JavaScriptem.
  3. Interpretacja danych terenowych. CrUX pokazywał dobre terenowe LCP i podwyższony na telefonach (p75 0,11 przy progu 0,1, a na komputerach 0,02), ale dla całej domeny, a nie dla strony głównej. Dobre wyniki LCP z danych terenowych nie unieważniają testów laboratoryjnych, a z kolei wysoki CLS nie oznacza automatycznie, że jego źródłem jest strona główna. Obie te sprawy wymagają dodatkowej weryfikacji.

Diagnoza wydajności: PageSpeed Insights, HAR i element LCP

Raport PSI wskazywał za duże obrazy, nieużywany JavaScript, CSS blokujący renderowanie i słaby cache. Nie było na tym etapie jasne, który element faktycznie opóźnia stronę, ale wiedziałem, w jakich obszarach szukać. Dalsza weryfikacja w przeglądarce potwierdziła, że elementem LCP na stronie głównej był główny obraz (hero image), natomiast analiza pliku HAR ujawniła szczegółową strukturę pobrań zasobów:

  • 78 żądań, łącznie około 1,41 MiB transferu,
  • JavaScript — niemal 66% tego transferu,
  • 45 żądań (ok. 444 KiB, prawie 31% transferu) powiązanych z prefetchem innych podstron,
  • 6 kafelków mapy (ok. 291 KiB) plus kod Leaflet i jego arkusz stylów.

Dzięki analizie pliku HAR odrzuciłem zbyt prostą hipotezę: skoro główny obraz kończył pobieranie po ok. 822 ms od startu nawigacji, a kafelki mapy startowały dopiero po ok. 1,45 s, mapa nie opóźniała ładowania elementu LCP w tej sesji, chociaż generowała dodatkowy koszt podczas początkowego ładowania. Z uwagi na to, że plik HAR nie rejestruje momentu renderowania elementów ani obciążenia procesora, dane te zestawiłem z analizą kodu oraz pomiarami Lighthouse, zamiast opierać wnioski wyłącznie na czasach transferu zasobów.

Problemy z wydajnością i kolejność poprawek

Kolejność prac ustaliłem na podstawie dwóch rzeczy: jak duży koszt dany problem generował w pomiarach i czy dotyczył bezpośrednio pierwszego widoku na telefonie.

ProblemDowódWpływPriorytet
Prefetch tras, których użytkownik nie wybrałHAR: 45 żądań, ~444 KiB, ~31% transferuTransfer i praca JS przy wejściuWysoki
Główny obraz bez wariantów srcsetKod + HTML z HAR: brak srcset dla 4 obrazówElement LCP pobierany w pełnym rozmiarzeWysoki
Mapa ładowana niezależnie od przewinięciaHAR: 6 kafelków ~291 KiB + LeafletTransfer przy wejściuŚredni
Przełączanie układu z desktopowego na mobilny przez JSPrzegląd kodu kart i FAQDodatkowy render, ryzyko przesunięćŚredni
Import pełnej bazy FAQ na stronie głównejPrzegląd koduRozmiar paczki JSNiski
Google Analytics ładowane wcześniePrzegląd koduPraca JS na starcieNiski
Jednodniowy cache wersjonowanych zasobówHAR: krótki cache z rewalidacjąKolejne wizytyNiski (dla pierwszego ładowania)

Wdrożenie 1: ograniczenie prefetchu w Next.js

Ograniczenie automatycznego prefetchu dla kart podstron oraz linku do bloga w nawigacji to nie wszystko — dalsze pomiary wykazały, że zasoby nadal pobierały się m.in. dla linku do polityki prywatności w banerze zgód czy przycisków „Dodaj swoją firmę”. Dopiero powiązanie pobranych fragmentów z manifestem paczek JavaScriptu pozwoliło precyzyjnie przypisać je do konkretnych tras i objąć optymalizacją.

Prefetchu nie wyłączyłem w całym projekcie, lecz wyłącznie tam, gdzie pomiary potwierdziły realny koszt podczas wejścia (linki działają bez zmian). To doskonały przykład tego, dlaczego ostrzeżenie o „nieużywanym JavaScripcie” bywa mylące: kod wcale nie był zbędny w serwisie, lecz po prostu pobierał się przedwcześnie.

Na tym prefetch się nie skończył. Nagranie HAR wykonane trzy dni po pierwszym wdrożeniu pokazało, że stare trasy zniknęły, ale pojawiła się nowa grupa: 36 żądań i ok. 225 KiB dla sześciu stron usług elektrycznych. Nowego kodu nie było — po uproszczeniu animacji (Wdrożenie 4) sekcja z linkami w opisie usług elektrycznych przesunęła się do pierwszego widoku, a Next.js pobiera z wyprzedzeniem strony dla widocznych linków. W drugim etapie wyłączyłem prefetch dla wszystkich 16 linków w opisach usług na stronie głównej. W kolejnym nagraniu prefetch to już jedno żądanie o wadze 0,5 KiB.

Wdrożenie 2: srcset, WebP i AVIF przy eksporcie statycznym Next.js

W konfiguracji Next.js ustawione było images.unoptimized: true, co jest zgodne z eksportem statycznym, ale w tej konfiguracji komponent next/image nie generuje zestawu srcset, a samo podanie sizes niczego nie zmienia. W rezultacie zdjęcie wyglądało poprawnie na telefonie, ale przeglądarka pobierała plik przygotowany dla większego ekranu, więc nie było to optymalne rozwiązanie. Dodałem generowanie wariantów przed kompilacją, używając skryptu opartego na Sharp — przygotowuje mniejsze pliki i zapisuje ich adresy w manifeście, a strona serwuje je przez <picture> i srcset.

Wprowadzone zmiany:

  • Zdjęcia w kartach dostały rozmiary WebP, a główny obraz dodatkowo AVIF i osobny kadr mobilny.

  • Oryginalny główny obraz ważył ok. 91 KiB, a mobilny kadr 768 px waży ok. 48 KiB w WebP i 28 KiB w AVIF.

  • Preload głównego obrazu używa tych samych wariantów i warunków media co właściwy obraz, więc przeglądarka nie pobiera równolegle wersji mobilnej i desktopowej.

  • Przeglądarki bez AVIF dostają WebP, a obrazy poniżej pierwszego widoku zachowały leniwe ładowanie.

Telefony nie zawsze pobierają wariant 768 px — przy ekranach o wyższej gęstości pikseli przeglądarka może wybrać większą grafikę. Emulowany Moto G Power, którego używa Lighthouse, pobiera kadr 768 px (28 KiB), a Pixel 7 z gęstszym ekranem kadr 960 px (34 KiB). Dlatego weryfikowałem faktycznie pobrany adres URL obrazu, a nie wyłącznie obecność odpowiednich atrybutów w kodzie HTML. Szerzej o wyborze między next/image, srcset a CDN piszę w poradniku optymalizacji obrazów w Next.js.

Wdrożenie 3: leniwe ładowanie mapy Leaflet po przewinięciu

Dynamiczny import mapy chronił dotychczas wyłącznie przed renderowaniem po stronie serwera, uruchamiając komponent od razu po jego zamontowaniu. Wdrożenie mechanizmu opartego na obserwacji widoczności (IntersectionObserver z marginesem 200 px) uzależniło ładowanie mapy, jej stylów i kafelków od zbliżania się sekcji do obszaru widocznego.

Dzięki zarezerwowaniu stałej wysokości kontenera wyeliminowałem skoki układu (CLS), a opcjonalny przycisk pozwala na ręczne włączenie widoku. Rozwiązanie wdrożyłem na stronie głównej, podstronach miejskich, w katalogu oraz sekcjach usługowych. Brak sztucznych opóźnień czasowych sprawia, że elementy znajdujące się blisko pierwszego widoku ładowane są natychmiast.

Wdrożenie 4: układ mobilny w CSS zamiast przełączania w JavaScripcie

Część komponentów — m.in. karty usług i typografia FAQ — renderowała się najpierw w wariancie desktopowym, a po uruchomieniu JS wykrywała szerokość ekranu i przełączała się na mobilny. To dodatkowy render i potencjalna zmiana odstępów, widocznego tekstu i geometrii strony już po jej wyświetleniu.

Przeniosłem te różnice do punktów przełamania w CSS. Karty mają jedno drzewo HTML, a układ jest właściwy od pierwszego renderu. Mobilne rozwijanie opisów zostało, a pełna treść jest w HTML. Usunąłem wejściowe rozmywanie i przesuwanie kart oraz efekt paralaksy. W selektorze usług pierwszy krok jest widoczny od razu, animacje między krokami zostały.

Nie przypisuję tej zmianie naprawy CLS. Laboratoryjne przesunięcia były małe już przed zmianami, a terenowy CLS dotyczył całej domeny.

Wdrożenie 5: lżejsze FAQ, Google Analytics dopiero po zgodzie i dostępność

  • FAQ. Strona główna pokazuje 10 pytań, ale importowała całą bazę. Wydzieliłem używaną sekcję do osobnego modułu. Pełna strona FAQ korzysta z tych samych danych, więc nie powstały dwie kopie do synchronizacji.

  • Google Analytics. W pierwszym etapie biblioteka zaczęła się ładować przez lazyOnload, czyli później, ale nadal przy każdej wizycie. W drugim etapie gtag.js (ok. 178 KiB) pobiera się dopiero po zgodzie na analitykę. Bez zgody biblioteka wysyłała wyłącznie anonimowe sygnały trybu zgody (), a mimo to obciążała procesor przy każdej pierwszej wizycie i w każdym teście Lighthouse. Ta zmiana dotyczy już zakresu pomiaru: wizyty bez zgody nie trafiają do GA4 nawet jako sygnały do modelowania, więc liczba sesji w raportach może spaść.

  • Dostępność. Poprawiłem nazwę dostępną linku logo i kontrast części linków w opisach usług, więc Ułatwienia dostępu wróciły do 100 punktów w automatycznym audycie.

Wdrożenie 6: długi cache zasobów i bezpieczne kolejne wdrożenia

Wersjonowane zasoby miały jednodniowy cache z obowiązkową rewalidacją, bo reguła dłuższego cache dla plików Next.js przegrywała z regułami ogólnymi. Teraz wersjonowane fragmenty kodu i obrazy dostają roczny cache z immutable, a HTML i manifesty krótszy, bo pod stałym adresem może zmienić się treść. Skrypt wdrożenia zachowuje starsze wersje obrazów, żeby HTML z cache przeglądarki nie odwoływał się do usuniętych plików. Korzyści dotyczą kolejnych wizyt, więc nie wliczam ich do wyników poniżej.

Wyniki przed zmianami i po nich: Lighthouse, HAR i PageSpeed Insights

transferu strony głównej w nagraniu HAR (z 1446 do 506 KiB)
−65%transferu strony głównej w nagraniu HAR (z 1446 do 506 KiB)
punkty wydajności na telefonie w PageSpeed Insights
66 → 94punkty wydajności na telefonie w PageSpeed Insights
mobilnego LCP w PageSpeed Insights
6,9 → 2,85 smobilnego LCP w PageSpeed Insights
żądań prefetch przy wejściu na stronę główną
45 → 1żądań prefetch przy wejściu na stronę główną

Lokalne pomiary Lighthouse

Przed wdrożeniem sprawdzałem zmiany na lokalnym eksporcie w Lighthouse 13.5.0, po trzy przebiegi na wariant. Liczba żądań spadła tam z 76 do 28 na telefonie i z 89 do 28 na komputerze, a wyniki przestały skakać: przed zmianami przebiegi dawały od 68 do 88 punktów, po zmianach wszystkie trzy 88. Lokalny serwer nie odtwarzał hostingu produkcyjnego, więc o efektach rozstrzygają pomiary z produkcji poniżej.

Nagrania HAR na produkcji: przed zmianami i po nich

Lokalny audyt nie pokazuje wszystkiego, co dzieje się na produkcji, dlatego stronę główną nagrałem jeszcze dwa razy: po pierwszym etapie wdrożeń (Wdrożenia 1–6) i po drugim, czyli po wyłączeniu nowego prefetchu i zmianie ładowania Google Analytics. Pierwsze dwa nagrania pochodzą z Chrome DevTools, trzecie z Chrome sterowanego skryptem: okno 1440×900, wyłączony cache, bez przewijania, 7 s od startu nawigacji, trzy przebiegi o identycznej liczbie żądań i bajtów.

KomputerPrzed zmianamiPo 1. etapiePo 2. etapie
Żądania786223
Transfer1446 KiB982 KiB506 KiB
JavaScript956 KiB666 KiB275 KiB
Prefetch45 żądań / 444 KiB36 żądań / 225 KiB1 żądanie / 0,5 KiB
Kafelki mapy i Leaflet295 KiB00
gtag.js178 KiB178 KiB0

Na telefonie (emulacja Pixel 7) strona po drugim etapie pobiera 22 żądania i 403 KiB, a główny obraz w AVIF waży 34 KiB.

Jest jedno zastrzeżenie: nagrania z DevTools nie zapisują rozmiaru okna, a od niego zależy, które linki i leniwie ładowane obrazy trafią do pomiaru. W nagraniu po pierwszym etapie pobrały się trzy zdjęcia kart usług (152 KiB), a przy oknie 1440×900 pobiera się tylko jedno z nich (79 KiB). Część różnicy między drugą a trzecią kolumną wynika więc z wysokości okna, a nie z poprawek. Spadki prefetchu, mapy i gtag.js nie zależą od rozmiaru okna, bo potwierdziłem je także przy oknie 1440×1300.

Wyniki w PageSpeed Insights na produkcji

Po każdym etapie zmierzyłem stronę główną w PageSpeed Insights, po trzy niezależne przebiegi na urządzenie. PSI przez chwilę zwraca zapisany wynik dla tego samego adresu, więc kolejne przebiegi uruchamiałem z parametrem w URL i sprawdzałem, czy każdy ma inny czas pomiaru.

TelefonPrzed zmianami (1 przebieg)Po 1. etapie (mediana z 3)Po 2. etapie (mediana z 3)
Wydajność6684 (81–94)94 (91–95)
FCP2,3 s1,45 s1,05 s
LCP6,9 s2,90 s2,85 s
TBT240 ms340 ms116 ms
Speed Index5,1 s4,60 s2,88 s
CLS000

Na komputerze wynik po drugim etapie to 99 punktów (96–100), LCP 0,53 s i 100 ms. Pozostałe kategorie nadal mają po 100 punktów na obu urządzeniach. Na produkcji potwierdziłem też nagłówki: wersjonowane fragmenty kodu dostają roczny cache z immutable, a HTML godzinny z rewalidacją.

Mobilny LCP spadł po pierwszym etapie z 6,9 do 2,9 s i w drugim już się nie zmienił (2,85–2,89 s we wszystkich przebiegach), bo usunięte w nim zasoby pobierały się dopiero po wyświetleniu głównego obrazu. Wzrost wyniku z 84 do 94 punktów to więc efekt mniejszej pracy JavaScriptu na starcie, a nie szybszego głównego obrazu: TBT spadł z 340 do 116 ms, Speed Index z 4,6 do 2,9 s, a nieużywany JavaScript ze 141 do 69 KiB.

Z porównaniem do stanu wyjściowego trzeba być ostrożnym, bo 66 punktów i LCP 6,9 s to pojedynczy pomiar. Lokalne przebiegi „przed” pokazały, że jeden pomiar potrafi różnić się od kolejnych nawet dwukrotnie, więc część spadku LCP może wynikać z niekorzystnego przebiegu wyjściowego.

Testy funkcjonalne po optymalizacji wydajności

Mniejszy transfer nic nie daje, jeśli użytkownik nie może wybrać usługi albo widzi pustą mapę. Dlatego po pierwszym etapie sprawdzałem także działanie interfejsu:

  • 34 kontrole w Chromium przy szerokościach 390, 768 i 1366 px — wszystkie przeszły. Objęły wybór miasta i usługi, przejście do wyników, mapę po przewinięciu, rozwijanie opisów i FAQ, zgody, zdarzenia Oferteo, strony elektryczne, gazowe, miejskie, artykuł blogowy i formularz rezerwacji.
  • Pełna kompilacja: 786 stron, lint, TypeScript i 96 testów jednostkowych bez błędów.
  • Osobne testy dla reguł cache i zachowania plików między wdrożeniami.

Po drugim etapie powtórzyłem TypeScript, lint i 96 testów jednostkowych, a efekt na produkcji sprawdziłem w nagraniach HAR i PSI opisanych wyżej.

Czego nie osiągnąłem: mobilny LCP i kolejne kroki

Cel na telefonach miał dwie części: 90 punktów i LCP do 2,5 s. Pierwszą osiągnąłem dopiero po drugim etapie (mediana 94 punkty), drugiej nie. LCP 2,85 s jest wprawdzie daleko od wyjściowych 6,9 s, ale nadal w przedziale „wymaga poprawy”.

Z czego składa się 2,85 s mobilnego LCP

Żeby to sprawdzić, nagrałem cztery przebiegi w panelu wydajności Chrome z emulacją telefonu Moto G Power (tego samego, którego używa Lighthouse), siecią Slow 4G i czterokrotnie spowolnionym procesorem. LCP wyszedł 2,82–2,94 s, czyli tyle co w PSI.

Część LCPCzasUdział
Odpowiedź serwera (TTFB)ok. 145 ms5%
Opóźnienie startu pobierania obrazuok. 550 ms21%
Pobieranie obrazuok. 2100 ms72%
Opóźnienie renderu25–50 ms1%

Głównym źródłem problemu jest przepustowość łącza na początku ładowania. Obraz jest przygotowany poprawnie, bo jest w HTML od pierwszego bajtu, ma fetchpriority="high" i nie ma leniwego ładowania. Startuje jednak w tej samej chwili co prawie cały pierwszy widok — zanim się wyświetli, przeglądarka zaczyna pobierać 391 z 397 KiB strony. Wysoki priorytet niewiele tu zmienia, bo wszystkie te pliki dzielą jedno łącze, więc obraz ważący 28 KiB pobiera się ponad 2 s.

Przegląd kodu z mapami źródeł pokazał, co dzieli łącze z obrazem:

  • Biblioteki animacji i menu. framer-motion waży ok. 49 KiB po kompresji, a Headless UI z zależnościami ok. 34 KiB, czyli razem więcej niż sam React. Obsługują menu mobilne, rozwijane menu na komputerze, przejścia między krokami selektora usług i efekty wciśnięcia przycisków, czyli głównie rzeczy, które użytkownik uruchamia dopiero kliknięciem.

  • Duplikaty. Katalog usług z next-seo (11,6 KiB) i runtime (4,1 KiB) trafiają do HTML w dwóch identycznych plikach. Build przez webpack nie pomaga, bo strona główna ma wtedy 277 zamiast 270 KiB JavaScriptu.

  • Fonty. Plus Jakarta Sans to font zmienny, więc jeden plik obsługuje wszystkie grubości, ale strona pobiera dwa: podstawowy zestaw łaciński (27 KiB) i rozszerzony z polskimi literami (21,5 KiB). Konfiguracja next/font deklaruje tylko latin, więc drugi plik nie ma preloadu i przeglądarka odkrywa go dopiero po przetworzeniu CSS, tuż przed LCP.

Przy przepustowości Slow 4G (ok. 195 KiB/s) każde ok. 70 KiB mniej przed wyświetleniem obrazu to ok. 0,35 s, czyli mniej więcej tyle, ile brakuje do progu.

Następne kroki:

  1. Zastąpienie framer-motion przejściami CSS w nagłówku, przyciskach i selektorze usług, a menu mobilnego i rozwijanego natywnymi elementami albo kodem ładowanym dopiero po pierwszym kliknięciu (do ok. 80 KiB mniej przed LCP).
  2. Usunięcie zduplikowanych plików JavaScriptu (ok. 16 KiB).
  3. Jeden plik fontu z polskimi znakami, ładowany wstępnie (ok. 15–20 KiB mniej i brak późnego odkrywania).
  4. Obserwacja terenowego CLS na telefonach w kolejnych 28-dniowych oknach CrUX, z rozbiciem na typy stron. Pierwszy sygnał wygląda dobrze, bo CLS dla domeny spadł z 0,11 do 0,10, ale okno nadal obejmuje głównie dni sprzed wdrożeń i trzeba czekać do końca listopada na jego przesunięcie.

Jak wygląda strona usługowa w Next.js doprowadzona do 100 punktów na obu urządzeniach, pokazuję w case study PageSpeed 100/100.

Audyt techniczny i optymalizacja SEO.
Audyt techniczny SEO

O autorze

Maciej Sala

Maciej Sala — konsultant technologiczny produktów cyfrowych i web 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.

Pomagam przekładać takie tematy na konkretne wdrożenia w frontendzie, SEO, analityce i procesie produktowym.

Skontaktuj się ze mną
LH.pl – Hosting Mango

Biblioteka wiedzy na temat SEO

Czytaj dalej

Zobacz więcej wpisów
Jak poprawić Core Web Vitals i czy to pomaga w Google?

Core Web Vitals pokazują, jak szybko strona wyświetla główną treść, reaguje na działania użytkownika i czy jej układ pozostaje cały czas stabilny. Mimo że Google bierze pod uwagę te metryki przy ustalaniu pozycji, sam „zielony raport” nie zapewnia sukcesu w wynikach wyszukiwania. Najważniejszym czynnikiem zawsze pozostaje merytoryczna i dopasowana do intencji użytkownika treść . W związku z powyższym, by optymalizacja miała sens, trzeba rozpoznać problem w danych, dobrać poprawkę i sprawdzić jej efekty u użytkowników.

Maciej Sala

Maciej Sala

Founder StriveLab

Jak osiągnąć 100/100 w Lighthouse Performance w Next.js? Case study

Mamy tu typową stronę usługową zbudowaną w Next.js, wyposażoną w Google Analytics, Google Tag Manager , prosty formularz kontaktowy, galerię zdjęć i animacje. Na początku testy PageSpeed Insights pokazały wyniki: 67/100 na urządzeniach mobilnych i 89/100 na komputerach stacjonarnych.

Maciej Sala

Maciej Sala

Founder StriveLab

Audyt techniczny SEO: co obejmuje w 2026 roku?

To, że strona otwiera się w przeglądarce, nie oznacza jeszcze, że robot wyszukiwarki jest w stanie bez przeszkód pobrać jej treść, poprawnie ją zinterpretować i ostatecznie włączyć do indeksu. Audyt techniczny SEO służy właśnie do weryfikacji tych krytycznych warunków. Pozwala on zidentyfikować fundamenty wymagające naprawy i wyznaczyć właściwe priorytety, zanim przejdziemy do rozbudowy treści oraz pozyskiwania linków.

Maciej Sala

Maciej Sala

Founder StriveLab

LH.pl – Cloud Server 1C4G