AutomationFlowsSocial Media › Optimize Instagram Hashtags with Gpt-4o & Real Engagement Data via Graph API

Optimize Instagram Hashtags with Gpt-4o & Real Engagement Data via Graph API

ByShun Nakayama @nakayama on n8n.io

This workflow automatically generates optimal hashtags for your Instagram posts by analyzing captions and fetching real-time engagement data.

Event trigger★★★★☆ complexityAI-powered29 nodesOpenAI ChatChain LlmGoogle SheetsFacebook Graph ApiExecute Workflow Trigger
Social Media Trigger: Event Nodes: 29 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Chainllm → Execute Workflow Trigger 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
{
  "id": "6336I5qyz7eI9Awi",
  "name": "Generate Instagram hashtags using OpenAI and Graph API",
  "tags": [],
  "nodes": [
    {
      "id": "af47f63f-2c54-4e11-9be2-66f9a3983049",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        1664,
        2752
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "97f03e91-0108-4fd8-bd0f-c0bf691dab6b",
      "name": "Set Dummy Caption",
      "type": "n8n-nodes-base.set",
      "position": [
        1888,
        2752
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "caption-assign",
              "name": "caption",
              "type": "string",
              "value": "Just built an amazing automation workflow with n8n! \ud83d\ude80 It connects my apps and saves me hours every week."
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "51119ee4-4be2-454e-ae24-713849ebb3c5",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2144,
        2912
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "1cd632c4-cee8-46eb-b334-935dc640d525",
      "name": "Generate Initial Hashtags",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        2144,
        2576
      ],
      "parameters": {
        "text": "=Please suggest 10 English hashtags relevant to the following post caption.\nInclude a balance of big words (high post volume) and niche ones.\n\nCaption:\n{{ $json.caption }}\n\nOutput ONLY in the following JSON format.\n[\"keyword1\", \"keyword2\", ...]",
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.4
    },
    {
      "id": "e47315ec-3fa6-48d8-b404-08ab28d165e5",
      "name": "Parse & Clean Tags",
      "type": "n8n-nodes-base.code",
      "position": [
        2448,
        2576
      ],
      "parameters": {
        "jsCode": "const content = $input.first().json.text;\n// Extract JSON array from text\nconst match = content.match(/\\[.*\\]/s);\nif (!match) throw new Error(\"No JSON array found\");\nconst tags = JSON.parse(match[0]);\n\nreturn tags.map(tag => ({ json: { tag: tag.replace('#', '') } }));"
      },
      "typeVersion": 2
    },
    {
      "id": "e9f84e2b-ce3b-4078-b1a1-3630f65c8715",
      "name": "Fetch Cached Hashtags",
      "type": "n8n-nodes-base.googleSheets",
      "onError": "continueRegularOutput",
      "position": [
        2448,
        2832
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "YOUR_SHEET_NAME_OR_ID"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SPREADSHEET_ID"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "3518e6e7-65ba-45df-b6a8-3e2dcabd741d",
      "name": "Split In Batches",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        3408,
        2576
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "b4336549-b98d-4c94-ada7-c06671456392",
      "name": "Check if Tag Exists",
      "type": "n8n-nodes-base.if",
      "position": [
        3840,
        2144
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "check-id-exists",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.data && $json.data.length > 0 }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1fc9bb2a-9e23-49c5-8ca9-1f93011e96d4",
      "name": "Save to Cache",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4880,
        2064
      ],
      "parameters": {
        "columns": {
          "value": {
            "tag": "={{ $json.tag }}",
            "average_likes": "={{ $json.average_likes }}",
            "average_comments": "={{ $json.average_comments }}"
          },
          "schema": [
            {
              "id": "tag",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "tag",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "average_likes",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "average_likes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "average_comments",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "average_comments",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "YOUR_SHEET_NAME_OR_ID"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SPREADSHEET_ID"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "db82c644-e0fe-4142-847c-f9f189ac1607",
      "name": "Rate Limit Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        5104,
        2256
      ],
      "parameters": {
        "unit": "seconds",
        "amount": 2
      },
      "typeVersion": 1
    },
    {
      "id": "a9f06fe5-9133-42eb-976b-aa9b37a0f47d",
      "name": "Merge Cache & Fresh",
      "type": "n8n-nodes-base.merge",
      "position": [
        3696,
        2704
      ],
      "parameters": {},
      "typeVersion": 2.1
    },
    {
      "id": "4a59c75e-5769-4496-969e-30a16384b156",
      "name": "Aggregate & Rank Candidates",
      "type": "n8n-nodes-base.code",
      "position": [
        3872,
        2704
      ],
      "parameters": {
        "jsCode": "// Get data from previous nodes\n// Cached items\nconst cachedItems = $input.all().map(i => i.json).filter(i => i.source === 'cache');\n\n// Fresh items\nlet freshItems = [];\ntry {\n    freshItems = $('Format New Hashtag Data').all().map(i => i.json);\n} catch (e) {}\n\nconst allItems = [...cachedItems, ...freshItems];\n\n// Sort by average_likes desc\nallItems.sort((a, b) => (b.average_likes || 0) - (a.average_likes || 0));\n\n// Pick Top 15 candidates for AI to choose from\nconst candidates = allItems.slice(0, 15).map(i => ({\n    tag: i.tag || i.name,\n    likes: i.average_likes || 0,\n    comments: i.average_comments || 0\n}));\n\n// Get original caption for context. Handle both manual trigger and workflow trigger paths.\nlet caption = '';\ntry {\n    caption = $('Set Dummy Caption').first().json.caption;\n} catch(e) {}\n\nif (!caption) {\n    try {\n        caption = $('Workflow Trigger').first().json.caption;\n    } catch(e) {}\n}\n\nreturn { json: { caption, candidates } };"
      },
      "typeVersion": 2
    },
    {
      "id": "cf3d233b-5c53-4977-91af-2b462767a4c3",
      "name": "Format New Hashtag Data",
      "type": "n8n-nodes-base.set",
      "position": [
        4656,
        2064
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "tag-mapping",
              "name": "tag",
              "type": "string",
              "value": "={{ $('Split In Batches').item.json.tag }}"
            },
            {
              "id": "count-mapping",
              "name": "average_likes",
              "type": "number",
              "value": "={{ $json.average_likes }}"
            },
            {
              "id": "4ba7ae2a-11f6-436d-bf9d-005d3c7c8265",
              "name": "average_comments",
              "type": "number",
              "value": "={{ $json.average_comments }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "30863e06-c7f4-4711-85b1-d3d8dff49c3b",
      "name": "Check Cache Status",
      "type": "n8n-nodes-base.code",
      "inputs": [
        "main"
      ],
      "output": [
        "Uncached",
        "Cached"
      ],
      "position": [
        2960,
        2736
      ],
      "parameters": {
        "jsCode": "const allItems = $input.all();\nconst sheetRows = allItems.filter(i => i.json.tag && (i.json.average_likes !== undefined || i.json.media_count !== undefined)).map(i => i.json);\nconst aiTags = allItems.filter(i => !i.json.average_likes && !i.json.media_count && i.json.tag).map(i => i.json.tag);\n\nconst sheetMap = new Map();\nsheetRows.forEach(row => {\n    if(row.tag) {\n        // Convert to number if possible, undefined only if empty/invalid\n        const likes = row.average_likes !== '' && row.average_likes !== null ? Number(row.average_likes) : undefined;\n        const comments = row.average_comments !== '' && row.average_comments !== null ? Number(row.average_comments) : undefined;\n        const media = row.media_count !== '' && row.media_count !== null ? Number(row.media_count) : undefined;\n\n        // Normalize cache keys to lowercase\n        const cleanTag = row.tag.replace('#','').toLowerCase();\n        sheetMap.set(cleanTag, {\n            average_likes: !isNaN(likes) ? likes : undefined,\n            average_comments: !isNaN(comments) ? comments : undefined,\n            media_count: !isNaN(media) ? media : undefined\n        });\n    }\n});\n\nconst results = [];\naiTags.forEach(tag => {\n    // Normalize input to lowercase\n    const cleanTag = tag.replace('#','').toLowerCase();\n    const cache = sheetMap.get(cleanTag);\n    // Only treat as cache if we have the new metric (average_likes) as a valid number\n    if (cache && typeof cache.average_likes === 'number') {\n        results.push({ json: { \n            tag: cleanTag, \n            ...cache,\n            source: 'cache' \n        }});\n    } else {\n        results.push({ json: { tag: cleanTag, source: 'new' } });\n    }\n});\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "684590af-e173-4e7d-8275-8755b053ce65",
      "name": "Merge Input",
      "type": "n8n-nodes-base.merge",
      "position": [
        2784,
        2736
      ],
      "parameters": {},
      "typeVersion": 2.1
    },
    {
      "id": "c4accef3-aa36-4f62-8105-2aa5dacad19d",
      "name": "Route Cached vs New",
      "type": "n8n-nodes-base.if",
      "position": [
        3136,
        2736
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "check-cache-source",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.source }}",
              "rightValue": "cache"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "9257d4bd-8f58-46d4-b076-626c70985a58",
      "name": "Get Hashtag Info",
      "type": "n8n-nodes-base.facebookGraphApi",
      "onError": "continueErrorOutput",
      "position": [
        3600,
        2224
      ],
      "parameters": {
        "node": "ig_hashtag_search",
        "options": {
          "queryParameters": {
            "parameter": [
              {
                "name": "user_id",
                "value": "YOUR_INSTAGRAM_BUSINESS_ACCOUNT_ID"
              },
              {
                "name": "q",
                "value": "={{ $('Split In Batches').item.json.tag }}"
              }
            ]
          }
        },
        "graphApiVersion": "v18.0"
      },
      "credentials": {
        "facebookGraphApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4421b2d4-e25e-4f85-9cee-e62b009c1243",
      "name": "Get Hashtag Metrics",
      "type": "n8n-nodes-base.facebookGraphApi",
      "position": [
        4192,
        2064
      ],
      "parameters": {
        "edge": "top_media",
        "node": "={{ $json.data[0].id }}",
        "options": {
          "queryParameters": {
            "parameter": [
              {
                "name": "fields",
                "value": "like_count, comments_count"
              },
              {
                "name": "user_id",
                "value": "YOUR_INSTAGRAM_BUSINESS_ACCOUNT_ID"
              }
            ]
          }
        },
        "graphApiVersion": "v18.0"
      },
      "credentials": {
        "facebookGraphApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7ac65007-39c9-4167-8ad6-677f7eee0ca5",
      "name": "Calculate Average Metrics",
      "type": "n8n-nodes-base.code",
      "position": [
        4432,
        2064
      ],
      "parameters": {
        "jsCode": "// Get input data (Facebook API node \"data\" array)\nconst items = $input.all()[0].json.data;\n\nif (!items || items.length === 0) {\n  return { average_likes: 0, average_comments: 0 };\n}\n\nconst totalPosts = items.length;\nconst totalLikes = items.reduce((sum, post) => sum + (post.like_count || 0), 0);\nconst totalComments = items.reduce((sum, post) => sum + (post.comments_count || 0), 0);\n\n// Output specific format\nreturn {\n  average_likes: Math.round(totalLikes / totalPosts),\n  average_comments: Math.round(totalComments / totalPosts)\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "b2314331-1173-4f24-868c-7f37d18d3181",
      "name": "AI Model Selector",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        4064,
        2880
      ],
      "parameters": {
        "model": "gpt-5-mini",
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "90d1db2f-ba32-4efe-a167-82e9d8a3338e",
      "name": "Select Top 5 Hashtags",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        4064,
        2704
      ],
      "parameters": {
        "text": "=You are an Instagram Professional.\n\nAnalyze the following post caption and the candidate hashtag list (with average likes). Select the **5 best hashtags** that balance **\"Relevance to the post\"** and **\"High Engagement (Likes)\"**.\n\n[Selection Criteria]\n1. Must accurately reflect the post content (Prioritize Relevance).\n2. Do NOT select irrelevant tags even if they have many likes.\n3. Include niche tags (fewer likes) if they are perfect for the content.\n\nCaption:\n{{ $json.caption }}\n\nCandidate List:\n{{ JSON.stringify($json.candidates) }}\n\nOutput Format (JSON Only):\n[\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\"]",
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.4
    },
    {
      "id": "12d15702-4af6-42f5-9262-e14c50dcf0c6",
      "name": "Format Output",
      "type": "n8n-nodes-base.set",
      "position": [
        4384,
        2704
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "hashtags-assign",
              "name": "hashtags",
              "type": "string",
              "value": "={{ JSON.parse($json.text.replace(/```json/g,'').replace(/```/g,'')).map(t => '#' + t.replace('#','')).join(' ') }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "73f9ce86-0afc-4c95-a987-708952547f55",
      "name": "Workflow Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        1664,
        2576
      ],
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "caption"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "df67bfb9-558a-41a2-8120-9cae690cb1e3",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        912,
        2368
      ],
      "parameters": {
        "width": 643,
        "height": 734,
        "content": "## \ud83d\ude80 Instagram Hashtag Generator\nThis workflow automatically generates 5 optimized hashtags for your Instagram post by combining AI suggestions with real-time performance data (average likes/comments) fetched from the Instagram Graph API. It also caches results in Google Sheets to save API calls.\n\n### \ud83d\udee0\ufe0f Setup Steps\n1. **Credentials**: Connect your `OpenAI`, `Google Sheets`, and `Facebook Graph API` credentials in the respective nodes.\n2. **Google Sheets**: Create a sheet with columns: `tag` (string), `average_likes` (number), `average_comments` (number). \n   - Update the **Fetch Cached Hashtags** and **Save to Cache** nodes with your Spreadsheet ID.\n3. **Instagram**: Update the **Get Hashtag Info** and **Get Hashtag Metrics** nodes with your Instagram Business Account ID.\n\n### \ud83d\udd04 Usage Modes\n**1. Manual Mode**\n- Execute the workflow manually using the `Manual Trigger`.\n- Update the `Set Dummy Caption` node with your post caption.\n\n**2. Sub-workflow Mode**\n- Connect this workflow to another workflow using the `Execute Workflow` node.\n- Pass the JSON input: `{ \"caption\": \"Your post content here...\" }`.\n\n### \u2699\ufe0f How it works\n1. **Generate**: AI proposes 10 relevant hashtags.\n2. **Metrics**: Checks Google Sheet cache. If missing, fetches Avg Likes/Comments from Instagram API.\n3. **Select**: AI picks the top 5 tags balancing relevance and engagement."
      },
      "typeVersion": 1
    },
    {
      "id": "7c59ed3a-9f9e-4f26-b59f-d97b573c41d7",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        2368
      ],
      "parameters": {
        "color": 7,
        "width": 490,
        "height": 736,
        "content": "## 1. Input Processing\nAccepts caption from either Manual Trigger or another Workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "a239cd2d-02fa-463f-aff2-152e9f4ca955",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2096,
        2368
      ],
      "parameters": {
        "color": 7,
        "width": 526,
        "height": 736,
        "content": "## 2. Idea Generation\nAI suggests 10 initial candidates based on the caption."
      },
      "typeVersion": 1
    },
    {
      "id": "3e338bed-c67f-47d9-b08e-0574a5e36c02",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2656,
        2368
      ],
      "parameters": {
        "color": 7,
        "width": 654,
        "height": 732,
        "content": "## 3. Caching Logic\nChecks Google Sheets to avoid repeated API calls."
      },
      "typeVersion": 1
    },
    {
      "id": "ce9c3af1-2d4e-4b49-acc3-c1f396a01d49",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3376,
        1984
      ],
      "parameters": {
        "color": 7,
        "width": 1920,
        "height": 430,
        "content": "## 4. Instagram Data & Caching\nFetches fresh data for new tags and saves to Sheet."
      },
      "typeVersion": 1
    },
    {
      "id": "715b97b5-a3f9-4ef1-abb1-502418716ed8",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3376,
        2464
      ],
      "parameters": {
        "color": 7,
        "width": 1304,
        "height": 610,
        "content": "## 5. Final Selection\nAggregates data and AI selects the best 5 tags."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "cbf49ca1-0e84-41f5-be07-1b1ea30e5e3e",
  "connections": {
    "Merge Input": {
      "main": [
        [
          {
            "node": "Check Cache Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save to Cache": {
      "main": [
        [
          {
            "node": "Rate Limit Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Set Dummy Caption",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rate Limit Wait": {
      "main": [
        [
          {
            "node": "Split In Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Hashtag Info": {
      "main": [
        [
          {
            "node": "Check if Tag Exists",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Rate Limit Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split In Batches": {
      "main": [
        [
          {
            "node": "Merge Cache & Fresh",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get Hashtag Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Trigger": {
      "main": [
        [
          {
            "node": "Generate Initial Hashtags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Model Selector": {
      "ai_languageModel": [
        [
          {
            "node": "Select Top 5 Hashtags",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Initial Hashtags",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Set Dummy Caption": {
      "main": [
        [
          {
            "node": "Generate Initial Hashtags",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Cached Hashtags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Cache Status": {
      "main": [
        [
          {
            "node": "Route Cached vs New",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse & Clean Tags": {
      "main": [
        [
          {
            "node": "Merge Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if Tag Exists": {
      "main": [
        [
          {
            "node": "Get Hashtag Metrics",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Rate Limit Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Hashtag Metrics": {
      "main": [
        [
          {
            "node": "Calculate Average Metrics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Cache & Fresh": {
      "main": [
        [
          {
            "node": "Aggregate & Rank Candidates",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route Cached vs New": {
      "main": [
        [
          {
            "node": "Merge Cache & Fresh",
            "type": "main",
            "index": 1
          }
        ],
        [
          {
            "node": "Split In Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Cached Hashtags": {
      "main": [
        [
          {
            "node": "Merge Input",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Select Top 5 Hashtags": {
      "main": [
        [
          {
            "node": "Format Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format New Hashtag Data": {
      "main": [
        [
          {
            "node": "Save to Cache",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Average Metrics": {
      "main": [
        [
          {
            "node": "Format New Hashtag Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Initial Hashtags": {
      "main": [
        [
          {
            "node": "Parse & Clean Tags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate & Rank Candidates": {
      "main": [
        [
          {
            "node": "Select Top 5 Hashtags",
            "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

This workflow automatically generates optimal hashtags for your Instagram posts by analyzing captions and fetching real-time engagement data.

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

More Social Media workflows → · Browse all categories →

Related workflows

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

Social Media

This workflow is ideal for individuals, marketers, agencies, and brands who want to effortlessly automate the entire blogging and social media process—from idea generation to promotion. Its primary go

Execute Workflow Trigger, Notion, OpenAI Chat +13
Social Media

This workflow is built for creators, solopreneurs, SaaS founders, and agencies looking to automate their social media content process from idea to publication. It combines the power of OpenAI, Google

OpenAI Chat, Tool Workflow, Agent +15
Social Media

Automate your Instagram community management without sounding like a bot. This workflow monitors a specific Instagram post, uses Gemini 2.5 Flash to generate context-aware, highly personalized replies

Facebook Graph Api, Google Sheets, Google Gemini
Social Media

Automatically analyze your Instagram posts’ engagement and audience sentiment using GPT-4 to uncover top-performing content and improvement opportunities. 💬📈 This workflow fetches your latest Instagra

Facebook Graph Api, Agent, Memory Buffer Window +5
Social Media

AI Social Media Promoter – Automated Blog Sharing Workflow This workflow is built for bloggers, creators, and marketing teams who want to automatically promote new blog content across Instagram, Faceb

Output Parser Structured, Rss Feed Read Trigger, OpenAI Chat +6