AutomationFlowsData & Sheets › Find Top Keywords with NocoDB

Find Top Keywords with NocoDB

Original n8n title: Find Top Keywords

Find Top Keywords. Uses manualTrigger, scheduleTrigger, stickyNote, nocoDb. Event-driven trigger; 35 nodes.

Event trigger★★★★★ complexity35 nodesNoco DbHTTP Request
Data & Sheets Trigger: Event Nodes: 35 Complexity: ★★★★★ Added:
Find Top Keywords with NocoDB — n8n workflow card showing Noco Db, HTTP Request integration

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 →

Download .json
{
  "id": "SHgOqN3ednIo5gNu",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Find Top Keywords",
  "tags": [],
  "nodes": [
    {
      "id": "386c7972-34c2-4f51-9329-dee7f6a7511b",
      "name": "When clicking \u2018Test workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -3440,
        760
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "3ebf40fd-acfd-4424-99c9-95ddaac74de3",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -3440,
        1040
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 */4 * * *"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "a24af92b-849d-48ee-aedd-6c7e75d9c902",
      "name": "Gen Time",
      "type": "n8n-nodes-base.code",
      "position": [
        -3160,
        940
      ],
      "parameters": {
        "jsCode": "// Get today's date\nconst today = new Date();\n\n// Subtract one day to get the previous day\nconst yesterday = new Date(today);\nyesterday.setDate(today.getDate() - 1);\n\n// Format the date as yyyy-mm-dd\nconst year = yesterday.getFullYear();\nconst month = String(yesterday.getMonth() + 1).padStart(2, '0'); // Month is zero-indexed\nconst day = String(yesterday.getDate()).padStart(2, '0');\n\nconst formattedDate = `${year}-${month}-${day}`;\n\n// Set the formatted date to be used in a later node\nreturn [{ json: { previousDay: formattedDate } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "f0807e09-1f8f-45ba-a6d3-d14ee3f96a9f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3540,
        600
      ],
      "parameters": {
        "width": 520,
        "height": 780,
        "content": "## Create time for yesterday and today. This will be used to gather and search for news articles within a specific range."
      },
      "typeVersion": 1
    },
    {
      "id": "c97b391b-1da1-4c62-9394-e83a49dae788",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3020,
        600
      ],
      "parameters": {
        "color": 4,
        "width": 280,
        "height": 780,
        "content": "## Grab a list of base keywords from NocoDB"
      },
      "typeVersion": 1
    },
    {
      "id": "21e89f1c-7101-490a-89aa-a5a52e10d88a",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2740,
        600
      ],
      "parameters": {
        "width": 380,
        "height": 780,
        "content": "## Generate YouTube and Google Keywords from base keywords"
      },
      "typeVersion": 1
    },
    {
      "id": "3b6e8b0e-dfdc-41d0-a387-00872c92faa1",
      "name": "NocoDB",
      "type": "n8n-nodes-base.nocoDb",
      "position": [
        -2940,
        940
      ],
      "parameters": {
        "table": "mztryza8davdl48",
        "options": {
          "fields": [
            "keyword"
          ]
        },
        "operation": "getAll",
        "projectId": "pbwiwe87uf1cpgc",
        "returnAll": true,
        "authentication": "nocoDbApiToken"
      },
      "credentials": {
        "nocoDbApiToken": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "fef9283e-886a-486b-a51f-0f459f4b18e0",
      "name": "Second Order Google Autocomplete Keywords",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -2620,
        800
      ],
      "parameters": {
        "url": "http://192.168.1.110:8000/google-search/autocomplete-keywords",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "input_keyword",
              "value": "={{ $('NocoDB').item.json.keyword }}"
            },
            {
              "name": "input_country",
              "value": "US"
            },
            {
              "name": "use_proxy",
              "value": "true"
            },
            {
              "name": "output",
              "value": "toolbar"
            },
            {
              "name": "spell",
              "value": "1"
            },
            {
              "name": "hl",
              "value": "en"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "accept",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "typeVersion": 4.2
    },
    {
      "id": "fad88d1e-a14e-4cc1-9ac1-dcc6126355c4",
      "name": "Google Search Volume",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -2020,
        800
      ],
      "parameters": {
        "url": "https://api.dataforseo.com/v3/keywords_data/google_ads/search_volume/live",
        "method": "POST",
        "options": {},
        "jsonBody": "=[\n    {\n        \"location_code\": 2840,\n        \"language_code\": \"en\",\n        \"keywords\": [{{ $json.keywords }}],\n        \"date_from\": \"2021-08-01\",\n        \"search_partners\": false \n    }\n]",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth"
      },
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "typeVersion": 4.2
    },
    {
      "id": "dac54baa-6166-4fb6-a705-a45a91b993ed",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2360,
        600
      ],
      "parameters": {
        "color": 4,
        "width": 500,
        "height": 780,
        "content": "## Query YouTube and Google Keyword search volume."
      },
      "typeVersion": 1
    },
    {
      "id": "753401aa-c78e-4dd1-b47f-b774bed8a6ce",
      "name": "Split Out Google Search",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -1740,
        800
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "tasks[0].result"
      },
      "executeOnce": false,
      "typeVersion": 1
    },
    {
      "id": "12f53197-a03e-4862-a6cf-d4feffd49b29",
      "name": "YouTube Search Volume",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -2020,
        1120
      ],
      "parameters": {
        "url": "https://api.dataforseo.com/v3/keywords_data/google_ads/search_volume/live",
        "method": "POST",
        "options": {},
        "jsonBody": "=[\n    {\n        \"location_code\": 2840,\n        \"language_code\": \"en\",\n        \"keywords\": [{{ $json.keywords }}],\n        \"date_from\": \"2021-08-01\",\n        \"search_partners\": true,\n        \"sort_by\": \"search_volume\"\n    }\n]",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth"
      },
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "typeVersion": 4.2
    },
    {
      "id": "d0173c03-c803-4c64-9c87-48a47952085f",
      "name": "Second Order YouTube Autocomplete Keywords",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -2620,
        1120
      ],
      "parameters": {
        "url": "http://192.168.1.110:8000/google-search/autocomplete-keywords",
        "options": {
          "redirect": {
            "redirect": {}
          }
        },
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "input_keyword",
              "value": "={{ $json.keyword }}"
            },
            {
              "name": "input_country",
              "value": "US"
            },
            {
              "name": "use_proxy",
              "value": "true"
            },
            {
              "name": "output",
              "value": "toolbar"
            },
            {
              "name": "spell",
              "value": "1"
            },
            {
              "name": "hl",
              "value": "en"
            },
            {
              "name": "ds",
              "value": "yt"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "accept",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "typeVersion": 4.2
    },
    {
      "id": "dfa987d0-c18c-44c4-9796-942404f49630",
      "name": "Split Out YT Search",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -1740,
        1120
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "tasks[0].result"
      },
      "executeOnce": false,
      "typeVersion": 1
    },
    {
      "id": "29196a5b-c46e-46f7-99ff-781a0d97c551",
      "name": "Google Filter",
      "type": "n8n-nodes-base.filter",
      "position": [
        -1520,
        800
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "6e46fa28-2adf-47a0-bbf3-7a9b8b8413f7",
              "operator": {
                "type": "array",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.monthly_searches }}",
              "rightValue": ""
            },
            {
              "id": "45bca7c3-eac2-44e8-9993-b53200174003",
              "operator": {
                "type": "number",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.cpc }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "6b11b8e2-d6fb-45d7-817e-3e1038068696",
      "name": "YT Filter",
      "type": "n8n-nodes-base.filter",
      "position": [
        -1520,
        1120
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "6e46fa28-2adf-47a0-bbf3-7a9b8b8413f7",
              "operator": {
                "type": "array",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.monthly_searches }}",
              "rightValue": ""
            },
            {
              "id": "45bca7c3-eac2-44e8-9993-b53200174003",
              "operator": {
                "type": "number",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.cpc }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "6d52836b-ce37-46c0-aa4b-7c2b917b9f1d",
      "name": "Add Second Tier YT Keyword Data",
      "type": "n8n-nodes-base.nocoDb",
      "position": [
        -440,
        980
      ],
      "parameters": {
        "table": "m8bp2fnwtqsd2m7",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldName": "=keyword",
              "fieldValue": "={{ $('Split Out YT Search').item.json.keyword }}"
            },
            {
              "fieldName": "location_code",
              "fieldValue": "={{ $('Split Out YT Search').item.json.location_code }}"
            },
            {
              "fieldName": "language_code",
              "fieldValue": "={{ $('Split Out YT Search').item.json.language_code }}"
            },
            {
              "fieldName": "search_partners",
              "fieldValue": "={{ $('Split Out YT Search').item.json.search_partners }}"
            },
            {
              "fieldName": "competition",
              "fieldValue": "={{ $('Split Out YT Search').item.json.competition }}"
            },
            {
              "fieldName": "competition_index",
              "fieldValue": "={{ $('Split Out YT Search').item.json.competition_index }}"
            },
            {
              "fieldName": "cpc",
              "fieldValue": "={{ $('Split Out YT Search').item.json.cpc }}"
            },
            {
              "fieldName": "low_top_of_page_bid",
              "fieldValue": "={{ $('Split Out YT Search').item.json.low_top_of_page_bid }}"
            },
            {
              "fieldName": "high_top_of_page_bid",
              "fieldValue": "={{ $('Split Out YT Search').item.json.high_top_of_page_bid }}"
            },
            {
              "fieldName": "search_volume",
              "fieldValue": "={{ $('Split Out YT Search').item.json.search_volume }}"
            }
          ]
        },
        "operation": "create",
        "projectId": "pbwiwe87uf1cpgc",
        "authentication": "nocoDbApiToken"
      },
      "credentials": {
        "nocoDbApiToken": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "retryOnFail": true,
      "typeVersion": 3
    },
    {
      "id": "d4a72c2b-8c16-4f3e-80ad-1564ec8b33d4",
      "name": "Add Second Tier G Keyword Data",
      "type": "n8n-nodes-base.nocoDb",
      "position": [
        -440,
        400
      ],
      "parameters": {
        "table": "mjmbcomto18scyi",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldName": "=keyword",
              "fieldValue": "={{ $('Split Out Google Search').item.json.keyword }}"
            },
            {
              "fieldName": "location_code",
              "fieldValue": "={{ $('Split Out Google Search').item.json.location_code }}"
            },
            {
              "fieldName": "language_code",
              "fieldValue": "={{ $('Split Out Google Search').item.json.language_code }}"
            },
            {
              "fieldName": "search_partners",
              "fieldValue": "={{ $('Split Out Google Search').item.json.search_partners }}"
            },
            {
              "fieldName": "competition",
              "fieldValue": "={{ $('Split Out Google Search').item.json.competition }}"
            },
            {
              "fieldName": "competition_index",
              "fieldValue": "={{ $('Split Out Google Search').item.json.competition_index }}"
            },
            {
              "fieldName": "cpc",
              "fieldValue": "={{ $('Split Out Google Search').item.json.cpc }}"
            },
            {
              "fieldName": "low_top_of_page_bid",
              "fieldValue": "={{ $('Split Out Google Search').item.json.low_top_of_page_bid }}"
            },
            {
              "fieldName": "high_top_of_page_bid",
              "fieldValue": "={{ $('Split Out Google Search').item.json.high_top_of_page_bid }}"
            },
            {
              "fieldName": "search_volume",
              "fieldValue": "={{ $('Split Out Google Search').item.json.search_volume }}"
            }
          ]
        },
        "operation": "create",
        "projectId": "pbwiwe87uf1cpgc",
        "authentication": "nocoDbApiToken"
      },
      "credentials": {
        "nocoDbApiToken": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "retryOnFail": true,
      "typeVersion": 3
    },
    {
      "id": "1fdaf0fc-5c11-406f-93fb-b4a7fd3b6eed",
      "name": "Format G Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -240,
        400
      ],
      "parameters": {
        "jsCode": "// Get the monthly search data from the \"Loop Over Google Keywords\" node\nconst loopData = $node[\"Loop Over Google Keywords\"].json;\nif (!loopData || !loopData.monthly_searches || !Array.isArray(loopData.monthly_searches)) {\n  throw new Error(\"monthly_searches data is missing or not an array from Loop Over Google Keywords node.\");\n}\nconst monthlySearches = loopData.monthly_searches;\n\n// Get all items from the \"Add Second Tier G Keyword Data\" node\nconst secondTierItems = $items(\"Add Second Tier G Keyword Data\");\n\nif (!secondTierItems || secondTierItems.length === 0) {\n  throw new Error(\"No data found in Add Second Tier G Keyword Data node.\");\n}\n\nconst results = [];\n\n// Loop through each second-tier item\nsecondTierItems.forEach(itemWrapper => {\n  const item = itemWrapper.json;\n  // Validate that the required properties exist on the second-tier item.\n  if (!item.keyword || item.Id === undefined) {\n    throw new Error(\"A second tier item is missing 'keyword' or 'Id'.\");\n  }\n  \n  // For each monthly search record, combine with the second-tier data\n  monthlySearches.forEach(record => {\n    // Validate that each monthly record has the required properties.\n    if (record.year === undefined || record.month === undefined || record.search_volume === undefined) {\n      throw new Error(\"A monthly search record is missing 'year', 'month', or 'search_volume'.\");\n    }\n    \n    results.push({\n      json: {\n        keyword: item.keyword,\n        google_keyword_id: item.Id,\n        year: record.year,\n        month: record.month,\n        search_volume: record.search_volume,\n        unique_id: `${record.year}-${record.month}-${item.keyword}`\n      }\n    });\n  });\n});\n\n// Chunk the results into batches of 1000 items each\nconst batchSize = 1000;\nconst batchedResults = [];\n\nfor (let i = 0; i < results.length; i += batchSize) {\n  // Create a batch containing up to batchSize items\n  const batchItems = results.slice(i, i + batchSize).map(item => item.json);\n  batchedResults.push({\n    json: {\n      batch: batchItems\n    }\n  });\n}\n\nreturn batchedResults;\n"
      },
      "typeVersion": 2,
      "alwaysOutputData": false
    },
    {
      "id": "7d654cf7-1223-4f10-8026-997f5418402e",
      "name": "Format YT Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -220,
        980
      ],
      "parameters": {
        "jsCode": "// Get the monthly search data from the \"Loop Over Google Keywords\" node\nconst loopData = $node[\"Loop Over YT Keywords\"].json;\nif (!loopData || !loopData.monthly_searches || !Array.isArray(loopData.monthly_searches)) {\n  throw new Error(\"monthly_searches data is missing or not an array from Loop Over YT Keywords node.\");\n}\nconst monthlySearches = loopData.monthly_searches;\n\n// Get all items from the \"Add Second Tier G Keyword Data\" node\nconst secondTierItems = $items(\"Add Second Tier YT Keyword Data\");\n\nif (!secondTierItems || secondTierItems.length === 0) {\n  throw new Error(\"No data found in Add Second Tier YT Keyword Data node.\");\n}\n\nconst results = [];\n\n// Loop through each second-tier item\nsecondTierItems.forEach(itemWrapper => {\n  const item = itemWrapper.json;\n  // Validate that the required properties exist on the second-tier item.\n  if (!item.keyword || item.Id === undefined) {\n    throw new Error(\"A second tier item is missing 'keyword' or 'Id'.\");\n  }\n  \n  // For each monthly search record, combine with the second-tier data\n  monthlySearches.forEach(record => {\n    // Validate that each monthly record has the required properties.\n    if (record.year === undefined || record.month === undefined || record.search_volume === undefined) {\n      throw new Error(\"A monthly search record is missing 'year', 'month', or 'search_volume'.\");\n    }\n    \n    results.push({\n      json: {\n        keyword: item.keyword,\n        google_keyword_id: item.Id,\n        year: record.year,\n        month: record.month,\n        search_volume: record.search_volume,\n        unique_id: `${record.year}-${record.month}-${item.keyword}`\n      }\n    });\n  });\n});\n\n// Chunk the results into batches of 1000 items each\nconst batchSize = 1000;\nconst batchedResults = [];\n\nfor (let i = 0; i < results.length; i += batchSize) {\n  // Create a batch containing up to batchSize items\n  const batchItems = results.slice(i, i + batchSize).map(item => item.json);\n  batchedResults.push({\n    json: {\n      batch: batchItems\n    }\n  });\n}\n\nreturn batchedResults;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "67848762-a140-4c63-b8ca-e20331135741",
      "name": "Bulk Import G Monthly Search Volume",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        0,
        400
      ],
      "parameters": {
        "url": "http://192.168.1.186:8080/api/v2/tables/ma51kvf78diz0sg/records",
        "method": "POST",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1000
            }
          }
        },
        "jsonBody": "={{ $json.batch }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "nocoDbApiToken"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        },
        "nocoDbApiToken": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "377b5470-9d9f-42e5-9528-fbf9fd3a1d77",
      "name": "Bulk Import YT Monthly Search Volume",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        40,
        980
      ],
      "parameters": {
        "url": "http://192.168.1.186:8080/api/v2/tables/ma51kvf78diz0sg/records",
        "method": "POST",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1000
            }
          }
        },
        "jsonBody": "={{ $json.batch }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "nocoDbApiToken"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        },
        "nocoDbApiToken": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "6939afbf-b463-44fb-ab0b-45cbe81648eb",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1860,
        600
      ],
      "parameters": {
        "width": 540,
        "height": 780,
        "content": "## Process and filter Keywords for monthly traffic and CPC"
      },
      "typeVersion": 1
    },
    {
      "id": "6fdbd7c3-75ca-4ed4-a5aa-3718bee0786f",
      "name": "Is Google Keyword Available",
      "type": "n8n-nodes-base.if",
      "position": [
        -680,
        640
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c4c4ed58-b14d-4973-93b2-4426fe314a2a",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.pageInfo.totalRows }}",
              "rightValue": 0
            }
          ]
        }
      },
      "executeOnce": false,
      "typeVersion": 2.2
    },
    {
      "id": "f10d1313-fdfb-4f58-921d-65f307afab4e",
      "name": "Is YT Keyword Avaliable",
      "type": "n8n-nodes-base.if",
      "position": [
        -700,
        1260
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c4c4ed58-b14d-4973-93b2-4426fe314a2a",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.pageInfo.totalRows }}",
              "rightValue": 0
            }
          ]
        }
      },
      "executeOnce": false,
      "typeVersion": 2.2
    },
    {
      "id": "c6c26129-fce0-4d98-a72a-662dcbc06ae0",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1320,
        320
      ],
      "parameters": {
        "color": 4,
        "width": 1560,
        "height": 1280,
        "content": "## Add or update YouTube or Google Tables in NocoDB\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a3c0ed20-f696-4ca6-a6fb-872cab8fbba5",
      "name": "Check for Google Keyword",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -900,
        640
      ],
      "parameters": {
        "url": "=http://192.168.1.186:8080/api/v2/tables/mjmbcomto18scyi/records?where=(keyword,eq,{{ $json.keyword }})",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 1
            }
          }
        },
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "nocoDbApiToken"
      },
      "credentials": {
        "nocoDbApiToken": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "bb7cae83-8ff0-45d0-abca-d8d99efcfead",
      "name": "Check for YT Keyword",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -940,
        1260
      ],
      "parameters": {
        "url": "=http://192.168.1.186:8080/api/v2/tables/m8bp2fnwtqsd2m7/records/?where=(keyword,eq,{{ $json.keyword }})",
        "options": {},
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "nocoDbApiToken"
      },
      "credentials": {
        "nocoDbApiToken": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "e04d2f1c-45b6-4994-91a7-dc9f54a3fba8",
      "name": "Loop Over YT Keywords",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -1180,
        1240
      ],
      "parameters": {
        "options": {},
        "batchSize": 1000
      },
      "executeOnce": false,
      "typeVersion": 3
    },
    {
      "id": "452a67b4-d30c-4732-abc4-8b3513ec31f6",
      "name": "Update Second Tier G Keyword Data",
      "type": "n8n-nodes-base.nocoDb",
      "position": [
        -220,
        660
      ],
      "parameters": {
        "table": "mjmbcomto18scyi",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldName": "=keyword",
              "fieldValue": "={{ $('Split Out Google Search').item.json.keyword }}"
            },
            {
              "fieldName": "location_code",
              "fieldValue": "={{ $('Split Out Google Search').item.json.location_code }}"
            },
            {
              "fieldName": "language_code",
              "fieldValue": "={{ $('Split Out Google Search').item.json.language_code }}"
            },
            {
              "fieldName": "search_partners",
              "fieldValue": "={{ $('Split Out Google Search').item.json.search_partners }}"
            },
            {
              "fieldName": "competition",
              "fieldValue": "={{ $('Split Out Google Search').item.json.competition }}"
            },
            {
              "fieldName": "competition_index",
              "fieldValue": "={{ $('Split Out Google Search').item.json.competition_index }}"
            },
            {
              "fieldName": "cpc",
              "fieldValue": "={{ $('Split Out Google Search').item.json.cpc }}"
            },
            {
              "fieldName": "low_top_of_page_bid",
              "fieldValue": "={{ $('Split Out Google Search').item.json.low_top_of_page_bid }}"
            },
            {
              "fieldName": "high_top_of_page_bid",
              "fieldValue": "={{ $('Split Out Google Search').item.json.high_top_of_page_bid }}"
            },
            {
              "fieldName": "search_volume",
              "fieldValue": "={{ $('Split Out Google Search').item.json.search_volume }}"
            },
            {
              "fieldName": "id",
              "fieldValue": "={{ $json.list[0].Id }}"
            }
          ]
        },
        "operation": "update",
        "projectId": "pbwiwe87uf1cpgc",
        "authentication": "nocoDbApiToken"
      },
      "credentials": {
        "nocoDbApiToken": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "retryOnFail": true,
      "typeVersion": 3
    },
    {
      "id": "e50cc116-3b5b-4908-b0b6-8781360cb5f2",
      "name": "Update Second Tier YT Keyword Data",
      "type": "n8n-nodes-base.nocoDb",
      "position": [
        -440,
        1280
      ],
      "parameters": {
        "table": "m8bp2fnwtqsd2m7",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldName": "=keyword",
              "fieldValue": "={{ $('Split Out YT Search').item.json.keyword }}"
            },
            {
              "fieldName": "location_code",
              "fieldValue": "={{ $('Split Out YT Search').item.json.location_code }}"
            },
            {
              "fieldName": "language_code",
              "fieldValue": "={{ $('Split Out YT Search').item.json.language_code }}"
            },
            {
              "fieldName": "search_partners",
              "fieldValue": "={{ $('Split Out YT Search').item.json.search_partners }}"
            },
            {
              "fieldName": "competition",
              "fieldValue": "={{ $('Split Out YT Search').item.json.competition }}"
            },
            {
              "fieldName": "competition_index",
              "fieldValue": "={{ $('Split Out YT Search').item.json.competition_index }}"
            },
            {
              "fieldName": "cpc",
              "fieldValue": "={{ $('Split Out YT Search').item.json.cpc }}"
            },
            {
              "fieldName": "low_top_of_page_bid",
              "fieldValue": "={{ $('Split Out YT Search').item.json.low_top_of_page_bid }}"
            },
            {
              "fieldName": "high_top_of_page_bid",
              "fieldValue": "={{ $('Split Out YT Search').item.json.high_top_of_page_bid }}"
            },
            {
              "fieldName": "search_volume",
              "fieldValue": "={{ $('Split Out YT Search').item.json.search_volume }}"
            },
            {
              "fieldName": "id",
              "fieldValue": "={{ $json.list[0].Id }}"
            }
          ]
        },
        "operation": "update",
        "projectId": "pbwiwe87uf1cpgc",
        "authentication": "nocoDbApiToken"
      },
      "credentials": {
        "nocoDbApiToken": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "retryOnFail": true,
      "typeVersion": 3
    },
    {
      "id": "4ef57b89-913c-4e0e-8e60-675807ad6a5d",
      "name": "Loop Over Google Keywords",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -1160,
        620
      ],
      "parameters": {
        "options": {},
        "batchSize": 1000
      },
      "executeOnce": false,
      "typeVersion": 3
    },
    {
      "id": "94fbe48b-22bf-4a15-9ef0-423b1dab586a",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3540,
        1560
      ],
      "parameters": {
        "width": 1060,
        "height": 380,
        "content": "## Setup Instuctions: \n### Required: NocoDB, N8N, [DataforSEO Account *aff*](https://app.dataforseo.com/?aff=184401), and [Social Flood Docker Instance](https://github.com/rainmanjam/social-flood)\n### Tables for NocoDB\n-- Base Keyword Search (Keyword)\n-- Second Order Google Keywords( keyword, location_code, language_code, search_partners, competition, competition_index, search_volume, cpc, low_top_of_page, high_top_of_page)\n-- Second Order YouTube Keywords( keyword, location_code, language_code, search_partners, competition, competition_index, search_volume, cpc, low_top_of_page, high_top_of_page)\n-- Search Volume( unique_id, year, month, search_volume, youtube_keyword_id, google_keyword_id)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "8429c63d-09e7-47ac-a11b-e5132d5ac832",
      "name": "Combine G Keywords and Filter",
      "type": "n8n-nodes-base.code",
      "position": [
        -2300,
        800
      ],
      "parameters": {
        "jsCode": "// Gather all keywords from all items\nlet allKeywords = [];\n\nfor (const item of items) {\n  const keywordData = item.json.keyword_data;\n  const keywords = Object.values(keywordData)\n    .flatMap(section => Object.values(section))\n    .flat();\n\n  allKeywords = allKeywords.concat(keywords);\n}\n\n// Clean and transform the combined keywords\nconst cleanedKeywords = allKeywords\n  .filter(keyword => keyword.length <= 80)\n  .filter(keyword => keyword.split(\" \").length <= 10)\n  .map(keyword => keyword.replace(/[^a-zA-Z0-9\\s]/g, \"\"))\n  .map(keyword => keyword.trim())\n  .filter(keyword => keyword.length > 0)\n  .map(keyword => `\"${keyword}\"`);\n\n// Remove duplicates\nconst uniqueKeywords = Array.from(new Set(cleanedKeywords));\n\n// Split into batches of 1000\nconst batchSize = 1000;\nconst result = [];\n\nfor (let i = 0; i < uniqueKeywords.length; i += batchSize) {\n  result.push({\n    json: {\n      keywords: uniqueKeywords.slice(i, i + batchSize).join(\", \")\n    }\n  });\n}\n\n// Return as an array of objects\nreturn result;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "5aa39111-c1c1-440e-b0e8-ba5c54909a0d",
      "name": "Combine YT Keywords and Filter",
      "type": "n8n-nodes-base.code",
      "position": [
        -2300,
        1120
      ],
      "parameters": {
        "jsCode": "// Gather all keywords from all items\nlet allKeywords = [];\n\nfor (const item of items) {\n  const keywordData = item.json.keyword_data;\n  const keywords = Object.values(keywordData)\n    .flatMap(section => Object.values(section))\n    .flat();\n\n  allKeywords = allKeywords.concat(keywords);\n}\n\n// Clean and transform the combined keywords\nconst cleanedKeywords = allKeywords\n  .filter(keyword => keyword.length <= 80)\n  .filter(keyword => keyword.split(\" \").length <= 10)\n  .map(keyword => keyword.replace(/[^a-zA-Z0-9\\s]/g, \"\"))\n  .map(keyword => keyword.trim())\n  .filter(keyword => keyword.length > 0)\n  .map(keyword => `\"${keyword}\"`);\n\n// Remove duplicates\nconst uniqueKeywords = Array.from(new Set(cleanedKeywords));\n\n// Split into batches of 1000\nconst batchSize = 1000;\nconst result = [];\n\nfor (let i = 0; i < uniqueKeywords.length; i += batchSize) {\n  result.push({\n    json: {\n      keywords: uniqueKeywords.slice(i, i + batchSize).join(\", \")\n    }\n  });\n}\n\n// Return as an array of objects\nreturn result;\n"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "2712313f-4b1e-4f5b-8c6b-1f456896d981",
  "connections": {
    "NocoDB": {
      "main": [
        [
          {
            "node": "Second Order YouTube Autocomplete Keywords",
            "type": "main",
            "index": 0
          },
          {
            "node": "Second Order Google Autocomplete Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gen Time": {
      "main": [
        [
          {
            "node": "NocoDB",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "YT Filter": {
      "main": [
        [
          {
            "node": "Loop Over YT Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format G Data": {
      "main": [
        [
          {
            "node": "Bulk Import G Monthly Search Volume",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Filter": {
      "main": [
        [
          {
            "node": "Loop Over Google Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format YT Data": {
      "main": [
        [
          {
            "node": "Bulk Import YT Monthly Search Volume",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Gen Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out YT Search": {
      "main": [
        [
          {
            "node": "YT Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check for YT Keyword": {
      "main": [
        [
          {
            "node": "Is YT Keyword Avaliable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Search Volume": {
      "main": [
        [
          {
            "node": "Split Out Google Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over YT Keywords": {
      "main": [
        [],
        [
          {
            "node": "Check for YT Keyword",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "YouTube Search Volume": {
      "main": [
        [
          {
            "node": "Split Out YT Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is YT Keyword Avaliable": {
      "main": [
        [
          {
            "node": "Add Second Tier YT Keyword Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Update Second Tier YT Keyword Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out Google Search": {
      "main": [
        [
          {
            "node": "Google Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check for Google Keyword": {
      "main": [
        [
          {
            "node": "Is Google Keyword Available",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Google Keywords": {
      "main": [
        [],
        [
          {
            "node": "Check for Google Keyword",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Google Keyword Available": {
      "main": [
        [
          {
            "node": "Add Second Tier G Keyword Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Update Second Tier G Keyword Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine G Keywords and Filter": {
      "main": [
        [
          {
            "node": "Google Search Volume",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Second Tier G Keyword Data": {
      "main": [
        [
          {
            "node": "Format G Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine YT Keywords and Filter": {
      "main": [
        [
          {
            "node": "YouTube Search Volume",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Second Tier YT Keyword Data": {
      "main": [
        [
          {
            "node": "Format YT Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Second Tier G Keyword Data": {
      "main": [
        [
          {
            "node": "Loop Over Google Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Test workflow\u2019": {
      "main": [
        [
          {
            "node": "Gen Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Second Tier YT Keyword Data": {
      "main": [
        [
          {
            "node": "Loop Over YT Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Bulk Import G Monthly Search Volume": {
      "main": [
        [
          {
            "node": "Loop Over Google Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Bulk Import YT Monthly Search Volume": {
      "main": [
        [
          {
            "node": "Loop Over YT Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Second Order Google Autocomplete Keywords": {
      "main": [
        [
          {
            "node": "Combine G Keywords and Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Second Order YouTube Autocomplete Keywords": {
      "main": [
        [
          {
            "node": "Combine YT Keywords and Filter",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

How this works

Discover the most relevant keywords for your content or SEO strategy effortlessly with this workflow, which analyses search trends to prioritise high-impact terms that drive traffic and engagement. Ideal for marketers, content creators, and SEO specialists seeking data-driven insights without manual research. The key step involves querying Google Autocomplete via HTTP requests to generate second-order keyword suggestions, followed by storing and ranking results in NocoDB for easy access and analysis.

Use this workflow when you need periodic keyword updates for ongoing campaigns or ad optimisation, especially in competitive niches like e-commerce or blogging. Avoid it for real-time queries or if you lack API access to Google services, as it relies on scheduled or event-based triggers. Common variations include adapting the HTTP requests for other search engines like Bing or integrating additional filters in NocoDB to focus on long-tail keywords.

About this workflow

Find Top Keywords. Uses manualTrigger, scheduleTrigger, stickyNote, nocoDb. Event-driven trigger; 35 nodes.

Source: https://github.com/Zie619/n8n-workflows — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

Simple LinkedIn profile collector. Uses manualTrigger, httpRequest, stickyNote, convertToFile. Event-driven trigger; 23 nodes.

HTTP Request, OpenAI, Noco Db
Data & Sheets

Workflow Importer. Uses extractFromFile, executeCommand, readWriteFile, httpRequest. Event-driven trigger; 58 nodes.

Execute Command, Read Write File, HTTP Request +3
Data & Sheets

Retrieves workflows directly from an n8n instance using the n8n API Dynamically generates a form to select which workflows to import Supports both fixed instance configuration and dynamic source/targe

Form Trigger, Form, Notion +2
Data & Sheets

[2/3] Set up medoids (2 types) for anomaly detection (crops dataset). Uses manualTrigger, httpRequest, splitOut, stickyNote. Event-driven trigger; 48 nodes.

HTTP Request
Data & Sheets

Splitout Limit. Uses httpRequest, splitOut, removeDuplicates, splitInBatches. Event-driven trigger; 40 nodes.

HTTP Request, n8n, Form Trigger +1