This workflow corresponds to n8n.io template #15911 — we link there as the canonical source.
This workflow follows the Form Trigger → Gmail recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "vQoMqhlLAuy1uCJp",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Monitor Core Web Vitals at scale with PageSpeed API & Google Sheets",
"tags": [],
"nodes": [
{
"id": "f3ded7a8-81ea-435b-88cb-57f8a70067da",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3104,
-256
],
"parameters": {
"color": 7,
"width": 848,
"height": 304,
"content": "## Fetch XML sitemap & extract URLs\nIf no file is uploaded, workflow will fetch the XML sitemap defined in the Config node and extract all URLs."
},
"typeVersion": 1
},
{
"id": "7539fc6a-3bb0-4ab3-9444-25e787149809",
"name": "Fetch the XML sitemap",
"type": "n8n-nodes-base.httpRequest",
"position": [
-3024,
-144
],
"parameters": {
"url": "={{ $('Config').item.json.xml_sitemap_url }}",
"options": {}
},
"typeVersion": 4.4
},
{
"id": "c4a37165-700e-44d8-8573-8d094206f590",
"name": "Convert to JSON",
"type": "n8n-nodes-base.xml",
"position": [
-2832,
-144
],
"parameters": {
"options": {}
},
"typeVersion": 1
},
{
"id": "54889c3c-42ce-4f6f-be39-a855d5d913f2",
"name": "Extract URL tags",
"type": "n8n-nodes-base.splitOut",
"position": [
-2624,
-144
],
"parameters": {
"options": {},
"fieldToSplitOut": "urlset.url"
},
"typeVersion": 1
},
{
"id": "0c795eda-84b7-4287-b6f3-ce28031a94cb",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4256,
-832
],
"parameters": {
"color": 7,
"width": 800,
"height": 704,
"content": "## Workflow setup\n\n**Required:**\n1. Insert your PageSpeed API key into **api_key** field in the *Config* node\n2. Insert your XML sitemap address into **xml_sitemap_url** field *(required unless CSV file is used)*\n3. Create and select the default Google Sheet into which report is saved *(new sheets, columns and data will populate automatically on each run).*\n4. Add your email address inside the 'Send audit summary email' node to get the email notification \n\n\n**Optional customisation:**\n- Change the **lighthouse_device** to switch between mobile/desktop audit *(default: desktop)*\n- Change the **analytics_campaign_utm** to keep track of the audit data in your website analytics platform; can also be removed entirely *(default: PageSpeedAudit)*\n- Update the **cwv_pass_thresholds** object if you need looser/stricter pass thresholds *(current defaults were taken from official Lighthouse/CWV documentation which may change in the future)*\n\n\n[Official Lighthouse performance scoring documentation](https://developer.chrome.com/docs/lighthouse/performance/performance-scoring)\n\n"
},
"typeVersion": 1
},
{
"id": "bbbaa679-56de-46ca-9a9d-dbeae17b1511",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-1872,
-544
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "84d3e39c-9586-41a1-904a-417b02ba48d4",
"name": "Upload CSV",
"type": "n8n-nodes-base.formTrigger",
"position": [
-4608,
-128
],
"parameters": {
"options": {},
"formTitle": "Upload CSV",
"formFields": {
"values": [
{
"fieldType": "file",
"fieldLabel": "CSV file:",
"requiredField": true,
"acceptFileTypes": ".csv"
}
]
},
"formDescription": "Upload a CSV file containing URLs to be audited in .CSV format (comma-delimited)."
},
"typeVersion": 2.5
},
{
"id": "e6c0adeb-1899-47ba-beae-f346441d32f4",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2128,
-768
],
"parameters": {
"color": 7,
"width": 1060,
"height": 896,
"content": "## Main audit loop\nSplit in batches, test each URL, and save results to spreadsheet. Any errors will be caught and inserted into spreadsheet along with Lighthouse error message for debugging.\n\n**Optional customisation:**\n- Change the time interval in the Wait node if you want to limit performance impact of the audit on your site *(useful for large audits, default: 1 second)*"
},
"typeVersion": 1
},
{
"id": "de694c52-2794-4aa2-b0fa-6f0050a3e2ee",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-4608,
-368
],
"parameters": {},
"typeVersion": 1
},
{
"id": "d08aa690-091b-4603-b992-fadb086b1cae",
"name": "Pick default spreadsheet to save the report",
"type": "n8n-nodes-base.googleSheets",
"position": [
-4016,
-368
],
"parameters": {
"title": "=PageSpeed_audit_{{ $json.lighthouse_device }}_{{ $now.format('dd-MM-yyyy_HH:mm') }}",
"options": {},
"operation": "create",
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "3d8bedbc-dc42-4064-9a70-1cab3cb97e5d",
"name": "Add column headers to new sheet",
"type": "n8n-nodes-base.httpRequest",
"position": [
-3808,
-368
],
"parameters": {
"url": "=https://sheets.googleapis.com/v4/spreadsheets/{{ $('Pick default spreadsheet to save the report').item.json.spreadsheetId }}/values/{{ $('Pick default spreadsheet to save the report').item.json.title }}!A1:AB?valueInputOption=RAW",
"method": "PUT",
"options": {},
"jsonBody": "={\n\t\"range\": \"{{ $('Pick default spreadsheet to save the report').item.json.title }}!A1:AB\",\n\t\"majorDimension\": \"ROWS\",\n\t\"values\": [{{ $('Config').item.json.report_column_names.toJsonString() }}]\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleSheetsOAuth2Api"
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.4
},
{
"id": "02cf2511-e26c-49ef-86b3-3f6d731c4f83",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3104,
-656
],
"parameters": {
"color": 7,
"width": 464,
"height": 320,
"content": "## Extract URLs from the CSV file\nIf CSV file is uploaded manually, it will be processed instead of XML sitemap defined in the Config node."
},
"typeVersion": 1
},
{
"id": "68688f68-2dc4-4975-a766-0858722beeaf",
"name": "Config",
"type": "n8n-nodes-base.set",
"position": [
-4208,
-368
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "f3b9a727-cd59-4166-9dbf-4e4abb54ff0a",
"name": "api_key",
"type": "string",
"value": "> Insert your API key here <"
},
{
"id": "f7b57b1e-20c7-4c8d-b095-1f88d29d60d0",
"name": "xml_sitemap_url",
"type": "string",
"value": "> Insert your XML sitemap URL here <"
},
{
"id": "beb25ef0-f0e3-4d20-b8c8-14a8a0ae07af",
"name": "lighthouse_category",
"type": "string",
"value": "performance"
},
{
"id": "b024103b-8d3d-4366-8276-811c8dfb7f43",
"name": "lighthouse_device",
"type": "string",
"value": "desktop"
},
{
"id": "a27363c6-1904-4a25-9b61-0b8c6c3f762c",
"name": "analytics_campaign_utm",
"type": "string",
"value": "PageSpeedAudit"
},
{
"id": "52e003be-4759-410e-aab8-8f0ca1f7e937",
"name": "cwv_pass_thresholds",
"type": "object",
"value": "{ \t\"LCP_pass_threshold\" : 2500, \t\"INP_pass_threshold\" : 200, \t\"CLS_pass_threshold\" : 0.1, \t\"FCP_pass_threshold\" : 1800, \t\"TTFB_pass_threshold\" : 800, \t\"TBT_pass_threshhold\": 200, \t\"SI_pass_threshold\" : 3400, }"
},
{
"id": "a7377308-0513-46cf-9af3-51a7c1034322",
"name": "report_column_names",
"type": "array",
"value": "[\"url\", \"HTTP_status_code\", \"download_size_KiB\", \"DOM_size\", \"lh_performance_score\", \"lh_FCP_score\", \"lh_FCP_result\", \"lh_LCP_score\", \"lh_LCP_result\", \"lh_TBT_score\", \"lh_TBT_result\", \"lh_CLS_score\", \"lh_CLS_result\", \"lh_SI_score\", \"lh_SI_result\", \"cwv_LCP_score\", \"cwv_LCP_result\", \"cwv_INP_score\", \"cwv_INP_result\", \"cwv_CLS_score\", \"cwv_CLS_result\", \"cwv_FCP_score\", \"cwv_FCP_result\", \"cwv_TTFB_score\", \"cwv_TTFB_result\", \"audit_timestamp\", \"warnings_errors\"]"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "75d158f4-7a8f-4f54-8e72-2b183f242c2f",
"name": "Process CSV file if uploaded, otherwise fetch the XML sitemap",
"type": "n8n-nodes-base.if",
"position": [
-3360,
-368
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "7b7cb9f5-e69b-4185-9923-433aa9d26e87",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $('Upload CSV').isExecuted }}",
"rightValue": ""
}
]
}
},
"executeOnce": true,
"typeVersion": 2.3
},
{
"id": "ff85a5dc-2c67-4b2c-9da1-07ba68923caf",
"name": "Run PageSpeed audit",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
-1680,
-480
],
"parameters": {
"url": "https://www.googleapis.com/pagespeedonline/v5/runPagespeed",
"options": {},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "category",
"value": "={{ $('Config').item.json.lighthouse_category }}"
},
{
"name": "strategy",
"value": "={{ $('Config').item.json.lighthouse_device }}"
},
{
"name": "url",
"value": "={{ $('Loop Over Items').item.json.urls}}"
},
{
"name": "key",
"value": "={{ $('Config').item.json.api_key }}"
},
{
"name": "utm_campaign",
"value": "={{ $('Config').item.json.analytics_campaign_utm }}"
}
]
}
},
"notesInFlow": false,
"retryOnFail": false,
"typeVersion": 4.4,
"alwaysOutputData": false
},
{
"id": "763262aa-153b-4191-9e73-f74acffb75c1",
"name": "Extract URLs from file",
"type": "n8n-nodes-base.splitOut",
"position": [
-2816,
-544
],
"parameters": {
"include": "=",
"options": {
"destinationFieldName": "urls"
},
"fieldToSplitOut": "row"
},
"typeVersion": 1
},
{
"id": "84edb909-f156-44a9-bd6f-b74e200ccd40",
"name": "Extract data from file",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-3024,
-544
],
"parameters": {
"options": {
"delimiter": ",",
"headerRow": false,
"readAsString": true
},
"binaryPropertyName": "={{ $('Upload CSV').item.binary.CSV_file_ }}"
},
"typeVersion": 1.1
},
{
"id": "307c902f-c0af-4cfb-9933-5597e99041be",
"name": "Create audit metadata",
"type": "n8n-nodes-base.set",
"position": [
-3600,
-368
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "8f8fb1da-a8a7-45c3-bbb1-a574bb0f12fb",
"name": "audit_meta",
"type": "object",
"value": "={ \t\"device_tested\": \"{{ $('Config').item.json.lighthouse_device }}\",\t\"urls_processed\": 0, \t\"errors\": 0, \t\"audit_start_time\": \"{{ $now.toUTC().format('dd-MM-yyyy HH:mm') }}\", \t\"audit_finish_time\": \"\", \t\"final_audit_url\": \"https://docs.google.com/spreadsheets/d/{{ $('Pick default spreadsheet to save the report').item.json.spreadsheetId }}/?gid={{ $('Pick default spreadsheet to save the report').item.json.sheetId }}\", }"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "76256599-28e0-46c5-bba7-15855a04cd79",
"name": "Increment error count meta",
"type": "n8n-nodes-base.set",
"position": [
-1456,
-352
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "517d61b3-0113-49ea-83f8-c17ce855bd5f",
"name": "audit_meta.errors",
"type": "number",
"value": "={{ $('Create audit metadata').item.json.audit_meta.errors += 1 }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "1c6d32fb-afd6-4bd4-8d40-e51ed50b7a9d",
"name": "Insert API audit data into sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1632,
-112
],
"parameters": {
"columns": {
"value": {
"url": "={{ $json.lighthouseResult.finalUrl }}",
"DOM_size": "={{ $json.lighthouseResult.audits['dom-size-insight'].details.debugData.totalElements }}",
"lh_SI_score": "={{ ($json.lighthouseResult.audits['speed-index'].numericValue / 1000).round(2)}}",
"lh_CLS_score": "={{ $json.lighthouseResult.audits['cumulative-layout-shift'].numericValue.round(3) }}",
"lh_FCP_score": "={{ ($json.lighthouseResult.audits['first-contentful-paint'].numericValue / 1000).round(2)}}",
"lh_LCP_score": "={{ ($json.lighthouseResult.audits['largest-contentful-paint'].numericValue / 1000).round(2)}}",
"lh_SI_result": "={{ $json.lighthouseResult.audits['speed-index'].numericValue <= $('Config').item.json.cwv_pass_thresholds.SI_pass_threshold ? \"Pass\" : \"Fail\"}}",
"lh_TBT_score": "={{ $json.lighthouseResult.audits['total-blocking-time'].numericValue.round(0) }}",
"cwv_CLS_score": "={{ $json.loadingExperience.metrics.CUMULATIVE_LAYOUT_SHIFT_SCORE.percentile }}",
"cwv_FCP_score": "={{ $json.loadingExperience.metrics.FIRST_CONTENTFUL_PAINT_MS.percentile }}",
"cwv_INP_score": "={{ $json.loadingExperience.metrics.INTERACTION_TO_NEXT_PAINT.percentile }}",
"cwv_LCP_score": "={{ $json.loadingExperience.metrics.LARGEST_CONTENTFUL_PAINT_MS.percentile }}",
"lh_CLS_result": "={{ $json.lighthouseResult.audits['cumulative-layout-shift'].numericValue <= $('Config').item.json.cwv_pass_thresholds.CLS_pass_threshold ? \"Pass\" : \"Fail\"}}",
"lh_FCP_result": "={{ $json.lighthouseResult.audits['first-contentful-paint'].numericValue <= $('Config').item.json.cwv_pass_thresholds.FCP_pass_threshold ? \"Pass\" : \"Fail\" }}",
"lh_LCP_result": "={{ $json.lighthouseResult.audits['largest-contentful-paint'].numericValue <= $('Config').item.json.cwv_pass_thresholds.LCP_pass_threshold ? \"Pass\" : \"Fail\"}}",
"lh_TBT_result": "={{ $json.lighthouseResult.audits['total-blocking-time'].numericValue <= $('Config').item.json.cwv_pass_thresholds.TBT_pass_threshhold ? \"Pass\" : \"Fail\"}}",
"cwv_CLS_result": "={{ $json.loadingExperience.metrics.CUMULATIVE_LAYOUT_SHIFT_SCORE.percentile <= $('Config').item.json.cwv_pass_thresholds.CLS_pass_threshold ? \"Pass\" : \"Fail\"}}",
"cwv_FCP_result": "={{ $json.loadingExperience.metrics.FIRST_CONTENTFUL_PAINT_MS.percentile <= $('Config').item.json.cwv_pass_thresholds.FCP_pass_threshold ? \"Pass\" : \"Fail\"}}",
"cwv_INP_result": "={{ $json.loadingExperience.metrics.INTERACTION_TO_NEXT_PAINT.percentile <= $('Config').item.json.cwv_pass_thresholds.INP_pass_threshold ? \"Pass\" : \"Fail\"}}",
"cwv_LCP_result": "={{ $json.loadingExperience.metrics.LARGEST_CONTENTFUL_PAINT_MS.percentile <= $('Config').item.json.cwv_pass_thresholds.LCP_pass_threshold ? \"Pass\" : \"Fail\"}}",
"cwv_TTFB_score": "={{ $json.loadingExperience.metrics.EXPERIMENTAL_TIME_TO_FIRST_BYTE.percentile }}",
"audit_timestamp": "={{ $now.toUTC().format('dd-MM-yyyy HH:mm') }}",
"cwv_TTFB_result": "={{ $json.loadingExperience.metrics.EXPERIMENTAL_TIME_TO_FIRST_BYTE.percentile <= $('Config').item.json.cwv_pass_thresholds.TTFB_pass_threshold ? \"Pass\" : \"Fail\"}}",
"warnings_errors": "={{ $json.lighthouseResult.runWarnings.length > 0 ? $json.lighthouseResult.runWarnings : \"\" }}",
"HTTP_status_code": "={{ $json.lighthouseResult.audits['network-requests'].details.items[0].statusCode }}",
"download_size_KiB": "={{ ($json.lighthouseResult.audits['total-byte-weight'].numericValue / 1024).round(1)}}",
"lh_performance_score": "={{ $json.lighthouseResult.categories.performance.score * 100}}"
},
"schema": [
{
"id": "url",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HTTP_status_code",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "HTTP_status_code",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "download_size_KiB",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "download_size_KiB",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "DOM_size",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "DOM_size",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_performance_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_performance_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_FCP_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_FCP_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_FCP_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_FCP_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_LCP_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_LCP_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_LCP_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_LCP_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_TBT_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_TBT_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_TBT_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_TBT_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_CLS_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_CLS_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_CLS_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_CLS_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_SI_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_SI_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_SI_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_SI_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_LCP_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_LCP_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_LCP_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_LCP_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_INP_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_INP_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_INP_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_INP_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_CLS_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_CLS_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_CLS_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_CLS_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_FCP_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_FCP_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_FCP_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_FCP_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_TTFB_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_TTFB_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_TTFB_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_TTFB_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "audit_timestamp",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "audit_timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "warnings_errors",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "warnings_errors",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {
"useAppend": true
},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "={{ $('Pick default spreadsheet to save the report').item.json.sheetId }}"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Pick default spreadsheet to save the report').item.json.spreadsheetId }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "e5e6eaed-5351-4eba-939f-3656d2878559",
"name": "Wait between each batch",
"type": "n8n-nodes-base.wait",
"position": [
-2032,
-96
],
"parameters": {
"amount": 1
},
"typeVersion": 1.1
},
{
"id": "9819d61c-ec29-4021-978d-d279fbe2b35a",
"name": "Increment urls_processed meta",
"type": "n8n-nodes-base.set",
"position": [
-1392,
-112
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "c12d35fa-d746-4aa0-b9a8-224adf395488",
"name": "urls_processed",
"type": "number",
"value": "={{ $('Create audit metadata').item.json.audit_meta.urls_processed += 1 }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "943ac022-083a-46fc-994d-b73c899ff98b",
"name": "Update audit_finish_time meta",
"type": "n8n-nodes-base.set",
"position": [
-1360,
-560
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "78d94c01-c6ba-4d5b-8698-01c8dd653b93",
"name": "audit_meta.audit_finish_time",
"type": "string",
"value": "={{ $now.toUTC().format('dd-MM-yyyy HH:mm') }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "cbaea255-e164-4f2a-aee5-6913fdbf9630",
"name": "Insert error data into sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1264,
-352
],
"parameters": {
"columns": {
"value": {
"url": "={{ $('Run PageSpeed audit').item.json.urls }}",
"audit_timestamp": "={{ $now.toUTC().format('dd-MM-yyyy HH:mm') }}",
"warnings_errors": "={{ $('Run PageSpeed audit').item.json.error.message }}",
"HTTP_status_code": "={{ $('Run PageSpeed audit').item.json.error.status }}"
},
"schema": [
{
"id": "url",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HTTP_status_code",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "HTTP_status_code",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "download_size_KiB",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "download_size_KiB",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "DOM_size",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "DOM_size",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_performance_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_performance_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_FCP_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_FCP_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_FCP_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_FCP_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_LCP_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_LCP_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_LCP_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_LCP_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_TBT_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_TBT_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_TBT_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_TBT_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_CLS_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_CLS_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_CLS_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_CLS_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_SI_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_SI_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "lh_SI_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "lh_SI_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_LCP_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_LCP_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_LCP_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_LCP_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_INP_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_INP_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_INP_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_INP_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_CLS_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_CLS_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_CLS_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_CLS_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_FCP_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_FCP_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_FCP_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_FCP_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_TTFB_score",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_TTFB_score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "cwv_TTFB_result",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "cwv_TTFB_result",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "audit_timestamp",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "audit_timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "warnings_errors",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "warnings_errors",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "={{ $('Pick default spreadsheet to save the report').item.json.sheetId }}"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Pick default spreadsheet to save the report').item.json.spreadsheetId }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "b4ca0c24-dac1-4a0e-b555-34a1de5066bd",
"name": "Extract URLs",
"type": "n8n-nodes-base.splitOut",
"position": [
-2416,
-144
],
"parameters": {
"options": {
"destinationFieldName": "urls"
},
"fieldToSplitOut": "loc"
},
"typeVersion": 1
},
{
"id": "d645e845-6bfc-4bdb-acb7-fc5d84199407",
"name": "Schedule Audit",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-4608,
-592
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
]
}
]
}
},
"typeVersion": 1.3
},
{
"id": "650c9999-5813-4ba1-b07b-b2d7cdd0d85e",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4720,
-832
],
"parameters": {
"color": 7,
"width": 384,
"height": 864,
"content": "## Ways to run this workflow:\n- On-demand via 'Upload CSV' node (URLs extracted from .csv file)\n- On a regular schedule via 'Schedule Audit' node (URLs fetched from XML sitemap)\n- Manually via 'Execute workflow' node (URLs fetched from XML sitemap)"
},
"typeVersion": 1
},
{
"id": "467017ad-0252-422a-8697-d42bdc213e86",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-992,
-768
],
"parameters": {
"color": 7,
"width": 416,
"height": 432,
"content": "## Send audit notification email\nOnce the audit finishes, this node builds a simple HTML email and sends it to your pre-defined address. \n\nEmail includes basic audit metadata and a link to the spreadsheet with full report."
},
"typeVersion": 1
},
{
"id": "62cbddc7-3681-4bf2-a56f-4327ae38f6c2",
"name": "Send audit summary email",
"type": "n8n-nodes-base.gmail",
"position": [
-832,
-560
],
"parameters": {
"sendTo": "> Insert your email here <",
"message": "=<h2>Your PageSpeed audit has finished</h2>\n\n<h3>Here are the details:</h3>\n<h4>Device tested:</h4>\n<p>{{ $('Create audit metadata').item.json.audit_meta.device_tested }}</p>\n<h4>URLs processed successfully:</h4>\n<p>{{ $('Create audit metadata').item.json.audit_meta.urls_processed }}</p>\n<h4>URLs with errors:</h4>\n<p>{{ $('Create audit metadata').item.json.audit_meta.errors }}</p>\n<h4>Start time (UTC):</h4>\n<p>{{ $('Create audit metadata').item.json.audit_meta.audit_start_time }}</p>\n<h4>Finish time (UTC):</h4>\n<p>{{ $json.audit_meta.audit_finish_time }}</p>\n<br>\n<p>Full audit has been <a href=\"{{ $('Create audit metadata').item.json.audit_meta.final_audit_url }}\">saved here.</a></p>",
"options": {},
"subject": "PageSpeed audit complete"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"executeOnce": true,
"typeVersion": 2.2
},
{
"id": "3ff98180-dd60-4f7d-970e-27a3d85a499a",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-5328,
-1088
],
"parameters": {
"color": "#D3CD8D",
"width": 528,
"height": 1120,
"content": "## What this workflow does\nThis workflow extracts URL addresses from either a CSV file or an XML sitemap, then uses PageSpeed API to get Lighthouse and Core Web Vitals metrics for each URL.\n\n\n### The final report contains the following columns (in order):\n\n- url\n- HTTP_status_code *(as returned by Lighthouse)*\n- download_size_KiB *(main document size in Kibibytes)*\n- DOM_size *(total number of DOM elements)*\n- lh_performance_score *(overall Lighthouse performance score, 0-100)*\n- lh_FCP_score *(notable CWV metric)*\n- lh_FCP_result *(Pass/Fail)*\n- lh_LCP_score *(main CWV metric)*\n- lh_LCP_result *(Pass/Fail)*\n- lh_TBT_score\n- lh_TBT_result *(Pass/Fail)*\n- lh_CLS_score *(main CWV metric)*\n- lh_CLS_result *(Pass/Fail)*\n- lh_SI_score\n- lh_SI_result *(Pass/Fail)*\n- cwv_LCP_score *(main CWV metric)*\n- cwv_LCP_result *(Pass/Fail)*\n- cwv_INP_score *(main CWV metric)*\n- cwv_INP_result *(Pass/Fail)*\n- cwv_CLS_score *(main CWV metric)*\n- cwv_CLS_result *(Pass/Fail)*\n- cwv_FCP_score *(notable CWV metric)*\n- cwv_FCP_result *(Pass/Fail)*\n- cwv_TTFB_score *(notable CWV metric)*\n- cwv_TTFB_result *(Pass/Fail)*\n- audit_timestamp *(in UTC timezone)*\n- warnings_errors *(warnings/error messages, if returned by Lighthouse)*\n\n\n**For brevity, the following acronyms are used in column names:**\n\n- **\"lh_\"** indicates Lighthouse lab data\n- **\"cwv_\"** indicates Core Web Vitals field data from CrUX (if available for a given URL)\n- **\"_score\"** indicates columns containing actual numeric values for each metric\n- **\"_result\"** indicates columns validating Pass/Fail results\n- **\"FCP\"** stands for First Contentful Paint\n- **\"LCP\"** stands for Largest Contentful Paint\n- **\"TBT\"** stands for Total Blocking Time\n- **\"CLS\"** stands for Cumulative Layout Shift\n- **\"SI\"** stands for Speed Index\n- **\"INP\"** stands for Interaction to Next Paint\n- **\"TTFB\"** stands for Time To First Byte\n"
},
"typeVersion": 1
},
{
"id": "27877f97-f6d8-4c08-9a91-1c20ad37da9a",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4720,
80
],
"parameters": {
"color": 5,
"width": 384,
"height": 208,
"content": "## CSV file setup: \nThe CSV file should contain only a single column (no headers) with URLs separated by commas.\n\n**Format example:**\n\nhttps://firsturl.com,\nhttps://secondurl.com,\nhttps://thirdurl.com,\n..."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "d0c5d687-b697-4925-a884-c8f3eb6e6679",
"connections": {
"Config": {
"main": [
[
{
"node": "Pick default spreadsheet to save the report",
"type": "main",
"index": 0
}
]
]
},
"Upload CSV": {
"main": [
[
{
"node": "Config",
"type": "main",
"index": 0
}
]
]
},
"Extract URLs": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Schedule Audit": {
"main": [
[
{
"node": "Config",
"type": "main",
"index": 0
}
]
]
},
"Convert to JSON": {
"main": [
[
{
"node": "Extract URL tags",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[
{
"node": "Update audit_finish_time meta",
"type": "main",
"index": 0
}
],
[
{
"node": "Run PageSpeed audit",
"type": "main",
"index": 0
}
]
]
},
"Extract URL tags": {
"main": [
[
{
"node": "Extract URLs",
"type": "main",
"index": 0
}
]
]
},
"Run PageSpeed audit": {
"main": [
[
{
"node": "Insert API audit data into sheet",
"type": "main",
"index": 0
}
],
[
{
"node": "Increment error count meta",
"type": "main",
"index": 0
}
]
]
},
"Create audit metadata": {
"main": [
[
{
"node": "Process CSV file if uploaded, otherwise fetch the XML sitemap",
"type": "main",
"index": 0
}
]
]
},
"Fetch the XML sitemap": {
"main": [
[
{
"node": "Convert to JSON",
"type": "main",
"index": 0
}
]
]
},
"Extract URLs from file": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Extract data from file": {
"main": [
[
{
"node": "Extract URLs from file",
"type": "main",
"index": 0
}
]
]
},
"Wait between each batch": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Increment error count meta": {
"main": [
[
{
"node": "Insert error data into sheet",
"type": "main",
"index": 0
}
]
]
},
"Insert error data into sheet": {
"main": [
[
{
"node": "Wait between each batch",
"type": "main",
"index": 0
}
]
]
},
"Increment urls_processed meta": {
"main": [
[
{
"node": "Wait between each batch",
"type": "main",
"index": 0
}
]
]
},
"Update audit_finish_time meta": {
"main": [
[
{
"node": "Send audit summary email",
"type": "main",
"index": 0
}
]
]
},
"Add column headers to new sheet": {
"main": [
[
{
"node": "Create audit metadata",
"type": "main",
"index": 0
}
]
]
},
"Insert API audit data into sheet": {
"main": [
[
{
"node": "Increment urls_processed meta",
"type": "main",
"index": 0
}
]
]
},
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Config",
"type": "main",
"index": 0
}
]
]
},
"Pick default spreadsheet to save the report": {
"main": [
[
{
"node": "Add column headers to new sheet",
"type": "main",
"index": 0
}
]
]
},
"Process CSV file if uploaded, otherwise fetch the XML sitemap": {
"main": [
[
{
"node": "Extract data from file",
"type": "main",
"index": 0
}
],
[
{
"node": "Fetch the XML sitemap",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
gmailOAuth2googleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow audits a list of URLs from a CSV upload or an XML sitemap using the Google PageSpeed Insights API, writes Lighthouse and Core Web Vitals metrics into a new Google Sheets report, and emails a completion summary via Gmail. Starts either on a schedule, via manual…
Source: https://n8n.io/workflows/15911/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Submit any YouTube, Vimeo, or Zoom webinar URL using a simple form and the workflow handles everything from there. It runs a two-phase pipeline: first identifying the top viral moments in your video w
This two-part workflow collects CV profiles via an n8n form and stores them in Google Sheets, then runs every 6 hours to pull jobs from Remotive and Arbeitnow, score fit and generate cover letters wit
Stop chasing blurry receipts and manually typing expense data. This workflow creates an intelligent, "snap-and-submit" reimbursement pipeline that hosts photos via UploadToURL, extracts deep data via
Atlas Opco Import. Uses github, stopAndError, formTrigger, googleSheets. Event-driven trigger; 22 nodes.
Shopify and E-Commerce store owners often struggle to create engaging 3D videos from static product images. This workflow automates that entire process—from image upload to video delivery—so store own