Polska wersja case study z santifer.io. Obrazy wyodrębnione z zapisanej strony HTML (folder assets/). Oryginał: Programmatic SEO — Santiago Fernández de Valderrama.

Case study — Santifer iRepair

Programmatic SEO: ponad 4700 stron z ERP

Jak wygenerowałem 4730 unikalnych landing page’y z realnymi danymi produkcyjnymi, CMS-em Airtable (14 tabel) i DataForSEO jako silnikiem decyzji. 2,26 mln wyświetleń, ponad 19 tys. kliknięć.

Santiago Fernández de Valderrama
37 min czytania· Aktualizacja

Na hiszpańskim rynku naprawy urządzeń nikt nie robił programmatic SEO. Każda kombinacja urządzenia, marki, modelu, typu naprawy i miasta była niewykorzystaną okazją long-tail.

Teza: jeśli ktoś szuka „wymiana baterii iPhone Sewilla”, powinna istnieć dedykowana strona — z realną ceną, szacowanym czasem realizacji i zdjęciami z prawdziwych napraw. Ręczne budowanie tysięcy stron się nie skaluje. Potrzebowałem systemu, który generuje je automatycznie z ERP i wystarczająco mądrego, by zdecydować, które indeksować, a które pominąć.

Santifer iRepair to był mój serwis naprawy urządzeń w Sewilli od 2009 roku. Szesnaście lat, ponad 30 000 napraw. W 2024 uznałem, że strona musi wyjść poza broszurę na Squarespace i zacząć przechwytywać popyt już obecny w Google. Zbudowałem ten system programmatic SEO jako moat konkurencyjny i sprzedałem firmę we wrześniu 2025 — w szczycie wyników.

W 10 sekund

  • Zbudowano 4730 statycznych landing page’y z produkcyjnego ERP (realne ceny, zdjęcia, zweryfikowane opinie)
  • Silnik decyzji z DataForSEO: indeksowane są tylko strony z realnym wolumenem wyszukiwań
  • Wynik: 2,26 mln wyświetleń, ponad 19 tys. kliknięć organicznych, 80% całego ruchu witryny
  • 7 miesięcy budowy, jedna osoba, sprzedaż na szczycie wyników

Okazja

Hiszpański rynek naprawy urządzeń jest hiper-lokalny. Ludzie szukają po mieście, marce i typie naprawy. Większość punktów miała jednak generyczne strony — jeden landing na całą Hiszpanię, o ile w ogóle miała stronę.

Tysiące kombinacji long-tail praktycznie bez konkurencji w SERP

Wyraźna intencja transakcyjna: użytkownik chce naprawy, nie informacji

Żaden konkurent w branży nie robił programmatic SEO w Hiszpanii (2024)

ERP miał już wszystko: 867 modeli, ceny, czasy realizacji, prawdziwe zdjęcia

Naturalna taksonomia biznesu (urządzenie, marka, model, naprawa, miasto) mapuje się wprost na URL-e

Prawdziwe zapytania z GSC

ZapytanieKliknięciaImp.CTRPos.
reparacion moviles sevilla421,9472.2%2.5
reparar iphone sevilla513,3141.5%12.9
reparacion iphone sevilla464,3151.1%5.2
cambiar bateria pixel 6a517556.8%6.4
servicio tecnico garmin sevilla365346.7%6.5
cambiar bateria apple watch373,9670.9%11.7

Liczby

2.26M

Wyświetlenia

Łącznie (pomiar w Google Search Console)

19K+

Kliknięcia organiczne

Realny ruch z wyszukiwania organicznego (pomiar w Google Search Console)

4,730

Strony z ruchem

Spośród tysięcy wygenerowanych: 4084 indeksowalne w sitemapie, 4730 zebrało wyświetlenia

10.8x

Wzrost miesięczny

Z 202 do 2193 kliknięć/miesiąc w 11 miesięcy

80%

Kliknięcia z pSEO

Ruch organiczny pochodzi ze stron programmatic

7

Miesiące

1 osoba. CMS, pipeline’y, DataForSEO, 26 tys. obrazów i deploy

Budowa: marzec → październik 2024 (7 miesięcy). Jedna osoba. CMS, skrypty generacji, pipeline obrazów, integracja DataForSEO i wdrożenie — wszystko równolegle. Start produkcyjny: październik 2024. Gdybym budował to dziś z Claude Code, zajęłoby tydzień.

Strona główna santiferirepair.es
santiferirepair.es: strona główna wygenerowana Astro SSG. Wyszukiwarka urządzeń, kategorie i marki.

Dwie strategie, jeden system

Projekt zaczął się od ambicji ogólnokrajowych, ale Google miał inne zdanie. Wyszukiwania napraw mają silną intencję lokalną — Google faworyzuje wyniki blisko użytkownika, więc strony bez miasta nie konkurowały. Rozwiązanie: strategia dualna. Strony lokalne dla Sewilli (gdzie jest fizyczny punkt) oraz krajowe strony niszowe dla konkretnych napraw, gdzie lokalizacja ma mniejsze znaczenie.

Strony lokalne (Sewilla)

Kombinacje urządzenie + marka + naprawa z „/sevilla”. Google wyżej je pozycjonuje dzięki bliskości fizycznego punktu. Generują najwięcej ruchu.

/reparar-smartwatch/sevilla615 kliknięć · 3,7%
/reparar-iphone/bateria/sevilla581 kliknięć · 2,5%
/reparar-apple-watch/sevilla562 kliknięć · 2,7%
/reparar-iphone/sevilla466 kliknięć · 0,6%
/reparar-ipad/sevilla370 kliknięć · 1,2%

Strony krajowe (bez miasta)

Niszowe naprawy, gdzie lokalizacja ma mniejsze znaczenie. Format „cambiar-{część}-{marka}-{model}” łapie zapytania informacyjne, które konwertują.

/cambiar-bateria-google-pixel-6a372 kliknięcia · 5,0%

Architektura

System ma cztery warstwy. Airtable działa jako headless CMS z 14 tabelami i ~60 polami na tabelę. ERP zasila realnymi danymi produkcyjnymi. DataForSEO decyduje, co trafia do indeksu. Astro generuje statyczny HTML z minimalnym JS po stronie klienta — tylko to, co potrzebne do UX (wyszukiwarka, karuzela), ładowane lazy.

Airtable (headless CMS)

14 tabel, ~60 pól na tabelę. Hierarchia 6 poziomów: typ urządzenia, marka, rodzina, model, naprawa + warianty lokalne. Podwójne ceny (części oryginalne i kompatybilne), dziedziczenie obrazów, kaskadowy social proof.

ERP (dane produkcyjne)

Zasila Airtable realnymi danymi: zdjęcia before/after z prawdziwych napraw, zweryfikowane opinie klientów, aktualny stan części. 867 modeli, 20+ marek, 15+ typów naprawy.

DataForSEO (silnik decyzji)

Pobiera realne wolumeny wyszukiwań dla każdej kombinacji. Pole „indexable” w Airtable jest napędzane bezpośrednio tymi danymi. Brak wolumenu = brak indeksacji.

Astro (generacja statyczna)

21 szablonów stron. Generuje statyczny HTML z minimalnym JS ładowanym lazy. 6 typów JSON-LD na stronę. SEO obrazów z wstrzykiwaniem EXIF. Deploy na Cloudflare CDN.

Taksonomia URL

Serwis używa 6 wzorców URL, każdy odpowiadający poziomowi taksonomii biznesowej. Wzorce lokalne (z /sevilla) łapią intencję lokalną. Wzorce krajowe (bez miasta) łapią wyszukiwania niszowe.

/reparar-{device}/{city}

/reparar-{device}/{brand}/{city}

/reparar-{device}/{repair-type}/{city}

/reparar-{device}/{brand}/{repair-type}/{city}

/reparar-{device}/{model}/{repair-type}

/cambiar-{repair}-{brand}-{model}

Premiumowe trasy Apple

Od 2009 naprawialiśmy wyłącznie urządzenia Apple — ludzie nas z tego znali. Apple ma najwyższy wolumen wyszukiwań, a krótsze trasy oddają ten priorytet: /iphone/14-pro zamiast /reparar-movil/apple/iphone-14-pro. Krócej, czyściej, lepszy CTR. Jedna flaga boolean zmienia wszystko:

// Apple: /iphone/14-pro (short, clean, better CTR)
const records = await getRecordsModelos(true);  // modoApple = true → CMSAstro(Apple) view
return records.map(r => ({
  params: { paramMarcaApple: r.paramMarca, paramModeloApple: r.paramModelo },
}));

// Generic: /reparar-movil/samsung/galaxy-s21
const records = await getRecordsModelos();  // modoApple = false → CMSAstro view
return records.map(r => ({
  params: { paramTipo: r.paramTipo, paramMarca: r.paramMarca, paramModelo: r.paramModelo },
}));

modoApple = true

Jedna flaga boolean przełącza widok Airtable (CMSAstro vs CMSAstro(Apple)) i strukturę URL. Ta sama strona, ten sam layout, dwa systemy routingu.

Krótsze trasy

/iphone/14-pro vs /reparar-movil/apple/iphone-14-pro. Apple is the dominant brand in repairs; its routes deserve premium URLs.

Wewnątrz CMS

Airtable to nie tylko „arkusz na sterydach”. Tutaj działa jak pełny relacyjny CMS. Klucz: hierarchia 6 poziomów, która dokładnie odzwierciedla sposób działania firmy.

TabelaCelKluczowe pola
Typy urządzeńPoziom główny taksonomiislug, name, SEO description, menu order
MarkiMarki powiązane z typami urządzeńslug, name, logo, compatible types
RodzinyGrupowanie modeli (np. seria iPhone 14)slug, hero image (inheritable), brand
ModeleKonkretne urządzenia z cenamislug, family, image (inherits from family if empty), year
NaprawyTypy napraw per modelslug, original price, compatible price, turnaround, indexable
Warianty lokalneStrony miejskie pod lokalne SEOmodel + repair + city, adjusted price, availability
Hierarchia tabel Airtable — CMS programmatic SEO
14 tabel CMS połączonych z Business OS (12 baz). Hierarchia 6 poziomów: od typu urządzenia do wariantu lokalnego.

Ten CMS z 14 tabelami jest częścią większego Airtable Business OS (12 baz), który prowadził całą firmę: magazyn, CRM, księgowość, HR i więcej. Przeczytaj pełne case study Business OS →

Kluczowe wzorce CMS

Podwójne ceny

Każda naprawa ma cenę z częściami oryginalnymi i cenę z kompatybilnymi. Użytkownik wybiera na landing page.

Dziedziczenie obrazów

Jeśli model nie ma obrazu, dziedziczy go z rodziny. Mniej utrzymania, żadnych pustych stron.

Kaskadowy social proof

Opinie łączą się na poziomie modelu, rodziny lub marki. Opinia o „iPhone 14 Pro” pojawia się na każdej stronie naprawy tego modelu.

Tryb bridge

Wycofane naprawy nie są usuwane — dostają flagę „bridge” i przekierowują do najbliższej alternatywy. Zero 404, zero utraty autorytetu.

Strona kategorii Samsung na santiferirepair.es
Automatycznie wygenerowana strona kategorii. Każda marka ma własny landing z modelami, cenami i opiniami.

Anatomia strony

Każda z ponad 4700 stron powstaje z szablonu, ale treść jest unikalna, bo pochodzi z ERP. To nie tekst generowany AI ani wypełniacz — to dane produkcyjne.

Breadcrumb + schema

Hierarchiczna nawigacja odzwierciedlająca taksonomię. Automatycznie generuje BreadcrumbList JSON-LD.

Realne ceny

Ceny oryginalne i kompatybilne, pobrane z ERP. Użytkownik widzi dokładnie, ile zapłaci.

Szacowany czas realizacji

Na podstawie realnych, historycznych danych napraw. Nie generyczny zgadywak.

Zdjęcia before/after

Prawdziwe zdjęcia z ukończonych napraw. EXIF z geolokalizacją i metadanymi SEO.

Zweryfikowane opinie

Prawdziwe opinie klientów powiązane z modelem lub rodziną. Ze schemą Review i AggregateRating.

6 typów JSON-LD

LocalBusiness, Product, Service, BreadcrumbList, FAQStrona, AggregateRating. Każda strona ma pełny markup.

Pola rekordu naprawy w Airtable
Każda naprawa ma ~60 pól: podwójne ceny, flaga indexable, specyfikacje modelu zasilające dynamiczny copy.
Anatomia programatycznej strony naprawy
Prawdziwy przykład: strona naprawy wygenerowana z ERP. Podwójne ceny, realne opinie, pełny JSON-LD.
Hero strony naprawy na santiferirepair.es
Hero strony naprawy: podwójne ceny (oryginał/kompatybilne), CTA rezerwacji i semantyczny breadcrumb.

Ścieżka konwersji na stronie

Każda strona ma strukturę konwersji zaprojektowaną tak, by przeprowadzić użytkownika od odkrycia do działania:

Hero z podwójnymi cenami (oryginał/kompatybilne) + bezpośrednie CTA rezerwacji

Specyfikacje modelu: aparat, bateria, technologie urządzenia

Galeria prawdziwych zdjęć before/after napraw

Zweryfikowane opinie klientów powiązane z modelem lub rodziną

FAQ generowane z danych ERP (prawdziwe pytania klientów)

Końcowe CTA z mapą punktu i przyciskiem rezerwacji

Użytkownik szuka „naprawa ekranu iPhone 14 Pro Sewilla”. Trafia na stronę z cenami (189 € oryginał / 89 € kompatybilne), szacowanym czasem (45 min), 3 prawdziwymi zdjęciami naprawy iPhone 14 Pro i 12 zweryfikowanymi opiniami. Bez zbędnej nawigacji — wszystko potrzebne do decyzji jest na miejscu.

Dynamiczny copy per model

Każdy model dostaje unikalny microcopy wygenerowany z realnych parametrów sprzętu. Pole w Airtable trzyma specyfikację (aparat, bateria, procesor, odporność na wodę), a prompt generuje opis różniący się per model. iPhone 14 Pro mówi o aparacie 48 MP i wyświetlaczu ProMotion. Pixel 7a podkreśla chip Tensor i fotografię obliczeniową. To nie generyczny wypełniacz — to copy, który dotyczy TYLKO tego modelu, na podstawie realnych danych sprzętowych. Ten sam szablon, unikalna treść na każdej stronie.

Dynamiczny copy iPhone 12: realne parametry sprzętu generują unikalny tekst per model
Strona iPhone 12: opcje pamięci, RAM, Super Retina XDR OLED, bateria Li-Ion 2815 mAh. Wszystko z realnych specyfikacji modelu w Airtable.

Live pricing z ERP

Ten sam CMS, który generuje copy, synchronizuje też ceny napraw w czasie rzeczywistym. Airtable łączy ERP (gdzie aktualizowane są koszty części i marże) ze stroną. Każda karta modelu pokazuje zakres cen z min i max dostępnych napraw. Gdy cena zmienia się w ERP, rebuild strony wgrywa nową cenę — zero ręcznej interwencji.

Strona kategorii iPhone z zakresami cen synchronizowanymi z ERP
Strona kategorii: każda karta pokazuje „Desde X € hasta Y €”, wyliczane automatycznie z cen napraw w ERP.
let cadenaPrecio = '';
if (mostrarPrecio.startsWith('desde') && detail.precioMinCard) {
  cadenaPrecio = `Desde ${detail.precioMinCard}`;
}
if (mostrarPrecio === 'desdeHasta' && detail.precioMaxCard) {
  cadenaPrecio = `${cadenaPrecio} hasta ${detail.precioMaxCard}`;
}
if (mostrarPrecio === 'exacto' && detail.precioMinCard) {
  cadenaPrecio = detail.precioMaxCard
    ? `Desde ${detail.precioMinCard} hasta ${detail.precioMaxCard}`
    : `${detail.precioMinCard}`;
}

Trzy tryby cen

„desde” (tylko minimum), „desdeHasta” (pełny zakres), „exacto” (stała cena lub zakres z CTA). Tryb konfiguruje się per typ strony.

precioMinCard / precioMaxCard

Pola wyliczane w Airtable: agregują min i max ze wszystkich dostępnych napraw modelu. Gdy koszt części zmienia się w ERP, pola przeliczają się automatycznie.

