▸ // rozdziały lekcji

Wchodzisz na stronę PageSpeed Insights, wklejasz adres, czekasz, spisujesz wynik. Potem przełączasz na komputer i spisujesz drugi. Następny adres. Przy 235 podstronach nikt tego nie robi, więc mierzy się stronę główną i zgaduje, że reszta wygląda podobnie.
Ten workflow bierze adresy z tabeli z serii NawiSEO, mierzy każdy dwa razy, na telefonie i na komputerze, i wpisuje oba wyniki obok adresu. Po kilku uruchomieniach widzisz w jednej tabeli, które podstrony ciągną serwis w dół.
Co robi ten workflow
- Uruchom recznie - start przyciskiem Execute workflow.
- Ustawienia - jedno pole,
ile_na_raz(5). - Przygotuj tabele - Data Table z operacją Create zakłada
nawiseo_adresy, jeśli jej nie ma. - Adresy bez pomiaru - Data Table z operacją Get bierze 5 adresów z pustą kolumną
psi_mobile. - PageSpeed mobile - HTTP Request do PageSpeed Insights API z
strategy=mobile. Klucz API bierze z poświadczenia. - Wynik mobile - Edit Fields zamienia ocenę na liczbę 0-100, a nieudany pomiar na -1.
- PageSpeed desktop - to samo zapytanie z
strategy=desktop. - Wyniki razem - Edit Fields składa adres i oba wyniki w jeden item.
- Zapisz wyniki - Data Table z operacją Update wpisuje
psi_mobileipsi_desktopw wiersz z tym samymurl.
Czego potrzebujesz
- adresów w tabeli
nawiseo_adresy. Wpisuje je NawiSEO 1 - parser sitemap XML, - klucza API do PageSpeed Insights z Google Cloud Console.
Dokumentacja API traktuje klucz jako opcjonalny. W praktyce jest wymagany. Mój test bez klucza od razu zwrócił „The service is receiving too many requests from you" i nic się nie zmierzyło.
Klucz robisz w Google Cloud Console: włączasz w projekcie PageSpeed Insights API i tworzysz klucz API.
W n8n klucz trzymasz w poświadczeniu typu Query Auth. To ogólne poświadczenie, które dopisuje do każdego zapytania jeden parametr w adresie. W polu Name wpisujesz key, w polu Value swój klucz. Poświadczenia nie trafiają do eksportu JSON, więc plik workflow możesz komuś wysłać bez wycinania klucza. Klucz i poświadczenie krok po kroku pokazuję w lekcji Credentials z kluczem API Google (wkrótce).
Jak uruchomić
- Zaimportuj plik z tej lekcji (jak importować workflow).
- W Overview, zakładka Credentials, załóż poświadczenie Query Auth: Name
key, Value twój klucz. - W obu węzłach PageSpeed (mobile i desktop) wybierz to poświadczenie. Authentication jest już ustawione na Generic Credential Type, typ Query Auth.
- Kliknij Execute workflow.
- Otwórz tabelę
nawiseo_adresy(Overview, zakładka Data tables) i sprawdź kolumnypsi_mobileipsi_desktopdla pięciu adresów. - Uruchamiaj ponownie, aż wszystkie adresy mają wynik. Każde uruchomienie bierze następną piątkę, bo zmierzone adresy mają już wypełnione
psi_mobile.

Kolejka po pustej kolumnie
Węzeł Adresy bez pomiaru ma jeden warunek: psi_mobile jest puste. Limit bierze z Ustawień. Ten sam patent co w NawiSEO 2: pusta kolumna robi za kolejkę, a zapis wyniku zdejmuje adres z kolejki.
Chcesz zmierzyć wszystko od nowa po zmianach na stronie - wyczyść kolumnę psi_mobile. Chcesz powtórzyć jeden adres - wyczyść jedną komórkę.
Zapytanie do PageSpeed
Oba węzły HTTP Request wysyłają GET na https://www.googleapis.com/pagespeedonline/v5/runPagespeed z trzema parametrami:
| Parametr | Wartość |
|---|---|
| url | {{ $('Adresy bez pomiaru').item.json.url }} |
| strategy | mobile albo desktop |
| category | performance |
Czwarty parametr, key, dokłada poświadczenie Query Auth. Nie widzisz go w liście parametrów i dobrze, bo nie siedzi w workflow.
Sprawdziłem, że klucz faktycznie idzie w zapytaniu: z fałszywym kluczem w poświadczeniu Google odpowiedział błędem 400 „API key not valid. Please pass a valid API key.".
Ustawienia węzła są dobrane pod wolne API:
- Timeout 120 sekund. Pomiar PageSpeed to uruchomienie Lighthouse na serwerach Google i trwa dłużej niż zwykłe zapytanie,
- Batching 1 zapytanie na sekundę, żeby nie wysyłać pięciu naraz,
- Retry On Fail 3 próby co 5 sekund, bo pojedynczy pomiar potrafi się nie udać,
- On Error ustawione na Continue. Jeśli pomiar nie wyjdzie nawet po trzech próbach, workflow nie staje, tylko idzie dalej z odpowiedzią błędu.

