{
  "id": "ex6EtLx0qHHlJlbD",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Blog With Image",
  "tags": [],
  "nodes": [
    {
      "id": "b32cc401-8586-4d52-add3-aa563f3997da",
      "name": "Daily Trigger 8AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -80,
        -16
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 8
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "30348d27-0cf9-49ed-afd4-ad23bf939693",
      "name": "Fetch Google Trends",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        128,
        -16
      ],
      "parameters": {
        "url": "https://api.apify.com/v2/acts/data_xplorer~google-trends-fast-scraper/run-sync-get-dataset-items?token=<YOUR-TOKEN>>",
        "method": "POST",
        "options": {},
        "jsonBody": "{\n    \"enableTrendingSearches\": true,\n    \"fetchRegionalData\": false,\n    \"proxyConfiguration\": {\n        \"useApifyProxy\": true\n    },\n    \"trendingSearchesCountry\": \"IN\",\n    \"trendingSearchesTimeframe\": \"24\"\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.3
    },
    {
      "id": "858f2dbe-4cc1-414d-ac4c-49215c0896aa",
      "name": "Generate SEO Blog Content",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        368,
        -16
      ],
      "parameters": {
        "text": "=Trending topics\n\n{{ $json.trending_searches[0].term }}\n  - {{ $json.trending_searches[0].trend_volume }}\n  - {{ $json.trending_searches[0].related_terms }}",
        "options": {
          "systemMessage": "=You are an expert SEO content writer who writes high-performing blog articles for Google Search and social media. \nYour job is to generate a fully SEO-optimized blog post based on the user\u2019s topic or keywords.\n\nRequirements:\n1. Create an engaging, keyword-rich **blog title** (under 70 characters).\n2. Generate **long-form blog content** (600\u20131200 words) that is:\n   - Fully SEO optimized with natural keyword placement.\n   - Structured with **headings (H2, H3)**, short paragraphs, and lists where helpful.\n   - Written in a human, engaging, and informative tone.\n3. Include a **meta description (under 160 characters)** optimized for CTR.\n4. Avoid repetition, AI-like phrases, or keyword stuffing.\n5. Add **relevant subheadings** and **call-to-action** at the end.\n6. Use current SEO best practices and trending search intent.\n\n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "37ee318d-d507-426d-90b5-8b056a306f6f",
      "name": "Refine Content with Gemini AI",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        368,
        144
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b5fde2a5-0077-41b6-8ca5-8a3347cce73c",
      "name": "Parse Blog Output",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        528,
        144
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"title\": \"SEO blog title here\",\n  \"meta_description\": \"Short SEO description here\",\n  \"content\": \"Full SEO optimized blog article here\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "c587ccea-4079-4cec-a167-45135257cdaf",
      "name": "Format output for Google Docs",
      "type": "n8n-nodes-base.code",
      "position": [
        736,
        -16
      ],
      "parameters": {
        "jsCode": "const input = $input.first().json;\nconst output = input.output || {};\nconst markdown = (output.content || '').trim();\nconst title = output.title || '';\nconst resultUrls = input.resultUrls || [];\n\nconst requests = [];\nlet cursor = 1;\n\n// Step 1: Insert image\nif (Array.isArray(resultUrls) && resultUrls.length > 0) {\n  const imageUrl = resultUrls[0];\n  requests.push({\n    insertInlineImage: {\n      location: { index: cursor },\n      uri: imageUrl,\n      objectSize: { height: { magnitude: 200, unit: 'PT' } }\n    }\n  });\n  cursor += 1; // move past image\n  requests.push({\n    insertText: {\n      location: { index: cursor },\n      text: '\\n\\n'\n    }\n  });\n  cursor += 2;\n}\n\n// Step 2: Insert Title\nif (title) {\n  const titleText = title + '\\n\\n';\n  requests.push({\n    insertText: { location: { index: cursor }, text: titleText }\n  });\n  requests.push({\n    updateParagraphStyle: {\n      range: { startIndex: cursor, endIndex: cursor + title.length },\n      paragraphStyle: { namedStyleType: 'HEADING_1' },\n      fields: 'namedStyleType'\n    }\n  });\n  cursor += titleText.length;\n}\n\n// Step 3: Remove duplicate markdown title\nconst markdownContent = markdown.replace(/^#.*\\n/, '').trim();\n\n// Step 4: Insert all markdown safely\nconst lines = markdownContent.split('\\n');\nfor (const line of lines) {\n  const trimmed = line.trim();\n  if (!trimmed) {\n    requests.push({\n      insertText: { location: { index: cursor }, text: '\\n' }\n    });\n    cursor += 1;\n    continue;\n  }\n\n  // Headings\n  const headingMatch = trimmed.match(/^(#{1,3})\\s*(.*)/);\n  if (headingMatch) {\n    const hashes = headingMatch[1].length;\n    const headingText = headingMatch[2].trim() + '\\n\\n';\n    let styleType = 'NORMAL_TEXT';\n    if (hashes === 1) styleType = 'HEADING_2';\n    if (hashes === 2) styleType = 'HEADING_3';\n    if (hashes === 3) styleType = 'HEADING_4';\n\n    requests.push({ insertText: { location: { index: cursor }, text: headingText } });\n    requests.push({\n      updateParagraphStyle: {\n        range: { startIndex: cursor, endIndex: cursor + headingText.length - 2 },\n        paragraphStyle: { namedStyleType: styleType },\n        fields: 'namedStyleType'\n      }\n    });\n    cursor += headingText.length;\n    continue;\n  }\n\n  // Normal paragraph (remove bold markers)\n  const paragraph = trimmed.replace(/[*_]{2}/g, '') + '\\n\\n';\n  requests.push({ insertText: { location: { index: cursor }, text: paragraph } });\n  cursor += paragraph.length;\n}\n\n// Step 5: Return requests\nreturn [{ json: { requests } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "8e804594-07bc-4e4d-908e-6412367548b0",
      "name": "Update Google Doc",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        976,
        -16
      ],
      "parameters": {
        "url": "=https://docs.googleapis.com/v1/documents/1xxCxjQ73GCtsJyn2u86dZsEId18Uha82OxvaIOjhZf0:batchUpdate",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "authentication": "predefinedCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "requests",
              "value": "={{ $json.requests }}"
            }
          ]
        },
        "nodeCredentialType": "googleDocsOAuth2Api"
      },
      "credentials": {
        "googleDocsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "8ea9d0c0-e219-40a5-a5f3-28cf7b70e94d",
      "name": "Generate Blog Image",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        832,
        400
      ],
      "parameters": {
        "url": "https://api.kie.ai/api/v1/jobs/createTask",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"model\": \"google/nano-banana\",\n  \"input\": {\n    \"prompt\": \"{{ $json.output.title }}\",\n    \"output_format\": \"png\",\n    \"image_size\": \"16:9\"\n  }\n} ",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer <YOUR-API-TOKEN>"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "a73a2817-5d92-4b70-a1de-6894b879a983",
      "name": "Check Image Generation Status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1072,
        400
      ],
      "parameters": {
        "url": "https://api.kie.ai/api/v1/jobs/recordInfo",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "taskId",
              "value": "={{ $json.data.taskId }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer <YOUR-API-TOKEN>"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "bda4084e-c7a6-4bad-9da6-ce3f11548e5d",
      "name": "Is Image Ready?",
      "type": "n8n-nodes-base.if",
      "position": [
        1312,
        400
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "0c96f9ae-4956-4698-86b1-76b1b067c2e1",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              },
              "leftValue": "={{ $json.data.resultJson }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "191b9b4d-a124-41c0-84fb-4855cc9d10fc",
      "name": "Prepare Image URL for Insert",
      "type": "n8n-nodes-base.set",
      "position": [
        1552,
        608
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={{ $json.data.resultJson }}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "08dc0f9e-abee-422f-8d22-3b78a39dd751",
      "name": "Download Image",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1760,
        608
      ],
      "parameters": {
        "url": "={{ $json.resultUrls[0] }}",
        "options": {}
      },
      "typeVersion": 4.3
    },
    {
      "id": "8eb3c2fd-7cef-4b39-a91c-f21430da15b0",
      "name": "Wait 5 Second Before Recheck",
      "type": "n8n-nodes-base.wait",
      "position": [
        1536,
        384
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "6ea6df37-6bb3-4978-865c-a68f3180b5bb",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        64,
        -192
      ],
      "parameters": {
        "width": 224,
        "height": 352,
        "content": "## \ud83d\ude80 Fetch Google Trends\n\nFetches India\u2019s top trending searches in the last 24h via Apify API"
      },
      "typeVersion": 1
    },
    {
      "id": "6c4c9e3b-00cc-4380-a0eb-5ad355c57e49",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        320,
        -224
      ],
      "parameters": {
        "color": 3,
        "width": 320,
        "height": 528,
        "content": "## \ud83d\udcdd Generate SEO Blog Content\n\nGenerates a fully SEO-optimized, human-like blog post from trending topics; includes title, meta description, and structured content."
      },
      "typeVersion": 1
    },
    {
      "id": "1e070641-8454-4cce-8bea-0d1769798939",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        672,
        -256
      ],
      "parameters": {
        "width": 224,
        "height": 400,
        "content": "## \ud83d\udcc4 Format Output for Google Docs\n\nConverts AI-generated blog content and images into Google Docs requests with proper headings and formatting."
      },
      "typeVersion": 1
    },
    {
      "id": "af6debd0-aa3f-40bb-9f2d-464f8ddd4400",
      "name": "Sticky Note - Update Google Doc",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        -224
      ],
      "parameters": {
        "color": 4,
        "width": 188,
        "height": 364,
        "content": "## \ud83d\udcdd Update Google Doc\n\nSends formatted blog content and images to Google Docs using batchUpdate API."
      },
      "typeVersion": 1
    },
    {
      "id": "d6c1df3a-ae0a-4db5-8adc-c0c18874ea98",
      "name": "Sticky Note - Generate Blog Image",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        784,
        176
      ],
      "parameters": {
        "color": 2,
        "width": 182,
        "height": 380,
        "content": "## \ud83d\uddbc\ufe0f Generate Blog Image\n\nCreates a blog post image using KIE AI based on the blog title in 16:9 PNG format."
      },
      "typeVersion": 1
    },
    {
      "id": "2393576a-24e6-4c36-a267-671f8aae18af",
      "name": "Sticky Note - Check Image Status",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1008,
        176
      ],
      "parameters": {
        "color": 4,
        "width": 220,
        "height": 396,
        "content": "## \u23f3 Check Image Generation Status\n\nPolls KIE AI to see if the blog image task is complete before downloading."
      },
      "typeVersion": 1
    },
    {
      "id": "67a52914-8394-4261-802f-bc1a564fbae1",
      "name": "Sticky Note - Is Image Ready?",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        192
      ],
      "parameters": {
        "color": 5,
        "width": 188,
        "height": 348,
        "content": "## \u2705 Is Image Ready?\n\nChecks if the generated blog image is complete; routes workflow based on readiness."
      },
      "typeVersion": 1
    },
    {
      "id": "e66abb7d-1659-41ac-a8f0-49b86b7576fa",
      "name": "Sticky Note - Wait 5 Seconds",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1488,
        176
      ],
      "parameters": {
        "color": 6,
        "width": 204,
        "height": 364,
        "content": "## \u23f1\ufe0f Wait 5 Seconds Before Recheck\n\nPauses workflow briefly before checking the blog image status again."
      },
      "typeVersion": 1
    },
    {
      "id": "e35d114c-98f8-4967-a2f1-ef62901d521e",
      "name": "Sticky Note - Prepare Image URL",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1232,
        592
      ],
      "parameters": {
        "color": 3,
        "width": 300,
        "height": 172,
        "content": "## \ud83d\udd17 Prepare Image URL for Insert\n\nExtracts the generated blog image URL to use in the Google Docs insertion step."
      },
      "typeVersion": 1
    },
    {
      "id": "1547eb6c-4b1d-4a99-a05d-7bd513f82d72",
      "name": "Sticky Note - Download Image",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1904,
        592
      ],
      "parameters": {
        "color": 4,
        "width": 300,
        "height": 140,
        "content": "## \u2b07\ufe0f Download Image\n\nDownloads the generated blog image from the URL for insertion into Google Docs."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "db809ba2-f0e9-4946-be50-9a55429a133e",
  "connections": {
    "Download Image": {
      "main": [
        [
          {
            "node": "Format output for Google Docs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Image Ready?": {
      "main": [
        [
          {
            "node": "Wait 5 Second Before Recheck",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare Image URL for Insert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily Trigger 8AM": {
      "main": [
        [
          {
            "node": "Fetch Google Trends",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Blog Output": {
      "ai_outputParser": [
        [
          {
            "node": "Generate SEO Blog Content",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Google Trends": {
      "main": [
        [
          {
            "node": "Generate SEO Blog Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Blog Image": {
      "main": [
        [
          {
            "node": "Check Image Generation Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate SEO Blog Content": {
      "main": [
        [
          {
            "node": "Format output for Google Docs",
            "type": "main",
            "index": 0
          },
          {
            "node": "Generate Blog Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Image URL for Insert": {
      "main": [
        [
          {
            "node": "Download Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 5 Second Before Recheck": {
      "main": [
        [
          {
            "node": "Check Image Generation Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Image Generation Status": {
      "main": [
        [
          {
            "node": "Is Image Ready?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format output for Google Docs": {
      "main": [
        [
          {
            "node": "Update Google Doc",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Refine Content with Gemini AI": {
      "ai_languageModel": [
        [
          {
            "node": "Generate SEO Blog Content",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  }
}