Pasek wyszukiwania to nie prosty filtr tekstowy. Działa na własnym algorytmie scoringu — bez zewnętrznych bibliotek typu Fuse.js. Użytkownik wpisuje „iphone 12 pro”, a system ocenia wszystkie 867 modeli: +20 jeśli wszystkie słowa pasują, +30 za dokładne dopasowanie, +10 jeśli nazwa modelu zaczyna się od zapytania, i karze dodatkowe słowa w nazwie. Wynik: 6 najbardziej trafnych modeli, posortowanych po wyniku.

Homepage search: "12 pro" shows results across all brands
Home: "12 pro" → Xiaomi, Apple, Xiaomi...
iPhone page search: "13" only shows iPhone models
iPhone page: "13" → iPhones only

Ciekawe jest to, że wyszukiwanie jest świadome kontekstu. Na stronie głównej przeszukuje wszystkie 867 modeli ze wszystkich marek i typów. Na stronie marki (np. Samsung) — tylko modele Samsung. Na stronie typu urządzenia (np. tablety) — tylko tablety. Ten sam komponent, z propsami filtrów (`filtroTipo`, `filtroMarca`), zachowuje się inaczej w zależności od miejsca osadzenia. Modele ładują się lazy przy pierwszym fokusie inputu i cache’ują w localStorage, więc kolejne wyszukiwania są natychmiastowe.

Oto prawdziwa funkcja scoringu — 30 linii, zero zależności:

function calcularPuntuacion(modelo, terminosBusqueda) {
  let puntuacion = 0;
  const nombreModelo = modelo.n.toLowerCase();

  const todasPresentes = terminosBusqueda.every(t => nombreModelo.includes(t));

  if (todasPresentes) {
    puntuacion += 20;
    const palabrasModelo = nombreModelo.split(/\s+/);
    const extras = palabrasModelo.filter(p => !terminosBusqueda.includes(p)).length;
    puntuacion -= extras * 2;

    if (nombreModelo === terminosBusqueda.join(' ')) puntuacion += 30;
    if (nombreModelo.startsWith(terminosBusqueda.join(' '))) puntuacion += 10;
  }
  return puntuacion;
}

+20 baza

Wszystkie terminy muszą być obecne. „iphone 12 pro” pasuje do „Apple iPhone 12 Pro”, ale nie do „Apple iPhone 12”.

−2 za dodatkowe słowo

Karze długie nazwy. „Apple iPhone 12 Pro Max” dostaje niższy wynik niż „Apple iPhone 12 Pro” dla zapytania „iphone 12 pro”.

+30 dokładne, +10 starts-with

Dokładne dopasowania dominują. 30 linii, zero zależności, w tej domenie lepsze niż Fuse.js.

Silnik decyzji

System generuje tysiące stron (znacznie więcej niż 4730, które dostały ruch), ale nie wszystkie zasługują na indeksację. Jeśli nikt nie szuka „naprawa kamery przedniej iPhone 11”, ta strona nie powinna konkurować w Google — ale musi istnieć dla użytkownika przeglądającego stronę iPhone 11, który właśnie tej naprawy potrzebuje. Klucz: oddzielenie SEO od UX. Silnik decyzji odpytuje DataForSEO o realny wolumen dla każdej kombinacji i zapisuje wynik w polu „indexable” w airtable.ts.

1

Wysoki wolumen (DataForSEO) → strona indeksowalna

Jeśli słowo kluczowe ma istotny wolumen, strona powstaje z meta robots „index, follow”, trafia do sitemapy i dostaje priorytetowe linkowanie wewnętrzne.

2

Niski lub zerowy wolumen → strona noindex (tylko UX)

Strona istnieje pod UX i nawigację wewnętrzną, ale ma meta robots „noindex” i jest wyłączona z sitemapy.

3

Brak danych usługi w ERP → strona nie powstaje

Jeśli nie ma realnych danych usługi (cena, dostępność), strona nie jest budowana. Zero thin content.

4

Wycofana naprawa → przekierowanie bridge

Strona dostaje flagę „bridge” i zwraca 301 do najbliższej alternatywy. Chroni zgromadzony autorytet.

System generuje łącznie tysiące stron. Z nich 4084 trafiło do sitemapy jako indeksowalne. 4730 zebrało wyświetlenia z Google. Reszta nie jest indeksowana, ale nadal istnieje dla użytkownika nawigującego po serwisie.

Pole indexable w Airtable napędzane DataForSEO
Silnik decyzji: DataForSEO zasila pole indexable. Brak wolumenu → noindex.

Optymalizacja crawl budget

Przy ponad 4700 stronach zarządzanie crawl budgetem jest krytyczne — zgodnie z dokumentacją Google Search Central. Google nie powinien marnować czasu na strony, które nie będą rankować. Ponad 700 reguł robots.txt dokłada się do 1009 przekierowań odziedziczonych po migracji.

Selektywny noindex z DataForSEO

Pole „indexable” w Airtable jest zasilane bezpośrednio danymi wolumenu z DataForSEO. Strony bez wolumenu dostają noindex. To nie arbitralna decyzja — to podejście data-driven.

Filtrowana sitemap (4084 URL-e)

sitemap.xml zawiera tylko URL-e indeksowalne. Spośród 4730 stron z wyświetleniami tylko 4084 trafiło do sitemapy. Google nie odkrywa reszty tym kanałem.

Struktura URL z 6 wzorcami

Każdy poziom taksonomii ma przewidywalny wzorzec URL. Google rozumie hierarchię bez zgadywania.

Kontekstowe linkowanie wewnętrzne

Strony indeksowalne dostają więcej linków wewnętrznych. Strony miast linkują do dostępnych napraw, modele do swoich napraw, rodziny agregują modele.

Przekierowania bridge dla wycofanych pozycji

Zamiast zwracać 404 przy wycofanej naprawie, robi 301 do najbliższej alternatywy. Ponad 700 reguł przekierowań w vercel.json. Zero utraty autorytetu, zero martwych linków.

Wzorzec „Safe Noindex”

Przypadkowy noindex to jeden z najdroższych błędów SEO — jedna linia może zdeindeksować tysiące stron. Oto jak temu zapobiegliśmy:

{NOINDEXCUIDADO &&
  NOINDEXCUIDADO === 'Estoy absolutamente seguro que no quiero hacer no index por eso pongo esta cadena' && (
    <meta name="robots" content="noindex" />
  )}

String, nie boolean

Boolean może być true przez przypadek (złe pole, domyślna wartość, błąd migracji). 80-znakowy hiszpański string wymaga świadomej intencji.

Podwójna straż

Prop musi być truthy ORAZ dokładnie równy stringowi. Nawet ustawiony na „true” lub 1 — tag noindex się nie wyrenderuje.

Dwa lata na produkcji. Zero przypadkowych deindeksacji. 80-znakowy hiszpański string zrobił swoje.

Pipeline budowy

Pipeline zamienia dane CMS w gotowy do deployu statyczny serwis. W pełni zautomatyzowany. Sam schema.ts ma 1677 linii mapujących hierarchię Airtable na typy Astro.

1

Airtable API

Ekstrakcja rekordów z retry i exponential backoff

2

Mapowanie schema

1677 linii transformujących hierarchię 6 poziomów na typy TypeScript

3

Cache opinii

Opinie są cache’owane, by unikać zbędnych wywołań API

4

getStaticPaths

Generuje statyczne trasy z pełnej taksonomii

5

ReparacionLayout

21 szablonów stron renderowanych według poziomu taksonomii

6

Astro SSG

Statyczny build z minimalnym JavaScriptem ładowanym lazy

7

Optymalizacja

Skompresowane obrazy, wstrzykiwanie EXIF, filtrowana sitemap, linkowanie wewnętrzne

8

Cloudflare CDN

Deploy z invalidacją cache i globalnym cache’owaniem edge

Retry z exponential backoff

Pipeline zaczyna od pobrania danych z Airtable. Czternaście tabel, tysiące rekordów — wywołania API muszą być odporne. Jedna generyczna funkcja obsługuje wszystko:

function delay(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function retryWithBackoff<T>(
  operation: () => Promise<T>,
  retries: number = 5,
  delayTime: number = 500
): Promise<T> {
  try {
    return await operation();
  } catch (error: any) {
    if (retries > 0 && (error.statusCode === 502 || error.statusCode === 503)) {
      await delay(delayTime);
      return retryWithBackoff(operation, retries - 1, delayTime * 2);
    }
    throw error;
  }
}

Generic <T>

Jedna funkcja dla każdego typu rekordu (ITipos, IMarcas, IModelos, IReparaciones...).

Tylko 502/503

Retry tylko przy błędach serwera (Bad Gateway, Service Unavailable). Błędy klienta (400, 401) padają od razu.

delayTime * 2

Exponential backoff: 500 ms → 1 s → 2 s → 4 s → 8 s. 5 prób = max 15,5 s przed poddaniem się.

System cache’u opinii

Opinie to najdroższe wywołania w buildzie: ponad 4700 stron może ich potrzebować, ale istnieje tylko 607. Ładujemy je raz na starcie builda, a każda strona czyta z pamięci:

let caches: { [key: string]: Reseña[] | undefined } = {};

async function loadReseñas(baseName: string, cacheKey: string): Promise<void> {
  if (caches[cacheKey]) return;

  const fetchOperation = () => new Promise<Reseña[]>((resolve, reject) => {
    const allRecords: Reseña[] = [];
    base(baseName)
      .select({ view: 'CMSAstro', fields: ReseñaFields })
      .eachStrona(
        (records, fetchNextStrona) => {
          records.forEach(record => allRecords.push(mapReseñaFields(record.fields)));
          fetchNextStrona();
        },
        (err) => err ? reject(err) : resolve(allRecords)
      );
  });

  caches[cacheKey] = await retryWithBackoff(fetchOperation);
}

export async function ensureCachesLoaded(): Promise<void> {
  await Promise.all([
    loadReseñas('Reseñas sincronizar Astro', 'cachedReseñas'),
    loadReseñas('Reseñas Internas', 'cachedReseñasInternas')
  ]);
}

// Runs on module import
ensureCachesLoaded().catch(console.error);

Wywołanie na poziomie modułu

ensureCachesLoaded() uruchamia się przy imporcie modułu. W Astro SSG wszystkie opinie ładują się do pamięci przed generacją stron.

Promise.all

Oba źródła (Google My Business + wewnętrzne ankiety) ładują się równolegle.

Trade-off: O(n) find

Strony szukają po ID przez .find(). Skan liniowy, ale przy 607 opiniach eliminuje setki wywołań API. Właściwy trade-off dla pipeline’u budowy.

Zautomatyzowany pipeline treści

Wygenerowanie tysięcy stron to połowa roboty. Każda potrzebuje unikalnych obrazów, metadanych i copy. Osiem skryptów Node.js (łącznie 1411 linii) automatyzuje całą produkcję wizualną i tekstową — zero pracy ręcznej. Wszystko łączy się z 12 bazami Airtable w Business OS. Wynik: ponad 26 000 automatycznie wygenerowanych obrazów.

Parametryczna generacja obrazów

Jedno zdjęcie urządzenia automatycznie daje 18 wariantów — po jednym na typ naprawy (ekran, bateria, aparat, port ładowania...) plus obraz generyczny. Zdjęcia urządzeń pochodzą z GSM Arena i są składane z PNG overlayami napraw. 867 modeli × 18 wariantów = ponad 15 500 unikalnych obrazów, bez Photoshopa.

Wstrzykiwanie EXIF pod lokalne SEO

Każdy obraz dostaje współrzędne GPS Sewilli i opis SEO wstrzyknięty do metadanych EXIF. Google Images czyta je pod ranking lokalny. Automatyzacja: piexifjs i kodowanie UCS-2.

Pipeline zdjęć before/after

Ponad 10 000 prawdziwych zdjęć napraw przetwarzanych automatycznie. Pobrane z Airtable, przeskalowane, z rozmytym tłem, złożone do WebP, a wynikowe URL-e zapisane z powrotem do Airtable. Dwukierunkowe ETL: Airtable → przetwarzanie → Airtable.

Dynamiczny copy per model

Każdy model ma pole z realnymi parametrami sprzętu (aparat, bateria, procesor). Prompt zamienia je w unikalny microcopy dla każdej strony. To nie AI „wymyślające treść” — to AI opisujące realne dane sprzętowe. Każda strona czyta się inaczej, bo każde urządzenie JEST inne.

Każdy obraz naprawy dostaje współrzędne GPS punktu wstrzyknięte do metadanych EXIF. Google Images używa tych danych, by pokazywać obrazy w wynikach lokalnych:

// Shop coordinates in Seville
gps[piexif.GPSIFD.GPSLatitude] = convertToDMS(37.38606);
gps[piexif.GPSIFD.GPSLatitudeRef] = 'N';
gps[piexif.GPSIFD.GPSLongitude] = convertToDMS(-5.98585);
gps[piexif.GPSIFD.GPSLongitudeRef] = 'W';

// SEO description in both EXIF fields
exifObj['0th'][piexif.ImageIFD.ImageDescription] = description;

// UCS-2 for Unicode support (Spanish accents, ñ)
const userComment = Buffer.concat([
  Buffer.from('UNICODE\0\0\0', 'ascii'),
  encodeUCS2(description),
]);
exifObj['Exif'][piexif.ExifIFD.UserComment] = userComment.toString('binary');

Stałe GPS

Każdy obraz naprawy dostaje dokładne współrzędne punktu w Sewilli. Google Images używa EXIF GPS do wyników lokalnych.

Podwójny opis

Tekst SEO trafia do ImageDescription (standardowy EXIF) i UserComment (rozszerzony EXIF). Różne parsery czytają różne pola.

Kodowanie UCS-2

Hiszpańskie znaki (akcenty, ñ) wymagają Unicode. Specyfikacja EXIF wymaga UCS-2 z prefiksem UNICODE\0\0\0.

Pipeline obrazów w Airtable
Pipeline obrazów: 1 zdjęcie z GSM Arena → 18 automatycznie złożonych overlayów napraw. Wszystko zsynchronizowane z Business OS.

Kaskada treści: jedna opinia, sześć stron

System automatycznie dziedziczy treść przez taksonomię. Opinia o „naprawie ekranu iPhone 12” nie pojawia się tylko na tej stronie — pokazuje się wszędzie, gdzie jest istotna:

StronaPoziom
/reparar-movil/apple/iphone-12/pantalla/sevillaModel + naprawa + miasto
/reparar-iphone/pantalla/sevillaUrządzenie + naprawa + miasto
/reparar-movil/apple/sevillaUrządzenie + marka + miasto
/reparar-iphone/sevillaUrządzenie + miasto
/reparar-movil/pantalla/sevillaUrządzenie + naprawa + miasto
/reparar-movil/sevillaUrządzenie + miasto

Ta sama logika dotyczy zdjęć before/after: zdjęcie z naprawy ekranu iPhone 12 pojawia się na każdej stronie w tej gałęzi taksonomii. Mnoży unikalną treść bez sztucznego duplikowania ani generowania. Każda strona zbiera więcej social proof i treści wizualnej wraz ze wzrostem firmy.

Ponad 26 000 automatycznie wygenerowanych obrazów. 867 modeli po 18 wariantów. Ponad 10 000 prawdziwych zdjęć napraw. Zero ręcznej interwencji. 12 baz Business OS zasila cały pipeline.

Zobacz skrypty pipeline’u na GitHubie →

Wewnątrz pipeline’u obrazów

Poprzednia sekcja opisuje pipeline na wysokim poziomie. Tu widać dokładnie, jak działa: prawdziwe szablony overlay, kod kompozycji i co się dzieje przy uruchomieniu na 867 różnych modelach.

Szablony overlay

Każdy typ naprawy ma PNG overlay 384×256 px. Overlay wizualnie pokazuje, która część jest naprawiana: pęknięty ekran, bateria, aparat... Łącznie 17 szablonów, każdy zaprojektowany do złożenia na dowolne zdjęcie urządzenia.

Overlay naprawy ekranuOverlay naprawy ekranu — iPhone 14 Pro
Overlay naprawy ekranu
Overlay wymiany bateriiOverlay wymiany baterii — iPad Air 5
Overlay wymiany baterii
Overlay aparatu tylnegoOverlay aparatu tylnego — Pixel 7a
Overlay aparatu tylnego
Overlay portu ładowaniaOverlay portu ładowania — Huawei P30 Pro
Overlay portu ładowania
Overlay tylnej pokrywyOverlay tylnej pokrywy — OnePlus 11
Overlay tylnej pokrywy
Overlay wymiany szkłaOverlay wymiany szkła — Apple Watch Series 7
Overlay wymiany szkła

Proces kompozycji

Każdy obraz naprawy powstaje w 6 krokach, w pełni automatycznie skryptem Node.js i Sharp.js:

1

Pobierz zdjęcie urządzenia

Oficjalne zdjęcie urządzenia jest pobierane z GSM Arena i przechowywane tymczasowo.

2

Utwórz biały canvas 384×256

Sharp.js tworzy pustą bazę 384×256 px z kanałem alfa.

3

Nałóż PNG naprawy

Szablon naprawy (ekran, bateria itd.) jest składany jako pierwsza warstwa na canvasie.

4

Wycentruj urządzenie przy x=96

Zdjęcie urządzenia jest proporcjonalnie skalowane i centrowane przy x=96, zostawiając miejsce na overlay po prawej.

5

Eksport do WebP

Wynik eksportowany jako zoptymalizowany WebP. Każdy obraz waży ~5–8 KB.

6

Powtórz ×17 napraw + hero

Proces powtarza się dla wszystkich 17 typów naprawy plus generyczny hero 256×256. Razem: 18 obrazów na model.

Prawdziwy kod

To prawdziwy fragment z generarImagenesReparacionesModelos.mjs który generuje każdy obraz naprawy:

await sharp({
  create: {
    width: 384, height: 256,
    channels: 4,
    background: { r: 255, g: 255, b: 255, alpha: 1 }
  }
})
  .png()
  .composite([
    { input: overlayPath },
    { input: devicePhoto,
      top: Math.round(top),
      left: Math.round(left) }
  ])
  .webp()
  .toFile(outputPath)

Canvas

Tworzy pusty obraz 384×256 z białym tłem i kanałem alfa. To canvas, na którym wszystko jest składane.

Kolejność kompozycji

Najpierw overlay (szablon naprawy), potem zdjęcie urządzenia. Kolejność ma znaczenie: overlay siedzi za urządzeniem.

Pozycjonowanie

Zdjęcie urządzenia jest centrowane w pionie i ustawione przy x≈96. Zostawia miejsce, by overlay naprawy był widoczny po prawej.

1 zdjęcie → 18 wariantów

Z jednego zdjęcia iPhone 14 Pro pipeline automatycznie generuje 18 unikalnych obrazów: jeden generyczny hero i 17 wariantów naprawy. Każdy wariant składa zdjęcie urządzenia z konkretnym overlayem.

iPhone 14 Pro — automatycznie wygenerowany obraz hero
Obraz hero: zdjęcie iPhone 14 Pro wycentrowane na canvasie 256×256, bez overlay.
Wymiana ekranu iPhone 14 Pro

Wymiana ekranu iPhone 14 Pro

Wymiana baterii iPhone 14 Pro

Wymiana baterii iPhone 14 Pro

Wymiana tylnego aparatu iPhone 14 Pro

Wymiana tylnego aparatu iPhone 14 Pro

Wymiana portu ładowania iPhone 14 Pro

Wymiana portu ładowania iPhone 14 Pro

Wymiana tylnej pokrywy iPhone 14 Pro

Wymiana tylnej pokrywy iPhone 14 Pro

Wymiana szkła iPhone 14 Pro

Wymiana szkła iPhone 14 Pro

Wymiana głośnika iPhone 14 Pro

Wymiana głośnika iPhone 14 Pro

Wymiana mikrofonu iPhone 14 Pro

Wymiana mikrofonu iPhone 14 Pro

Wymiana słuchawki iPhone 14 Pro

Wymiana słuchawki iPhone 14 Pro

9 z 17 automatycznie wygenerowanych wariantów dla iPhone 14 Pro. Każdy obraz składa prawdziwe zdjęcie urządzenia z konkretnym overlayem naprawy.

Ten sam pipeline, inne urządzenie

Ten sam proces działa dla dowolnego urządzenia. Zmienia się zdjęcie, overlaye zostają. Dlatego da się skalować do 867 modeli bez pracy ręcznej.

iPhone 14 Pro — hero
Samsung Galaxy S23 Ultra — hero
Xiaomi 12 — hero
Wymiana ekranu iPhone 14 Pro
Wymiana ekranu Samsung Galaxy S23 Ultra
Ten sam overlay „wymiana ekranu”, inne urządzenie. Szablon jest identyczny — zmienia się zdjęcie modelu.

Skala

867

Modele

Unikalne urządzenia z wygenerowanymi obrazami

17

Overlaye

Szablony napraw (ekran, bateria, aparat...)

18

Obrazy/model

17 napraw + 1 hero na urządzenie

15,606

Kompozycje

Łącznie automatycznie wygenerowanych obrazów

Pipeline opinii

Opinie to najsilniejszy social proof na każdej stronie. Ale zarządzanie setkami profili klientów, synchronizacja dwóch źródeł i kaskadowanie sygnałów zaufania przez całą taksonomię wymaga własnego pipeline’u.

Źródło i synchronizacja

Opinie pochodzą z dwóch źródeł: Google My Business (publicznie zweryfikowane) oraz wewnętrznych ankiet po naprawie. Oba synchronizują się do Airtable i normalizują do jednego formatu.

TabelaŹródłoKluczowe pola
Reseñas sincronizar AstroGoogle My Businessquote, name, rating, imageUrl, response
Reseñas InternasAnkiety po naprawiequote, name, rating, imageUrl, linked model

Przetwarzanie zdjęć profilowych

Każda opinia ze zdjęciem profilowym przechodzi przez zautomatyzowany pipeline:

1

Pobierz zdjęcie z Airtable

URL zdjęcia profilowego jest pobierany z pola załącznika w Airtable.

2

Konwertuj do WebP jakość 95

Sharp.js konwertuje obraz do WebP w jakości 95, by zachować detale twarzy.

3

Zapisz do /bg/res/

Plik zapisywany jest z semantyczną nazwą: reparacion-{type}-{model}-{name}-{date}.webp

4

Zapisz URL z powrotem do Airtable

Wynikowy URL jest zapisywany z powrotem do odpowiadającego pola. Dwukierunkowe ETL.

Prawdziwy kod

To prawdziwy fragment z `generarImagenesReseñas.mjs`, który przetwarza każde zdjęcie profilowe:

const imageBuffer = await fetch(attachmentUrl)
  .then(r => r.arrayBuffer())

await sharp(Buffer.from(imageBuffer))
  .webp({ quality: 95 })
  .toFile(outputPath)

// Write processed URL back to Airtable
await base('Reseñas sincronizar Astro')
  .update(record.id, {
    'imagen_procesada': outputUrl
  })

Zachowanie wymiarów

Bez skalowania — zdjęcia profilowe zachowują oryginalne wymiary dla maksymalnej jakości w karuzeli.

Jakość WebP 95

Wyższa jakość niż przy zdjęciach napraw (85), bo zdjęcia profilowe są mniejsze, a detale mają większe znaczenie.

Dwukierunkowe ETL

Airtable jest jednocześnie źródłem I celem: zdjęcie jest pobierane, przetwarzane, a wynikowy URL wraca do rekordu.

Kaskada social proof

Opinie nie pojawiają się tylko na jednej stronie — dziedziczą się przez całą taksonomię. Opinia powiązana z modelem propaguje się na każdą stronę, gdzie ten model jest istotny.

Opinia „iPhone 14 Pro” → pojawia się na każdej stronie naprawy tego modelu, w każdym mieście

Opinia rodziny „iPhone 14” → pojawia się na wszystkich modelach rodziny (14, 14 Plus, 14 Pro, 14 Pro Max)

Opinia marki „Apple” → pojawia się na zagregowanych stronach marki, np. /reparar-movil/apple/sevilla

Kaskada jest automatyczna: powiąż opinię z właściwym poziomem, a build ją rozdystrybuuje

Setki przetworzonych profili

Prawdziwe profile klientów przetworzone przez pipeline. Każde zdjęcie pobrano, skonwertowano do WebP i powiązano z powrotem z Airtable.

Victor — naprawa ekranu Samsung Galaxy A70
Sarah — iPhone 11 earpiece repair
Cristina — iPhone 12 earpiece repair
Ricardo — Google Pixel 4 battery replacement
Manolo — iPhone 11 Pro Max battery repair
Fernando — iPad 5 touch repair
Susana — iPhone XS screen repair
Teresa — iPhone 8 Plus screen repair
Luisa — iPhone 6 Plus battery repair

Prawdziwe profile klientów. Każde zdjęcie jest pobierane, konwertowane do WebP i powiązywane z powrotem z Airtable.

Na produkcji opinie renderują się w karuzeli z auto-rotacją co 9 s, wizualnym paskiem postępu i nawigacją kropkami. Top 20 opinii widać od razu; reszta rozwija się pod przyciskiem „Pokaż więcej”. Wszystko server-rendered — zero JavaScriptu dla bazowej karuzeli.

CRO carousel with real reviews 1/5

1 / 5

Automatyczny filtr: najpierw pojawiają się tylko opinie ≥5★ z napisanym komentarzem. Opinie bez tekstu lub poniżej 5 gwiazdek lądują poniżej foldu.

Skala

600+

Przetworzone profile

Zdjęcia profilowe skonwertowane do WebP

2

Źródła

Google My Business + ankiety wewnętrzne

9s

Rotacja

Interwał auto-rotacji karuzeli CRO

≥5★

Priorytet

Najpierw opinie 5★ z komentarzem

Pipeline before/after

Każda ukończona naprawa generuje dowód fotograficzny: 4 zdjęcia dokumentujące stan urządzenia przed i po. Ten pipeline przetwarza je automatycznie i rozsyła po serwisie.

Protokół zdjęć

Każda ukończona naprawa w punkcie ma protokół 4 zdjęć:

1

Front przed

Zdjęcie frontu urządzenia przed naprawą. Pokazuje widoczne uszkodzenia (pęknięty ekran, ślady itd.).

2

Front po

Zdjęcie frontu po naprawie. Ten sam kąt do bezpośredniego porównania.

3

Tył przed

Zdjęcie tyłu przed naprawą. Dokumentuje ogólny stan urządzenia.

4

Tył po

Zdjęcie tyłu po naprawie. Domknięcie dokumentacji wizualnej.

Flaga `difuminar` w Airtable oznacza zdjęcia wymagające rozmycia: ekrany z powiadomieniami, danymi osobowymi itd. Rozmycie nakładane jest automatycznie w pipeline.

Automatyczne przetwarzanie

Każde zdjęcie przechodzi 6 kroków przetwarzania Sharp.js:

1

Pobierz z Airtable

Oryginalne zdjęcie pobierane jest z pola załącznika rekordu naprawy.

2

Skaluj do rozdzielczości 1/4

Obraz skalowany do 25% oryginalnego rozmiaru. Wystarczy na web, dramatycznie tnie wagę pliku.

3

Warunkowe rozmycie (sigma 8)

Jeśli flaga `difuminar` jest ustawiona, nakładany jest Gaussian blur sigma 8. Chroni dane osobowe widoczne na ekranie.

4

Półprzezroczysty biały overlay

Warstwa 30% bieli jest składana na tle dla spójnego kontrastu i czystego wyglądu.

5

Eksport do WebP jakość 85

Jakość 85 — niższa niż przy zdjęciach profilowych (95), bo przy rozdzielczości 1/4 dodatkowy detal i tak nie jest zauważalny.

6

Zapisz slug z powrotem

Przetworzona nazwa pliku wraca do Airtable, żeby build Astro mógł ją znaleźć.

Prawdziwy kod

To prawdziwy fragment z CasosExito.mjs który przetwarza każde zdjęcie naprawy:

let pipeline = sharp(inputBuffer)
  .resize({
    width: Math.round(metadata.width / 4),
    height: Math.round(metadata.height / 4)
  })

if (record.fields.difuminar) {
  pipeline = pipeline.blur(8)
}

await pipeline
  .composite([{
    input: whiteOverlay,
    blend: 'over'
  }])
  .webp({ quality: 85 })
  .toFile(outputPath)

Skalowanie 1/4

Skaluje do 1/4. Zdjęcie 4032×3024 staje się 1008×756 — idealne na web, waga spada z ~3 MB do ~30 KB.

Warunkowe rozmycie

Stosowane tylko, gdy pole `difuminar` jest ustawione w Airtable. Sigma 8 rozmywa powiadomienia i dane osobowe na ekranie.

Jakość 85 vs 95

Niższa jakość niż przy zdjęciach profilowych, bo przy rozdzielczości 1/4 dodatkowy detal nie dodaje wartości. Oszczędza ~40% wagi na obraz.

Prawdziwy wynik: iPhone 14 Pro

To prawdziwe zdjęcia przetworzone przez pipeline. Front i tył, przed i po naprawie.

iPhone 14 Pro front — before repair
iPhone 14 Pro front — after repair
iPhone 14 Pro — front przed i po
iPhone 14 Pro back — before repair
iPhone 14 Pro back — after repair
iPhone 14 Pro — tył przed i po

Ten sam pipeline, różne marki

Pipeline działa tak samo dla każdej marki i modelu. Tu zastosowany do Samsung Galaxy A51 i Xiaomi Redmi Note 9S.

Samsung Galaxy A51 — before repair
Samsung Galaxy A51 — after repair
Samsung Galaxy A51 — przed i po
Xiaomi Redmi Note 9S — before repair
Xiaomi Redmi Note 9S — after repair
Xiaomi Redmi Note 9S — przed i po

Ten sam pipeline przetwarzania dla każdej marki. Zdjęcia są pobierane, skalowane, w razie potrzeby rozmywane i automatycznie eksportowane do WebP.

Skala

10,342

Przetworzone zdjęcia

Prawdziwe zdjęcia napraw skonwertowane do WebP

4

Kąty

Front przed/po + tył przed/po

1/4

Rozdzielczość

Przeskalowane do 25% oryginału pod web

Q85

Jakość WebP

Zoptymalizowana jakość zdjęć napraw

Krzywa wzrostu

Start w październiku 2024. Pierwsze miesiące to czysty momentum indeksacji. Po początkowym szczycie w styczniu ruch wypłaszczył się od lutego do czerwca — i to nie była sezonowość. To była restrukturyzacja: oryginalna wersja generowała strony krajowe i lokalne dla każdej kombinacji, ale było ich za dużo, a Google wyraźnie faworyzował intencję lokalną. Przekierowałem strony krajowe na lokalne odpowiedniki /sevilla, zostawiając w formacie krajowym tylko niszowe naprawy (np. /cambiar-bateria-iphone-11), gdzie specyfika waży więcej niż brak lokalizacji. Dopóki Google reindeksował nową strukturę, ruch stał w miejscu. Po konsolidacji wzrost ruszył znowu — szczyt we wrześniu 2025: 2193 kliknięcia.

Growth curve in Google Search Console — clicks and impressions
Google Search Console: kliknięcia (niebieski) i wyświetlenia (fiolet) od listopada 2024 do września 2025.
MiesiącKliknięciaWyświetlenia
Oct 202420216,420Start
Nov 202474869,054
Dec 202494977,387
Jan 20251,277110,836
Feb 2025935100,558Restrukturyzacja krajowe → lokalne
Mar 20251,191118,826
Apr 20251,027106,744
May 202593697,137
Jun 2025996121,088
Jul 20251,611150,927Po restrukturyzacji
Aug 20251,789164,791
Sep 20252,193164,440Szczyt · sprzedaż firmy

Z 202 do 2193 kliknięć/miesiąc w 11 miesięcy. Plateau luty–czerwiec pokrywa się z restrukturyzacją URL z krajowych na lokalne — Google potrzebował czasu na reindeksację nowej architektury. Po konsolidacji ruch skoczył o 62% w jeden miesiąc (cze → lip). System dalej działa u nowego właściciela.

Kamienie milowe Google Search Console

Google świętuje progi ruchu odznakami. W 3 miesiące przeszliśmy z 1,2 tys. do 2 tys. kliknięć miesięcznie — ostatnia odznaka przyszła dokładnie przy domknięciu sprzedaży firmy.

1.2K clicks
1.2K clicksJul 18, 2025
1.5K clicks
1.5K clicksAug 3, 2025
1.8K clicks
1.8K clicksSep 11, 2025
2K clicks
2K clicksSep 22, 2025

Wyniki

Metryki skumulowane od startu (październik 2024 – luty 2026), bezpośrednio z Google Search Console:

19,388

Kliknięcia organiczne

17 miesięcy działania, paź 2024 → lut 2026

1.17%

Średni CTR

Przy 2,26 mln wyświetleń łącznie

4,084

URL-e w sitemapie

Tylko te, które przechodzą silnik decyzji DataForSEO

<1s

Czas ładowania strony

Astro SSG z minimalnym lazy JS + Cloudflare CDN

Ale te wyniki nie wzięły się znikąd. Punktem startu była strona na Squarespace z problemami technicznymi, które trzeba było rozwiązać, zanim dało się zbudować system programmatic.

Punkt startu

Strona firmy przez lata działała na Squarespace. Brak kontroli URL, brak tagów canonical, brak własnych przekierowań. Nadchodziła nie tylko zmiana platformy — potrójna migracja: platforma (Squarespace → Astro), domena (santifer.me → santiferirepair.es) i hosting (Squarespace → Vercel/Cloudflare). Pierwszy krok: udokumentować, co trzeba naprawić — 144-stronicowy audyt techniczny, zrobiony jako Final Master's Project programu Big SEO.

santifer.me on Squarespace: mobile homepage
santifer.me on Squarespace: pricing page with generic icons
santifer.me na Squarespace. Strona główna i cennik: generyczne ikony, brak prawdziwych zdjęć, brak danych ERP.

Squarespace serwował tę samą stronę pod 4 różnymi URL-ami (www, non-www, trailing slash, .html). Google widział 4 kopie każdej strony.

Audyt techniczny

Pierwszym krokiem był pełny audyt techniczny, zrobiony jako Final Master's Project programu Big SEO. 144 strony dokumentujące każdy aspekt techniczny serwisu: od baseline ruchu po ostatni meta description.

23.1

Śr. pozycja

↓ Spadek

Widoczność SISTRIX

21/100

Lighthouse (mobile)

33/40

Elementy z błędami

SISTRIX: organic visibility of santifer.me in constant decline from 2019 to 2024
Indeks widoczności SISTRIX (2019–2024). 5-letni trend spadkowy, z 0,036 do 0,003.
Google Search Console: organic clicks halving over 12 months
SISTRIX: sector visibility comparison in Spain — santifer.me invisible vs competitors
Lewa: GSC pokazuje połowę kliknięć (17,3 tys. kliknięć, średnia pozycja 23,1). Prawa: porównanie sektora — santifer.me to czerwona linia przyklejona do osi X.

838 zduplikowanych H1

Szablon Squarespace wstrzykiwał ukryte H1 na każdej stronie, duplikując główny nagłówek. Google widział dwa tytuły walczące o relevance.

1015 kanibalizacji

Strony konkurujące ze sobą o te same słowa kluczowe. Home, kategorie i modele wchodziły sobie w drogę w wynikach.

869 błędów structured data

Schema LocalBusiness nie trzymała się rekomendacji schema.org. Google nie mógł poprawnie zinterpretować informacji o firmie.

831 stron non-canonical

Squarespace serwował 4 URL-e na stronę bez przekierowania na canonical. GSC raportował je jako duplikaty bez canonical.

33 z 40 audytowanych aspektów technicznych miało błędy. Tylko 7 przeszło. Audyt nie tylko zdiagnozował problemy — stał się roadmapą całego projektu.

Screaming Frog: 838 stron z wieloma H1, 118 duplicates, 255 without H2
Screaming Frog: 838 stron z wieloma H1
Screaming Frog: 8,000+ images without size attributes, 497 too heavy, 164 without alt text
Screaming Frog: ponad 8000 obrazów bez wymiarów

Dług techniczny

Brak tagów canonical

www vs non-www, z/bez trailing slash, z/bez .html. Ta sama strona, 4 URL-e. 831 stron non-canonical w GSC. Squarespace ustawiał canonical, ale nie przekierowywał.

Brak własnych przekierowań

Squarespace nie pozwala na własne 301. 266 historycznych URL-i zwracających 404 w GSC. Niemożliwe mapowanie starych URL-i na nową strukturę.

Brak kontroli slugów URL

Taksonomia biznesowa już istniała, ale Squarespace generował redundantne URL-e typu /reparar-iphone/reparar-iphone-x. 15 URL-i powyżej 115 znaków, 10 z wielkimi literami, słowo kluczowe powtórzone 3 razy.

Ryzyko duplicate content

Wykryto 1015 kanibalizacji. 79 stron z thin content. Warianty URL bez canonical wysyłały mylące sygnały do Google, rozwadniając autorytet domeny.

Repair page on Squarespace: generic icons and unstructured pricing
Typowa strona naprawy na Squarespace. Generyczne ikony, brak prawdziwych zdjęć, brak JSON-LD, brak danych ERP.
StronaSpeed Insights: Lighthouse 21 on mobile, 51 on desktop. Core Web Vitals: Not passed across all page types
Przed: Squarespace. Lighthouse 21/100 mobile. CWV niezaliczone.
StronaSpeed Insights: Lighthouse 97 on mobile, Dostępność 100, SEO 100. Core Web Vitals: Passed
Po: Astro + Cloudflare. Lighthouse 97/100 mobile. CWV zaliczone. Sprawdź sam →

Migracja

1

Pełny crawl Screaming Frog

Crawl wykazał 838 stron z wieloma H1, 266 URL-i z 404 i 1015 kanibalizacji. Mapowanie dało 1009 reguł przekierowań.

2

Nowa struktura URL w Astro

Z ~80 stron do architektury 480+ stron zoptymalizowanej pod 156 000 miesięcznych wyszukiwań transakcyjnych. Czyste URL-e: /reparar-{device}/, /reparar-{brand}/{model}/.

3

Przekierowania 301 w vercel.json

Dedykowany projekt (servidor-redirecciones) wdrożony na Vercel wyłącznie do serwowania 301. 190 KB konfiguracji w jednym pliku.

4

Przekierowania wg intencji

Przekierowanie stron krajowych na lokalne. Przykład: /reparar-movil/reparar-samsung → /reparar-movil/samsung/sevilla.

Serwer przekierowań

Potrójna migracja (platforma, domena, hosting) wymagała planu ochrony autorytetu zgromadzonego na starej domenie. Rozwiązaniem był dedykowany projekt Vercel, którego jedynym celem było serwowanie 301. Haczyk zmiany domeny: Squarespace nie pozwalał przekierować homepage, co blokowało change of address w GSC. Podwójny hop HTTP→308→301 uniemożliwiał walidację. Naprawione w jedno popołudnie: Vercel Redirect Domain + Cloudflare Redirect Rules dla jednego bezpośredniego 301.

1,009

Reguły przekierowań

190 KB

vercel.json

4

Warstwy przekierowań

46

Commitów w 7 miesięcy

Model → model

/reparar-movil/reparar-samsung/reparar-samsung-galaxy-a12 → /reparar-movil/samsung/galaxy-a12. Clean URL, same intent.

Marka → marka + miasto

/reparar-movil/reparar-realme → /reparar-movil/realme/sevilla. The new structure added the city as a local signal.

Wildcard + catch-all

Każdy URL nie zmapowany w poprzednich warstwach przekierowuje na homepage. Zero 404 dla użytkowników i dla Google.

Cały projekt Vercel wyłącznie do przekierowań. 1009 reguł zmapowanych ręcznie, bo struktura URL Squarespace nie miała jednolitego wzorca.

Wdróż przekierowania przed zgłoszeniem zmiany adresu w Google Search Console. Nie po. Kolejność ma znaczenie.

Koszt migracji

Każda migracja ma koszt przejścia. Ponad 800 stron potrzebowało czasu na reindeksację, a kluczowe słowa chwilowo spadły — „reparar iphone sevilla” z top 2 na pozycję 6. To było oczekiwane: Google potrzebuje czasu na ponowną ocenę domeny po change of address. Odbicie przyszło.

100

Wydajność

92

Dostępność

96

Dobre praktyki

100

SEO

AHREFs sector comparison: santifer.me with DR 0.1 and 23 backlinks vs competitors with thousands
Porównanie siły domeny (AHREFs). santifer.me: DR 0,1, 23 backlinki. Lider sektora (iriparo.com): DR 44, 21 430 backlinków.

Z Lighthouse 21 na Squarespace do 100 na Astro. Z DA 8 do konkurencji na rynku, gdzie liderzy mają 100× więcej ruchu. Audyt techniczny udokumentował 33 problemy; migracja rozwiązała je wszystkie naraz.

Stack i narzędzia

Stack dobrano pod konkretną potrzebę: generowanie tysięcy stron statycznych z relacyjnego CMS, z minimalnym JS po stronie klienta. Astro było oczywistym wyborem pod czyste SSG. Airtable działał jako CMS, bo już był Business OS firmy — migracja na Supabase pod statyczny serwis nie miała sensu. DataForSEO wybrano za cenę i pokrycie hiszpańskich słów kluczowych.

Astro

SSG, 21 szablonów, minimalny lazy JS

Airtable

Headless CMS, 14 tabel, ~60 pól/tabelę

DataForSEO

DataForSEO

Wolumeny wyszukiwań, pole „indexable”

Własny ERP

867 modeli, ceny, stock, zdjęcia, opinie

Cloudflare

CDN, cache edge, deploy

TypeScript

1677-liniowy schema.ts do mapowania

JSON-LD

6 typów structured data na stronę

Wnioski

1

Intencję użytkownika decyduje Google, nie Ty.

Chciałem rankować ogólnokrajowo. Google miał inne plany — odczytał wyszukiwania napraw jako silnie lokalne. Strony bez miasta zostały zmiażdżone przez te z Sewillą. Wniosek: zbuduj pełną infrastrukturę, ale niech dane GSC powiedzą, gdzie podwoić stawkę.

2

Silnik decyzji liczy się bardziej niż generator.

Wygenerowanie 10 000 stron jest trywialne. Decyzja, które indeksować na podstawie realnych danych DataForSEO — to oddziela pSEO z wynikami od farmy thin content. Ze wszystkich możliwych kombinacji tylko 4084 trafiło do sitemapy.

3

ERP jest moatem, nie szablon.

Każdy może postawić strony z AI. Nikt nie wygeneruje prawdziwych zdjęć before/after, zweryfikowanych opinii, podwójnych cen (oryginał i kompatybilne) oraz czasów realizacji z danych historycznych bez zintegrowanego ERP. Unikalna treść nie bierze się z copy — bierze się z danych.

4

Airtable skaluje się lepiej, niż się spodziewasz.

14 tabel, ~60 pól na tabelę, hierarchia 6 poziomów. Z retry i exponential backoff na API build zostaje stabilny. Sztuczka: cache’uj opinie i pomijaj zbędne wywołania. Dla jednoosobowego zespołu Airtable jako headless CMS po prostu działa.

5

Krajowe URL-e niszowe dają najlepszy CTR.

Format /cambiar-bateria-google-pixel-6a daje CTR 5,0% przy średniej pozycji 7,8. Te zapytania są tak konkretne, że mają prawie zerową konkurencję. Pojedynczy wolumen jest niski, ale pomnożony przez setki modeli szybko się sumuje.

6

Treść generowana bez danych produkcyjnych to thin content z lepszą gramatyką.

Różnica między pSEO, które działa, a farmą treści to nie szablon ani AI — tylko to, czy dane są realne. Ceny z ERP, prawdziwe zdjęcia napraw, zweryfikowane opinie. Ten wzorzec dotyczy każdej firmy z danymi operacyjnymi: e-commerce, marketplace’y, SaaS katalogowe.

7

Taksonomia biznesu JEST Twoją architekturą informacji — nie wymyślaj jej, zmapuj ją.

Nie projektowałem struktury URL od zera. Zmapowałem hierarchię, która już istniała w biznesie: typ → marka → model → naprawa → miasto. Business OS miał już tę taksonomię w Airtable. Serwis programmatic po prostu wystawił ją światu. Jeśli Twoja firma ma już wewnętrzną ontologię — użyj jej.

Co to pokazuje

Projekt systemu end-to-end

Od danych ERP do stron produkcyjnych — relacyjny CMS, pipeline budowy, silnik decyzji, optymalizacja crawl budget.

Automatyzacja skalująca się bez interwencji

Jedna osoba, 4730 stron, ponad 26 000 obrazów. System działał dalej po sprzedaży firmy.

Decyzje data-driven, nie na czuja

DataForSEO jako silnik indeksacji. Google Search Console jako pętla feedbacku. Każda decyzja oparta o realne metryki.

Pełna realizacja w realnym kontekście biznesowym

To nie projekt portfolio ani tutorial. To system produkcyjny, który napędzał realny ruch realnej firmy — i przyczynił się do jej sprzedaży.

Ten sam ERP zasila agenta AI

Dane Airtable generujące te ponad 4700 stron są też odpytywane przez Jacobo, omnichannelowego agenta AI obsługującego WhatsApp i telefon. To samo źródło prawdy, dwa kanały pozyskania.

Przeczytaj case study Jacobo →

Projektuję systemy, które zamieniają dane operacyjne w przewagę konkurencyjną.

To case study pokazuje wzorzec, który stosuję wielokrotnie: zmapuj ontologię biznesu, zbuduj pipeline data-to-deploy i mierz wszystko realnymi metrykami. Obecnie rozglądam się za rolami AI Product Manager i Solutions Architect — jeśli Twój zespół potrzebuje kogoś, kto myśli systemami i dowozi na produkcję, pogadajmy.

Napisz

FAQ

Czy programmatic SEO to nie spam?

Tylko jeśli strony nie dodają wartości. Tutaj każda ma realne dane usługi: aktualne ceny (części oryginalne i kompatybilne), czas realizacji z danych historycznych, zdjęcia before/after z prawdziwych napraw i zweryfikowane opinie klientów. To nie wypełniacz z AI — to dane produkcyjne z ERP.

Czy to działa tylko w Sewilli?

Strony lokalne skupiają się na Sewilli, bo tam jest fizyczny punkt, a Google faworyzuje wyniki blisko użytkownika przy wyszukiwaniach napraw. Strony krajowe (format /cambiar-{part}-{brand}-{model}) działają bez limitu geograficznego i łapią niszowe zapytania w całej Hiszpanii.

Dlaczego nie treści generowane AI?

Bo moatem są realne dane. Ceny z ERP, zdjęcia z prawdziwych napraw, opinie od zweryfikowanych klientów. Strona z AI może brzmieć dobrze, ale nie stoi za nią dane produkcyjne. Blog korzystał z AI do pisania, w parze z NotebookLM do odcinka podcastu przy każdym artykule.

Czy Airtable skaluje się przy ponad 4700 stronach?

Tak, z zastrzeżeniami. 14 tabel i ~60 pól na tabelę dobrze działa z pipeline’em budowy (nie z zapytaniami real-time). Klucz: retry z exponential backoff na API oraz cache często używanych danych, jak opinie. Przy żywych zapytaniach i większej skali warto rozważyć alternatywy typu Supabase.

Jak utrzymujecie strony na bieżąco?

Gdy zmienia się cena lub dodawany jest model w ERP, dane synchronizują się do Airtable. Kolejny build regeneruje dotknięte strony. Nowe opinie propagują się automatycznie przez kaskadę rodzina–model. Zero ręcznej pracy nad treścią.

Dlaczego Astro zamiast Next.js?

Dla w pełni statycznego serwisu, gdzie treść zmienia się rzadko, Astro oddaje czysty HTML z minimalnym JavaScriptem — tylko interaktywne komponenty jak wyszukiwarka i karuzela, ładowane lazy. Strony ładują się poniżej sekundy, Core Web Vitals są dobre od razu, a deploy na Cloudflare CDN jest banalnie prosty.

Co dokładnie robi DataForSEO?

DataForSEO dostarcza realny wolumen wyszukiwań dla każdego słowa kluczowego. Wynik trafia do pola „indexable” w Airtable. Jeśli kombinacja urządzenie + naprawa + miasto nie ma wolumenu, strona powstaje, ale z tagiem noindex. To silnik decyzji, który chroni przed rozwadnianiem autorytetu domeny stronami, które Google i tak zignoruje.

Zasoby