AutomationFlowsAI & RAG › Ai-powered Product Hunt Data Collection & Translation with Gpt-4 and Google…

Ai-powered Product Hunt Data Collection & Translation with Gpt-4 and Google…

Original n8n title: Ai-powered Product Hunt Data Collection & Translation with Gpt-4 and Google Sheets

ByAmine ARAGRAG @aminearg on n8n.io

It fetches new tools daily, translates content, categorizes them intelligently, and saves everything into a structured spreadsheet—ideal for building directories, research dashboards, newsletters, or competitive intelligence assets. Sticky notes inside the workflow explain each…

Cron / scheduled trigger★★★★☆ complexityAI-powered23 nodesGoogle SheetsOpenAI ChatGoogle Sheets ToolHTTP RequestAgent
AI & RAG Trigger: Cron / scheduled Nodes: 23 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #10791 — we link there as the canonical source.

This workflow follows the Agent → Google Sheets 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 →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "65a90e6a-4947-4d6d-8c5c-f87adbc128f9",
      "name": "Section: Initialization",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1760,
        440
      ],
      "parameters": {
        "color": 7,
        "width": 520,
        "height": 440,
        "content": "## Initialization\nStarts the workflow daily and sets the initial cursor for pagination."
      },
      "typeVersion": 1
    },
    {
      "id": "dbd5a1cb-3480-4256-8f63-0eef838efdad",
      "name": "Section: Data Fetching",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1200,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 660,
        "height": 400,
        "content": "## Data Fetching\nCalls the Product Hunt API and restructures each post into clean JSON fields.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "ae445ee4-010f-45c6-b575-bdd349dcf441",
      "name": "Section: Duplicate Check",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -500,
        400
      ],
      "parameters": {
        "color": 7,
        "width": 420,
        "height": 500,
        "content": "## Duplicate Check\nLooks up each tool by title in Google Sheets and only processes new entries.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "cbacda8f-9f8a-4710-beaf-714693dd9c1e",
      "name": "Section: AI Enrichment",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -40,
        200
      ],
      "parameters": {
        "color": 7,
        "width": 700,
        "height": 860,
        "content": "## AI Enrichment\nUses an AI agent to translate text, map categories, extract tech, and generate documentation.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e16f5262-ef32-4995-9511-3dde2a322424",
      "name": "Section: Persistence & Control",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        740,
        300
      ],
      "parameters": {
        "color": 7,
        "width": 1560,
        "height": 760,
        "content": "## Save & Loop Control\nWrites enriched tools to Google Sheets and manages pagination until all pages are processed.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a2c4cad8-fdea-4bcb-88d0-58f038a271bd",
      "name": "Save Enriched Tool to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        800,
        580
      ],
      "parameters": {
        "columns": {
          "value": {
            "Title": "={{ $json.Title }}"
          },
          "schema": [
            {
              "id": "Title",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "TitleFrench",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "TitleFrench",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "DescriptionFrench",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "DescriptionFrench",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "category",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "category",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "categoryFrench",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "categoryFrench",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "tech",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "tech",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "FunctionArea",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "FunctionArea",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "UrlDemo",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "UrlDemo",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "UrlGithub",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "UrlGithub",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "UrlVideo",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "UrlVideo",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "UrlLogo",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "UrlLogo",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "DocumentationMarkdown",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "DocumentationMarkdown",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "DocumentationMarkdownFrench",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "DocumentationMarkdownFrench",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "error",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "error",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "rawOutput",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "rawOutput",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "output",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "output",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "Title"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1688959666,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/YOUR_AWS_SECRET_KEY_HERE_BLy9Q/edit#gid=1688959666",
          "cachedResultName": "Tools"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1R5oMqm8QPfNlKagfdY566iGR7i4bamonmtRD3_BLy9Q",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/YOUR_AWS_SECRET_KEY_HERE_BLy9Q/edit?usp=drivesdk",
          "cachedResultName": "Porduct Hunt Scraping Tools - AIC_DEV N8N"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "26b897df-bbb4-475c-b148-5458de4eb838",
      "name": "Is Tool New?",
      "type": "n8n-nodes-base.if",
      "position": [
        -240,
        660
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "a2c0be21-5a8a-48eb-9926-db19cb90b26d",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.isEmpty() }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b11b0e86-5606-428b-8d8c-a43f63cf0227",
      "name": "Lookup Existing Tool by Title",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -460,
        660
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $json.Title }}",
              "lookupColumn": "Title"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1688959666,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/YOUR_AWS_SECRET_KEY_HERE_BLy9Q/edit#gid=1688959666",
          "cachedResultName": "Tools"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1R5oMqm8QPfNlKagfdY566iGR7i4bamonmtRD3_BLy9Q",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/YOUR_AWS_SECRET_KEY_HERE_BLy9Q/edit?usp=drivesdk",
          "cachedResultName": "Porduct Hunt Scraping Tools - AIC_DEV N8N"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "typeVersion": 4.6,
      "alwaysOutputData": true
    },
    {
      "id": "9b7f5c9e-0723-4cfc-b3a9-b0d1c5a0763c",
      "name": "Safety Limit Check (>50 iterations)",
      "type": "n8n-nodes-base.if",
      "position": [
        1980,
        800
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d3030029-4e31-4527-a2b0-86b6db1ec07f",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{$runIndex}}",
              "rightValue": 50
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "290975c3-0989-4666-9b6c-3c1be4c9a7d1",
      "name": "OpenAI GPT-4.1 Mini",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        20,
        840
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "09751390-74e4-462d-abc0-45b624a2e325",
      "name": "Daily Trigger at 9 AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1700,
        680
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 9
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "783ceba3-40bc-4e43-a0d1-7e1136453eea",
      "name": "Clean & Parse AI JSON Output",
      "type": "n8n-nodes-base.code",
      "position": [
        400,
        580
      ],
      "parameters": {
        "jsCode": "return items.map(item => {\n  let raw = item.json.output;\n\n  // If the output is empty, skip or return an empty object\n  if (!raw || raw.trim() === '') {\n    return { json: { error: \"Empty output\", rawOutput: raw || null } };\n  }\n\n  // Remove markdown backticks like ```json or ``` and trim\n  raw = raw.replace(/```json|```/g, '').trim();\n\n  try {\n    // Parse the cleaned JSON\n    const parsed = JSON.parse(raw);\n    return { json: parsed };\n  } catch (err) {\n    // If JSON is invalid, return an error for debugging\n    return {\n      json: {\n        error: \"Invalid JSON\",\n        message: err.message,\n        rawOutput: raw\n      }\n    };\n  }\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "8d0fcd7e-7439-4455-99f2-451d45addc2c",
      "name": "Extract Pagination Info",
      "type": "n8n-nodes-base.set",
      "position": [
        1100,
        720
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "c553dd87-d266-4394-a7c6-647cead1f6f6",
              "name": "cursor",
              "type": "string",
              "value": "={{ $('Fetch Products from Product Hunt API').first().json.data.posts.pageInfo.endCursor }}"
            },
            {
              "id": "92bdd4bd-f447-4a70-9ade-a58253b7e8ba",
              "name": "hasnextpage",
              "type": "boolean",
              "value": "={{ $('Fetch Products from Product Hunt API').first().json.data.posts.pageInfo.hasNextPage }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "1f8510ff-30de-471d-9af3-72bd919fa5ee",
      "name": "Restructure API Response to JSON",
      "type": "n8n-nodes-base.code",
      "position": [
        -740,
        680
      ],
      "parameters": {
        "jsCode": "const edges = $json.data.posts.edges;\n\nconst structured = edges.map(({ node }) => ({\n  Title: node.name,\n  TitleFrench: \"\" ,\n  Description: node.description,\n  DescriptionFrench: \"\" ,\n  category: node.topics?.edges.map(t => t.node.name) || [],\n  categoryFrench: \"\",\n  tech: node.topics?.edges.map(t => t.node.name) || [] ,\n  FunctionArea: \"\",\n  UrlDemo: node.website,\n  UrlGithub: \"\" ,\n  UrlVideo: (node.media && node.media.length > 0) \n    ? node.media.find(m => m.videoUrl)?.videoUrl || null \n    : null,\n  UrlLogo: node.thumbnail?.url || null,\n  DocumentationMarkdown: \"\" , \n  DocumentationMarkdownFrench: \"\"\n}));\n\nreturn structured.map(item => ({ json: item }));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "41571e69-54d2-4bf2-8bd1-62a53831696e",
      "name": "Update Category Dictionary (Write)",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        440,
        820
      ],
      "parameters": {
        "columns": {
          "value": {
            "Category Name French": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Category_Name_French', ``, 'string') }}",
            "Category Name English": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Category_Name_English', ``, 'string') }}"
          },
          "schema": [
            {
              "id": "Category Name English",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Category Name English",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Category Name French",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Category Name French",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Category Name English"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 872597000,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/YOUR_AWS_SECRET_KEY_HERE_BLy9Q/edit#gid=872597000",
          "cachedResultName": "Category_Dectionnaire"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1R5oMqm8QPfNlKagfdY566iGR7i4bamonmtRD3_BLy9Q",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/YOUR_AWS_SECRET_KEY_HERE_BLy9Q/edit?usp=drivesdk",
          "cachedResultName": "Porduct Hunt Scraping Tools - AIC_DEV N8N"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "710db2c5-d110-4261-99c6-0e8ae2a201da",
      "name": "Lookup Category Dictionary (Read)",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        240,
        820
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 872597000,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/YOUR_AWS_SECRET_KEY_HERE_BLy9Q/edit#gid=872597000",
          "cachedResultName": "Category_Dectionnaire"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1R5oMqm8QPfNlKagfdY566iGR7i4bamonmtRD3_BLy9Q",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/YOUR_AWS_SECRET_KEY_HERE_BLy9Q/edit?usp=drivesdk",
          "cachedResultName": "Porduct Hunt Scraping Tools - AIC_DEV N8N"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "b3ec4d3e-d36e-4b6d-aef7-dc3ad47e4eec",
      "name": "Fetch Products from Product Hunt API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1060,
        680
      ],
      "parameters": {
        "url": "https://api.producthunt.com/v2/api/graphql",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"query\": \"{ posts(order: RANKING, first:5 , after: \\\"{{ $json.cursor }}\\\") { edges { cursor node { name description tagline website thumbnail { url } topics { edges { node { name } } } media { videoUrl type url } productLinks { type url } } } pageInfo { endCursor hasNextPage } } }\"\n} ",
        "sendBody": true,
        "jsonHeaders": "{\n  \"Content-Type\": \"application/json\",\n  \"Accept\": \"application/json\"\n}",
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "specifyHeaders": "json",
        "genericAuthType": "oAuth2Api"
      },
      "credentials": {
        "oAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "70561358-e0d5-437a-82b6-65a43bca85bf",
      "name": "AI Agent: Translate & Enrich Product Data",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        40,
        580
      ],
      "parameters": {
        "text": "={{JSON.stringify($json)}}",
        "options": {
          "maxIterations": 8,
          "systemMessage": "=You are a helpful assistant. **Your tasks are:**\n\n---\n\n## **1. Translation**\n\n* Create two additional fields:\n\n  * **TitleFrench** \u2192 French translation of the value in **Title** (keep the original Title as-is).\n  * **DescriptionFrench** \u2192 French translation of the value in **Description** (keep the original Description as-is).\n\n---\n\n## **2. Category Translation Handling with Google Sheets Dictionary**\n\n* A Google Sheets dictionary exists with two columns:\n\n  * **Category Name English**\n  * **Category Name French**\n\n### **Steps:**\n\n1. Search for the **category** in the **Category Name English** column.\n2. **If a match exists**, retrieve the corresponding value from **Category Name French** and assign it to **categoryFrench**.\n3. **If no match exists**, translate the category into French, then:\n\n   * Add a new row to the dictionary with:\n\n     * Column 1 \u2192 Original English category\n     * Column 2 \u2192 Translated French category\n   * Assign this translation to **categoryFrench**.\n4. **Ensure no duplicates are added. Always check before inserting a new row.**\n\n---\n\n## **3. Content Generation**\n\nBased on the **Title**, **Description**, and **category**, generate the following fields:\n\n* **FunctionArea** \u2192 A short, meaningful English phrase summarizing the main purpose or domain of the product (e.g., *\"AI for HR\"*, *\"Design Automation\"*).\n* **DocumentationMarkdown** \u2192 A concise English guide (1\u20132 short paragraphs or step-by-step instructions) explaining:\n\n  * What the product does.\n  * How to use it effectively.\n* **DocumentationMarkdownFrench** \u2192 French translation of **DocumentationMarkdown**.\n* **tech** \u2192 A list of technologies mentioned explicitly in the **Description**.\n\n  * **Do not infer or guess.** If none are mentioned, return an empty list.\n\n---\n\n## **4. Preserve Other Fields**\n\nKeep all other provided fields and their original values as they are.\n\n\n---\n\n### **Example Input:**\n\n\n{\n  \"Title\": \"{{ $json.Title }}\",\n  \"TitleFrench\": \"{{ $json.TitleFrench }}\",\n  \"Description\": \"{{ $json.Description }}\",\n  \"DescriptionFrench\": \"{{ $json.DescriptionFrench }}\",\n  \"category\": \"{{ $json.category }}\",\n  \"tech\": \"{{ $json.tech }}\",\n  \"FunctionArea\": \"{{ $json.FunctionArea }}\",\n  \"UrlDemo\": \"{{ $json.UrlDemo }}\",\n  \"UrlGithub\": \"{{ $json.UrlGithub }}\",\n  \"UrlVideo\": \"{{ $json.UrlVideo }}\",\n  \"UrlLogo\": \"{{ $json.UrlLogo }}\",\n  \"DocumentationMarkdown\": \"{{ $json.DocumentationMarkdown }}\",\n  \"DocumentationMarkdownFrench\": \"{{ $json.DocumentationMarkdownFrench }}\"\n}\n\n---\n\n## **5. Output Requirements**\n\nReturn a **valid JSON object** with **all the following fields**:\n\n* `Title` (unchanged)\n* `TitleFrench` (translated)\n* `Description` (unchanged)\n* `DescriptionFrench` (translated)\n* `category` (unchanged)\n* `categoryFrench` (from Google Sheets logic above)\n* `tech` (list of technologies explicitly mentioned)\n* `FunctionArea` (generated in English)\n* `UrlDemo` (unchanged)\n* `UrlGithub` (unchanged)\n* `UrlVideo` (unchanged)\n* `UrlLogo` (unchanged)\n* `DocumentationMarkdown` (generated in English)\n* `DocumentationMarkdownFrench` (translated to French)\n\n\n---\n\n### **Important Rules:**\nBefore adding any new category translation to the Google Sheets dictionary:\n\nFirst, check the Category Name English column in the sheet.\n\nIf the category already exists, directly use the corresponding French translation from the sheet (categoryFrench).\n\nOnly if it doesn't exist, translate the category to French and:\n\nAdd a new row to the sheet:\n\nColumn 1 \u2192 Original English category\n\nColumn 2 \u2192 Translated French category\n\nDo not add duplicates under any condition.\n\nOutput only valid raw JSON, with no markdown formatting (no ```json) and no stringified JSON.\n\nDo not return explanations, notes, or wrappers \u2014 just a pure JSON object or array, machine-readable.\n\nThe final JSON must be fully parsable by automation tools like n8n without modification."
        },
        "promptType": "define"
      },
      "retryOnFail": true,
      "typeVersion": 1.7,
      "waitBetweenTries": 5000
    },
    {
      "id": "02607c5c-04ac-45a1-909b-b3244b396790",
      "name": "Rate Limit: Wait 15 Seconds",
      "type": "n8n-nodes-base.wait",
      "position": [
        1760,
        720
      ],
      "parameters": {
        "amount": 15
      },
      "typeVersion": 1.1
    },
    {
      "id": "9e4042f6-7499-4428-9a3d-3110330ff045",
      "name": "Initialize Starting Cursor",
      "type": "n8n-nodes-base.set",
      "position": [
        -1480,
        680
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "22be683f-3845-440f-b7ef-bbca424395cd",
              "name": "cursor",
              "type": "string",
              "value": "null"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "8def33bb-0c59-4b3b-9cc3-5e714b068b6a",
      "name": "Has Next Page?",
      "type": "n8n-nodes-base.if",
      "position": [
        1320,
        720
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "ed008eb8-a64c-4234-a72f-97cff2f2e41d",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.hasnextpage }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "7780bff4-63df-4cee-bad6-2426230e333c",
      "name": "Continue Loop",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1540,
        720
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "e23e20c5-e0c9-4a69-bbf0-728d93b98a66",
      "name": "Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2500,
        260
      ],
      "parameters": {
        "width": 600,
        "height": 620,
        "content": "## \ud83d\udccb Product Hunt AI Enrichment Workflow\n\nThis workflow automatically discovers new Product Hunt tools, enriches them with AI-generated insights, and stores everything in a structured Google Sheet. It helps you build and maintain a living database of Product Hunt launches without manual copy-paste.\n\n### How it works\nEvery day, a schedule trigger calls the Product Hunt GraphQL API with cursor-based pagination. For each post, the workflow restructures the data (title, description, topics, website, media) and checks your Google Sheet to avoid duplicates. Only new tools are sent to an AI agent, which translates the title and description into French, maps categories using a dictionary sheet, extracts any explicitly mentioned tech stack, and generates simple English/French Markdown documentation. The enriched record is then saved to your Tools sheet, and the loop continues until there are no more pages or the safety limit is reached.\n\n### Setup steps\n1. Add your Product Hunt OAuth2 credentials to the HTTP Request node.\n2. Connect your Google account and select the Tools and Category Dictionary sheets.\n3. Add your OpenAI (GPT-4.1-mini) credentials.\n4. Adjust sheet IDs, ranges, or column names if your structure is different.\n5. Enable the daily trigger when you are ready to run it automatically."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Is Tool New?": {
      "main": [
        [
          {
            "node": "AI Agent: Translate & Enrich Product Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Extract Pagination Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Continue Loop": {
      "main": [
        [
          {
            "node": "Rate Limit: Wait 15 Seconds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Next Page?": {
      "main": [
        [
          {
            "node": "Continue Loop",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI GPT-4.1 Mini": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent: Translate & Enrich Product Data",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Daily Trigger at 9 AM": {
      "main": [
        [
          {
            "node": "Initialize Starting Cursor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Pagination Info": {
      "main": [
        [
          {
            "node": "Has Next Page?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Initialize Starting Cursor": {
      "main": [
        [
          {
            "node": "Fetch Products from Product Hunt API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rate Limit: Wait 15 Seconds": {
      "main": [
        [
          {
            "node": "Safety Limit Check (>50 iterations)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Enriched Tool to Sheet": {
      "main": [
        [
          {
            "node": "Extract Pagination Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clean & Parse AI JSON Output": {
      "main": [
        [
          {
            "node": "Save Enriched Tool to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Existing Tool by Title": {
      "main": [
        [
          {
            "node": "Is Tool New?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Restructure API Response to JSON": {
      "main": [
        [
          {
            "node": "Lookup Existing Tool by Title",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Category Dictionary (Read)": {
      "ai_tool": [
        [
          {
            "node": "AI Agent: Translate & Enrich Product Data",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Update Category Dictionary (Write)": {
      "ai_tool": [
        [
          {
            "node": "AI Agent: Translate & Enrich Product Data",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Safety Limit Check (>50 iterations)": {
      "main": [
        [],
        [
          {
            "node": "Fetch Products from Product Hunt API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Products from Product Hunt API": {
      "main": [
        [
          {
            "node": "Restructure API Response to JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent: Translate & Enrich Product Data": {
      "main": [
        [
          {
            "node": "Clean & Parse AI JSON Output",
            "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

About this workflow

It fetches new tools daily, translates content, categorizes them intelligently, and saves everything into a structured spreadsheet—ideal for building directories, research dashboards, newsletters, or competitive intelligence assets. Sticky notes inside the workflow explain each…

Source: https://n8n.io/workflows/10791/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

Marketing, content, and enablement teams that need a quick, human-readable summary of every new video published by the YouTube channels they care about—without leaving Slack.

HTTP Request, Google Sheets, XML +7
AI & RAG

Template Name: AI Personal Assistant - Task & Email Management Price: $27 Category: Productivity & Automation Difficulty: Intermediate Use Case: Personal productivity automation for busy professionals

Telegram, HTTP Request, OpenAI +8
AI & RAG

This workflow automates end-to-end ESG (Environmental, Social, and Governance) sustainability reporting for enterprise sustainability teams, compliance officers, and green governance leads. It solves

Agent, OpenAI Chat, Output Parser Structured +12
AI & RAG

This workflow performs a comprehensive, automated monthly SEO and performance audit for any website. It uses a "team" of specialized AI agents to analyze data from multiple sources, aggregates their f

OpenAI Chat, Google Sheets Tool, HTTP Request +3
AI & RAG

Schedules automated vendor pricing analysis across multiple sources. Fetches delivery reliability and contract data, analyzes vendor performance using Claude AI, then distributes consolidated reports

HTTP Request, Airtable, OpenAI Chat +9