Skąd liczba 0-100
Odpowiedź PageSpeed to długi JSON z pełnym raportem Lighthouse. Z całości bierzemy jedno pole:
{{ $json.lighthouseResult ? Math.round($json.lighthouseResult.categories.performance.score * 100) : -1 }}API podaje ocenę jako ułamek od 0 do 1. Mnożymy przez 100 i zaokrąglamy, więc w tabeli masz 87 zamiast 0.87, tak jak w interfejsie PageSpeed.
Pierwsza część, przed znakiem zapytania, sprawdza, czy w odpowiedzi w ogóle jest raport. Po nieudanym pomiarze go nie ma, bo węzeł PageSpeed przepuścił dalej błąd. Wtedy wyrażenie zwraca -1. W teście z fałszywym kluczem tak właśnie wyszło: w tabeli psi_mobile = -1 i psi_desktop = -1, a pozostałe adresy z piątki poszły dalej.
Wynik mobile trzeba zapamiętać, zanim pójdzie zapytanie desktop, bo ono nadpisuje $json. Dlatego jest osobny węzeł Wynik mobile, a Wyniki razem sięga do niego po nazwie: $('Wynik mobile').item.json.psi_mobile. Adres bierze z Adresy bez pomiaru. n8n pamięta, z którego itemu co powstało, więc wyniki trafiają do właściwych adresów.

Pro-tip. Na telefonie wynik jest zwykle niższy niż na komputerze. Google ocenia strony głównie po wersji mobilnej, więc sortuj tabelę po
psi_mobile, nie popsi_desktop. Sam desktop potrafi uśpić czujność.
Haczyk. Adres z -1 nie wraca do kolejki, bo
psi_mobilenie jest już puste. Traktuj -1 jako punkt do sprawdzenia, nie jako wynik. Posortuj tabelę popsi_mobilerosnąco, -1 będą na górze. Otwórz taki adres w przeglądarce albo w historii wykonań zobacz, co odpowiedział Google. Żeby zmierzyć go ponownie, wyczyść komórkępsi_mobile. Jeśli -1 masz przy wszystkich adresach naraz, winny jest raczej klucz niż strona.
Co sprawdziłem, a czego nie
Bez klucza API dostałem odmowę. Z fałszywym kluczem w Query Auth dostałem błąd 400 i zapis -1 w obu kolumnach, więc poświadczenie i obsługa błędu działają. Z prawdziwym kluczem tego workflow nie testowałem, więc pełnego przebiegu z prawdziwymi pomiarami nie zrobiłem. Przeliczenie oceny, złożenie wyników i update po url sprawdziłem na przykładowej odpowiedzi PageSpeed. Jeśli po wklejeniu klucza coś nie zadziała, pierwsze miejsce do sprawdzenia to odpowiedź węzła PageSpeed mobile.
Kiedy tego nie używać
Do diagnozy, co konkretnie spowalnia stronę. Tabela dostaje sam wynik, bez listy zaleceń. Po szczegóły wejdziesz do raportu w przeglądarce, ale już wiesz, które adresy otworzyć najpierw.
Podsumowanie
Pusta kolumna psi_mobile robi za kolejkę, każde uruchomienie mierzy pięć adresów na telefonie i komputerze, a wynik 0-100 ląduje obok adresu. Nieudany pomiar zapisuje się jako -1 i nie blokuje reszty. Klucz API siedzi w poświadczeniu Query Auth, więc nie wycieka z eksportem.
W ostatniej lekcji serii, NawiSEO X1 - nowe meta tagi z AI (wkrótce), model Gemini przygotuje propozycje nowego title, description i H1 dla podstron z tabeli.
Pokaż JSON do skopiowania - nawiseo-pagespeed-insights.json
{
"name": "NawiSEO 6 - PageSpeed Insights do tabeli",
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
0,
0
],
"id": "8fd8660d-7cba-a01e-49c3-96d4c62f0832",
"name": "Uruchom recznie"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "ac00a6d3-ea99-8faf-5a6d-106e4fe95fc2",
"name": "ile_na_raz",
"value": "5",
"type": "number"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
220,
0
],
"id": "6f9fddd0-9c4f-f3e0-6405-de43005261fd",
"name": "Ustawienia"
},
{
"parameters": {
"resource": "table",
"operation": "create",
"tableName": "nawiseo_adresy",
"columns": {
"column": [
{
"name": "url",
"type": "string"
},
{
"name": "domena",
"type": "string"
},
{
"name": "sitemap",
"type": "string"
},
{
"name": "status_http",
"type": "number"
},
{
"name": "title",
"type": "string"
},
{
"name": "title_dl",
"type": "number"
},
{
"name": "description",
"type": "string"
},
{
"name": "description_dl",
"type": "number"
},
{
"name": "h1",
"type": "string"
},
{
"name": "h1_ilosc",
"type": "number"
},
{
"name": "sprawdzono",
"type": "date"
},
{
"name": "nowy_title",
"type": "string"
},
{
"name": "nowy_description",
"type": "string"
},
{
"name": "nowy_h1",
"type": "string"
},
{
"name": "gsc_status",
"type": "string"
},
{
"name": "gsc_ostatni_crawl",
"type": "string"
},
{
"name": "psi_mobile",
"type": "number"
},
{
"name": "psi_desktop",
"type": "number"
}
]
},
"options": {
"createIfNotExists": true
}
},
"type": "n8n-nodes-base.dataTable",
"typeVersion": 1.1,
"position": [
440,
0
],
"id": "71b469f6-aaf8-86df-92c1-fbb2e4332f63",
"name": "Przygotuj tabele"
},
{
"parameters": {
"operation": "get",
"dataTableId": {
"__rl": true,
"value": "nawiseo_adresy",
"mode": "name"
},
"returnAll": false,
"matchType": "allConditions",
"filters": {
"conditions": [
{
"keyName": "psi_mobile",
"condition": "isEmpty"
}
]
},
"limit": "={{ $('Ustawienia').item.json.ile_na_raz }}"
},
"type": "n8n-nodes-base.dataTable",
"typeVersion": 1.1,
"position": [
660,
0
],
"id": "463c7636-f606-78af-a8a5-30eb0778e857",
"name": "Adresy bez pomiaru"
},
{
"parameters": {
"url": "https://www.googleapis.com/pagespeedonline/v5/runPagespeed",
"authentication": "genericCredentialType",
"genericAuthType": "httpQueryAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "url",
"value": "={{ $('Adresy bez pomiaru').item.json.url }}"
},
{
"name": "strategy",
"value": "mobile"
},
{
"name": "category",
"value": "performance"
}
]
},
"options": {
"batching": {
"batch": {
"batchSize": 1,
"batchInterval": 1000
}
},
"timeout": 120000
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
880,
0
],
"id": "26688109-f72f-4bc7-0523-75cba6c3c2f5",
"name": "PageSpeed mobile",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 5000,
"onError": "continueRegularOutput"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "41eb73f5-64a0-7fc7-5e32-17899f73ac46",
"name": "psi_mobile",
"value": "={{ $json.lighthouseResult ? Math.round($json.lighthouseResult.categories.performance.score * 100) : -1 }}",
"type": "number"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1100,
0
],
"id": "0f8cc0e9-1fa0-2fa3-974e-018ceee7bc1a",
"name": "Wynik mobile"
},
{
"parameters": {
"url": "https://www.googleapis.com/pagespeedonline/v5/runPagespeed",
"authentication": "genericCredentialType",
"genericAuthType": "httpQueryAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "url",
"value": "={{ $('Adresy bez pomiaru').item.json.url }}"
},
{
"name": "strategy",
"value": "desktop"
},
{
"name": "category",
"value": "performance"
}
]
},
"options": {
"batching": {
"batch": {
"batchSize": 1,
"batchInterval": 1000
}
},
"timeout": 120000
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
1320,
0
],
"id": "66c52093-533e-1826-8f01-d541fb5cb3b6",
"name": "PageSpeed desktop",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 5000,
"onError": "continueRegularOutput"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "8dad5b4b-7969-942c-8246-f50fc2399ef8",
"name": "url",
"value": "={{ $('Adresy bez pomiaru').item.json.url }}",
"type": "string"
},
{
"id": "d5cbc4f6-66cf-93f6-06d2-58360e19eda6",
"name": "psi_mobile",
"value": "={{ $('Wynik mobile').item.json.psi_mobile }}",
"type": "number"
},
{
"id": "623b5cd8-1997-ab41-c80c-e37ccb71aa8b",
"name": "psi_desktop",
"value": "={{ $json.lighthouseResult ? Math.round($json.lighthouseResult.categories.performance.score * 100) : -1 }}",
"type": "number"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1540,
0
],
"id": "31c59081-3012-9bd8-4c6c-af4f78953a8b",
"name": "Wyniki razem"
},
{
"parameters": {
"operation": "update",
"dataTableId": {
"__rl": true,
"value": "nawiseo_adresy",
"mode": "name"
},
"matchType": "allConditions",
"filters": {
"conditions": [
{
"keyName": "url",
"condition": "eq",
"keyValue": "={{ $json.url }}"
}
]
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"psi_mobile": "={{ $json.psi_mobile }}",
"psi_desktop": "={{ $json.psi_desktop }}"
},
"matchingColumns": [],
"schema": [
{
"id": "url",
"displayName": "url",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"readOnly": false,
"removed": true
},
{
"id": "domena",
"displayName": "domena",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"readOnly": false,
"removed": true
},
{
"id": "sitemap",
"displayName": "sitemap",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"readOnly": false,
"removed": true
},
{
"id": "status_http",
"displayName": "status_http",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"readOnly": false,
"removed": true
},
{
"id": "title",
"displayName": "title",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"readOnly": false,
"removed": true
},
{
"id": "title_dl",
"displayName": "title_dl",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"readOnly": false,
"removed": true
},
{
"id": "description",
"displayName": "description",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"readOnly": false,
"removed": true
},
{
"id": "description_dl",
"displayName": "description_dl",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"readOnly": false,
"removed": true
},
{
"id": "h1",
"displayName": "h1",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"readOnly": false,
"removed": true
},
{
"id": "h1_ilosc",
"displayName": "h1_ilosc",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"readOnly": false,
"removed": true
},
{
"id": "sprawdzono",
"displayName": "sprawdzono",
"required": false,
"defaultMatch": false,
"display": true,
"type": "date",
"readOnly": false,
"removed": true
},
{
"id": "nowy_title",
"displayName": "nowy_title",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"readOnly": false,
"removed": true
},
{
"id": "nowy_description",
"displayName": "nowy_description",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"readOnly": false,
"removed": true
},
{
"id": "nowy_h1",
"displayName": "nowy_h1",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"readOnly": false,
"removed": true
},
{
"id": "gsc_status",
"displayName": "gsc_status",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"readOnly": false,
"removed": true
},
{
"id": "gsc_ostatni_crawl",
"displayName": "gsc_ostatni_crawl",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"readOnly": false,
"removed": true
},
{
"id": "psi_mobile",
"displayName": "psi_mobile",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"readOnly": false,
"removed": false
},
{
"id": "psi_desktop",
"displayName": "psi_desktop",
"required": false,
"defaultMatch": false,
"display": true,
"type": "number",
"readOnly": false,
"removed": false
}
]
},
"options": {}
},
"type": "n8n-nodes-base.dataTable",
"typeVersion": 1.1,
"position": [
1760,
0
],
"id": "98c891cb-f1dd-6dd8-8652-e2dd3f64200e",
"name": "Zapisz wyniki"
}
],
"connections": {
"Uruchom recznie": {
"main": [
[
{
"node": "Ustawienia",
"type": "main",
"index": 0
}
]
]
},
"Ustawienia": {
"main": [
[
{
"node": "Przygotuj tabele",
"type": "main",
"index": 0
}
]
]
},
"Przygotuj tabele": {
"main": [
[
{
"node": "Adresy bez pomiaru",
"type": "main",
"index": 0
}
]
]
},
"Adresy bez pomiaru": {
"main": [
[
{
"node": "PageSpeed mobile",
"type": "main",
"index": 0
}
]
]
},
"PageSpeed mobile": {
"main": [
[
{
"node": "Wynik mobile",
"type": "main",
"index": 0
}
]
]
},
"Wynik mobile": {
"main": [
[
{
"node": "PageSpeed desktop",
"type": "main",
"index": 0
}
]
]
},
"PageSpeed desktop": {
"main": [
[
{
"node": "Wyniki razem",
"type": "main",
"index": 0
}
]
]
},
"Wyniki razem": {
"main": [
[
{
"node": "Zapisz wyniki",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"active": false
}