AutomationFlowsAI & RAG › Publish Weekly Google Business Profile Posts Using Perplexity and Supabase

Publish Weekly Google Business Profile Posts Using Perplexity and Supabase

ByPedro Olavarria @polavarria on n8n.io

This workflow runs every Monday at 9AM ET to research recent automation topics with Perplexity, generate a Google Business Profile post with Anthropic Claude, publish it to Google Business Profile, log the published post to Supabase, and send a confirmation email via Microsoft…

Cron / scheduled trigger★★★★☆ complexityAI-powered17 nodesHTTP RequestPerplexityAgentAnthropic ChatGoogle Business ProfileMicrosoft Outlook
AI & RAG Trigger: Cron / scheduled Nodes: 17 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Agent → HTTP Request 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
{
  "name": "GBP Auto Poster",
  "nodes": [
    {
      "name": "Every Monday 9AM ET",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -16,
        48
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 9
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "name": "Fetch Recent Posts",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        176,
        48
      ],
      "parameters": {
        "url": "https://YOUR-PROJECT.supabase.co/rest/v1/gbp_posts?select=post_text,category,published_at&order=published_at.desc&limit=8",
        "options": {},
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "supabaseApi"
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "name": "Build Post Prompt",
      "type": "n8n-nodes-base.code",
      "position": [
        352,
        48
      ],
      "parameters": {
        "jsCode": "const now = new Date();\nconst startOfYear = new Date(now.getFullYear(), 0, 0);\nconst dayOfYear = Math.floor((now - startOfYear) / 86400000);\nconst weekOfYear = Math.floor(dayOfYear / 7);\nconst weekOfMonth = Math.ceil(now.getDate() / 7);\n\nconst industries = [\n  'healthcare and medical clinics',\n  'professional services such as legal accounting and consulting firms',\n  'retail and ecommerce small businesses',\n  'hospitality restaurants and food service',\n  'trades and home services like HVAC plumbing electrical and roofing',\n  'nonprofits and community organizations',\n  'education and training providers'\n];\nconst industry = industries[weekOfYear % industries.length];\n\nconst categories = ['automation_tip', 'service_spotlight', 'industry_insight', 'call_to_action'];\nconst category = categories[(weekOfMonth - 1) % 4];\n\nconst researchQueries = {\n  automation_tip: `Find 2 to 3 recent practical automation use cases or productivity wins from the last 30 days for ${industry}. Focus on time saved, processes improved, real world examples. Be specific. Cite sources.`,\n  service_spotlight: `Find 2 to 3 recent examples from the last 30 days of small ${industry} using AI workflow automation, document automation, compliance automation, or cybersecurity to improve operations. Cite sources.`,\n  industry_insight: `Find the latest trends, news, or developments from the last 14 days in AI and automation affecting ${industry}. Focus on practical implications for small business owners. Cite sources.`,\n  call_to_action: `Find 2 to 3 recent statistics or data points from the last 60 days showing the benefits of business automation for small businesses, particularly ${industry}. Focus on time savings, cost reductions, error reductions. Cite sources.`\n};\n\nreturn [{ json: {\n  category,\n  industry,\n  weekOfMonth,\n  weekOfYear,\n  research_query: researchQueries[category],\n  generatedAt: now.toISOString()\n}}];"
      },
      "typeVersion": 2
    },
    {
      "name": "Research Trending Topics",
      "type": "n8n-nodes-base.perplexity",
      "position": [
        640,
        48
      ],
      "parameters": {
        "model": "sonar-pro",
        "options": {},
        "messages": {
          "message": [
            {
              "content": "={{ $json.research_query }}"
            }
          ]
        },
        "requestOptions": {}
      },
      "credentials": {
        "perplexityApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "name": "Merge Prompt + History",
      "type": "n8n-nodes-base.code",
      "position": [
        1008,
        48
      ],
      "parameters": {
        "jsCode": "const ctx = $('Build Post Prompt').item.json;\nconst researchRaw = $('Research Trending Topics').first().json;\nconst research = (researchRaw.message && researchRaw.message.content)\n  || researchRaw.content\n  || (researchRaw.choices && researchRaw.choices[0] && researchRaw.choices[0].message && researchRaw.choices[0].message.content)\n  || (typeof researchRaw === 'string' ? researchRaw : JSON.stringify(researchRaw).substring(0, 2000));\n\nconst recentRaw = $('Fetch Recent Posts').all();\nconst recentSummary = recentRaw.length > 0\n  ? recentRaw.map((item, i) => {\n      const p = item.json;\n      const date = new Date(p.published_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });\n      const preview = (p.post_text || '').substring(0, 120).replace(/\\n/g, ' ');\n      return `[${i + 1}] Category: ${p.category} | Date: ${date} | Preview: \"${preview}...\"`;\n    }).join('\\n')\n  : 'No previous posts found.';\n\nconst ctaUrl = (ctx.category === 'service_spotlight' || ctx.category === 'call_to_action')\n  ? 'yourcompany.com/request-assessment'\n  : 'yourcompany.com';\n\nconst prompt = `Write a Google Business Profile post for Your Company Inc., an AI and automation consultancy serving small businesses across multiple industries.\n\nINDUSTRY FOCUS THIS WEEK: ${ctx.industry}\nCATEGORY: ${ctx.category}\n\nRESEARCH FINDINGS (use these for credibility, paraphrase, do not copy verbatim, do not include URLs or citation markers in the post):\n${research}\n\nVOICE AND TONE:\n- Educational and curious, never alarmist\n- Confident but humble, acknowledge nuance, trade offs, and limits\n- Plain English, accessible to a non technical owner\n- Never use the words leverage or streamline\n- Never use em dashes\n- No fear based phrases like losing revenue, walking out the door, before it is too late\n- Avoid framing customers, patients, or clients as transactions or sources of money\n\nSTRUCTURE (200 to 280 words):\n1. HOOK (1 to 2 sentences): A genuine insight, statistic, or trend from the research\n2. CONTEXT (2 to 3 sentences): What is actually happening in ${ctx.industry}, what is possible now\n3. NUANCE (1 to 2 sentences): Trade offs, guardrails, what NOT to automate, where humans still matter\n4. YourCo ANGLE (1 to 2 sentences): How we approach this with audit trails, human in the loop, industry fit SOPs, sensible guardrails\n5. SOFT CTA (1 sentence): Inviting close. Examples: Curious how this could work in your business, or Want to think it through together\n\nCATEGORY SPECIFIC FOCUS:\n- automation_tip: Practical use case showing how automation saves time or removes friction\n- service_spotlight: Highlight one YourCo service area such as IT managed services, cybersecurity, compliance automation, or AI workflows with a real example\n- industry_insight: A trend or development affecting ${ctx.industry}, broadly applicable\n- call_to_action: Invite small business owners to assess their operations as discovery, not pressure\n\nYour Company CONTEXT:\n- Tagline: Automate. Relentlessly. Ruthlessly.\n- Serves small businesses across ALL industries\n- Emphasizes guardrails, human in the loop, audit trails, SOPs, security, compliance\n- Builds systems that fit how a business actually operates, not generic templates\n- Based in Central Florida, serving small businesses nationally\n\nWHAT TO AVOID:\n- Specific made up business names or cities, only use what is in the research\n- Overclaiming AI capabilities, prefer modern automation can help with X over AI now does X\n- Treating customers, patients, or clients as revenue sources\n- Generic LinkedIn influencer phrasing\n- Hashtags, em dashes, emojis (unless very subtle)\n- URLs or citation markers in the post body\n\nCTA URL TO REFERENCE: ${ctaUrl}\nEnd with a soft invitation that includes the URL naturally.\n\nDO NOT REPEAT - Recent posts published:\n${recentSummary}\n\nPick a different angle, example, and hook from the recent posts. Same industry is acceptable if angle differs significantly.`;\n\nreturn [{ json: {\n  ...ctx,\n  prompt,\n  research_summary: research.substring(0, 500),\n  recentPostCount: recentRaw.length\n}}];"
      },
      "typeVersion": 2
    },
    {
      "name": "Generate GBP Post",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1200,
        48
      ],
      "parameters": {
        "text": "={{ $json.prompt }}",
        "options": {
          "systemMessage": "You are the content writer for Your Company Inc., an AI and automation consultancy. Write educational, confident, soft sell Google Business Profile posts that build trust and feel like advice from a thoughtful expert. Never alarmist. Never sales bro. Return ONLY the post text. No title, no label, no explanation. Just the post ready to publish."
        },
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "name": "Claude Sonnet",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        1200,
        256
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-5-20250929",
          "cachedResultName": "Claude Sonnet 4.5"
        },
        "options": {
          "temperature": 0.7,
          "maxTokensToSample": 1000
        }
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "name": "Extract Post Content",
      "type": "n8n-nodes-base.code",
      "position": [
        1680,
        48
      ],
      "parameters": {
        "jsCode": "const postText = $input.first().json.output || '';\nif (!postText) throw new Error('Claude returned empty post');\nconst ctx = $('Merge Prompt + History').item.json;\n// Google Business Profile rejects posts over 1500 chars (\"Bad request\").\n// Trim to a clean sentence boundary under 1450 so we never trip it.\nlet txt = postText.trim();\nconst MAX = 1450;\nif (txt.length > MAX) {\n  let cut = txt.slice(0, MAX);\n  const stop = Math.max(cut.lastIndexOf('. '), cut.lastIndexOf('! '), cut.lastIndexOf('? '), cut.lastIndexOf('\\n'));\n  cut = (stop > MAX * 0.6) ? cut.slice(0, stop + 1) : cut.replace(/\\s+\\S*$/, '');\n  txt = cut.trim();\n}\nreturn [{ json: {\n  post_text: txt,\n  post_chars: txt.length,\n  category: ctx.category,\n  industry: ctx.industry,\n  week_of_month: ctx.weekOfMonth,\n  week_of_year: ctx.weekOfYear,\n  generated_at: ctx.generatedAt\n}}];"
      },
      "typeVersion": 2
    },
    {
      "name": "Publish to GBP",
      "type": "n8n-nodes-base.googleBusinessProfile",
      "position": [
        1872,
        48
      ],
      "parameters": {
        "account": {
          "__rl": true,
          "mode": "list",
          "value": "accounts/YOUR_GBP_ACCOUNT_ID",
          "cachedResultName": "Your Name"
        },
        "summary": "={{ $json.post_text }}",
        "location": {
          "__rl": true,
          "mode": "list",
          "value": "locations/YOUR_GBP_LOCATION_ID",
          "cachedResultName": "locations/YOUR_GBP_LOCATION_ID"
        },
        "requestOptions": {},
        "additionalOptions": {
          "url": "https://yourcompany.com/request-assessment",
          "languageCode": "en-US",
          "callToActionType": "LEARN_MORE"
        }
      },
      "credentials": {
        "googleBusinessProfileOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "name": "Log Post to Supabase",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2064,
        48
      ],
      "parameters": {
        "url": "https://YOUR-PROJECT.supabase.co/rest/v1/gbp_posts",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"post_text\": {{ JSON.stringify($('Extract Post Content').item.json.post_text) }},\n  \"category\": {{ JSON.stringify($('Extract Post Content').item.json.category) }},\n  \"week_of_month\": {{ $('Extract Post Content').item.json.week_of_month }},\n  \"gbp_post_name\": {{ JSON.stringify($json.name || '') }},\n  \"status\": \"published\",\n  \"published_at\": {{ JSON.stringify(new Date().toISOString()) }}\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Prefer",
              "value": "return=representation"
            }
          ]
        },
        "nodeCredentialType": "supabaseApi"
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "name": "Notify Me Post Live",
      "type": "n8n-nodes-base.microsoftOutlook",
      "position": [
        2256,
        48
      ],
      "parameters": {
        "subject": "=GBP Post Live: {{ $('Extract Post Content').item.json.category.replace(/_/g, ' ').toUpperCase() }} ({{ $('Extract Post Content').item.json.industry }})",
        "bodyContent": "=<div style=\"font-family:Arial,sans-serif;max-width:680px;\"><div style=\"background:#1B4F8A;padding:24px 32px;border-radius:8px 8px 0 0;\"><h1 style=\"color:#fff;margin:0;font-size:20px;\">GBP Post Published</h1></div><div style=\"padding:32px;border:1px solid #e0e0e0;border-top:none;border-radius:0 0 8px 8px;\"><p><strong>Category:</strong> {{ $('Extract Post Content').item.json.category.replace(/_/g, ' ') }}</p><p><strong>Industry Focus:</strong> {{ $('Extract Post Content').item.json.industry }}</p><p><strong>Published:</strong> {{ new Date().toLocaleDateString('en-US',{year:'numeric',month:'long',day:'numeric'}) }}</p><hr style=\"border:none;border-top:1px solid #eee;margin:20px 0;\"><p><strong>Post Content:</strong></p><div style=\"background:#f7f9fc;padding:16px;border-radius:4px;font-size:14px;line-height:1.6;\">{{ $('Extract Post Content').item.json.post_text }}</div><hr style=\"border:none;border-top:1px solid #eee;margin:20px 0;\"><p style=\"color:#999;font-size:12px;\">Your Company | Automate. Relentlessly. Ruthlessly.</p></div></div>",
        "toRecipients": "you@example.com",
        "additionalFields": {
          "bodyContentType": "html"
        }
      },
      "credentials": {
        "microsoftOutlookOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "name": "Log Cost: Research Trending Topics",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        640,
        256
      ],
      "parameters": {
        "mode": "each",
        "options": {
          "waitForSubWorkflow": false
        },
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR-COST-LOG-SUBWORKFLOW-ID"
        },
        "workflowInputs": {
          "value": {
            "model": "={{ $('Research Trending Topics').item.json.model || 'sonar-pro' }}",
            "provider": "perplexity",
            "node_name": "Research Trending Topics",
            "request_id": "={{ $('Research Trending Topics').item.json.id || '' }}",
            "agent_label": "",
            "input_tokens": "={{ $('Research Trending Topics').item.json.usage?.prompt_tokens || 0 }}",
            "output_tokens": "={{ $('Research Trending Topics').item.json.usage?.completion_tokens || 0 }}",
            "workflow_name": "={{ $workflow.name }}"
          },
          "mappingMode": "defineBelow"
        }
      },
      "typeVersion": 1.3
    },
    {
      "name": "Sticky: Overview & Setup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        224,
        -624
      ],
      "parameters": {
        "color": 7,
        "width": 2004,
        "height": 332,
        "content": "## Weekly Google Business Profile auto-poster\n\nEvery Monday this researches a fresh, on-brand topic, writes a Google Business Profile post with AI (capped to GBP's 1500-character limit), publishes it, logs it, and emails you a copy. The industry focus and the post category rotate weekly so posts never repeat.\n\n### Setup (replace these before running)\n- Add credentials: **Supabase**, **Perplexity**, **Anthropic (Claude)**, **Google Business Profile**, **Microsoft Outlook**\n- `YOUR-PROJECT.supabase.co` -> your Supabase URL, with a `gbp_posts` table (post_text, category, week_of_month, gbp_post_name, status, published_at)\n- `YOUR_GBP_ACCOUNT_ID` and `YOUR_GBP_LOCATION_ID` -> your GBP account and location\n- `you@example.com` -> your notification email\n- Optional: the **Log Cost** node calls your own token-logging sub-workflow. Delete it if you do not track cost."
      },
      "typeVersion": 1
    },
    {
      "name": "Sticky: 1 Topic",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        -176
      ],
      "parameters": {
        "color": 4,
        "width": 592,
        "height": 548,
        "content": "## 1. Pick this week's topic\n\nThe **schedule** fires weekly. **Fetch Recent Posts** pulls your last 8 posts so the AI will not repeat them. **Build Post Prompt** rotates the industry and post category and builds a targeted research query."
      },
      "typeVersion": 1
    },
    {
      "name": "Sticky: 2 Research",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        544,
        -256
      ],
      "parameters": {
        "color": 4,
        "width": 312,
        "height": 708,
        "content": "## 2. Research the topic\n\n**Perplexity (sonar-pro)** finds recent, real examples and stats for the chosen industry and category, with citations, to ground the post in facts.\n\nThe **Log Cost** branch below is optional usage logging."
      },
      "typeVersion": 1
    },
    {
      "name": "Sticky: 3 Write",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        -176
      ],
      "parameters": {
        "color": 4,
        "width": 680,
        "height": 564,
        "content": "## 3. Write the post with AI\n\n**Merge Prompt + History** assembles the full writing brief: voice, structure, things to avoid, and the recent posts to dodge. **Generate GBP Post** writes it using the **Claude Sonnet** model."
      },
      "typeVersion": 1
    },
    {
      "name": "Sticky: 4 Publish",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        -176
      ],
      "parameters": {
        "color": 4,
        "width": 956,
        "height": 572,
        "content": "## 4. Publish, log and notify\n\n**Extract Post Content** trims the post to a clean sentence boundary under 1450 characters so GBP never rejects it. **Publish to GBP** posts it with a Learn More button. **Log Post to Supabase** records it (this is what step 1 reads to avoid repeats). **Notify Me Post Live** emails you the published post."
      },
      "typeVersion": 1
    }
  ],
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Claude Sonnet": {
      "ai_languageModel": [
        [
          {
            "node": "Generate GBP Post",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Publish to GBP": {
      "main": [
        [
          {
            "node": "Log Post to Supabase",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Post Prompt": {
      "main": [
        [
          {
            "node": "Research Trending Topics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate GBP Post": {
      "main": [
        [
          {
            "node": "Extract Post Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Recent Posts": {
      "main": [
        [
          {
            "node": "Build Post Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every Monday 9AM ET": {
      "main": [
        [
          {
            "node": "Fetch Recent Posts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Post Content": {
      "main": [
        [
          {
            "node": "Publish to GBP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Post to Supabase": {
      "main": [
        [
          {
            "node": "Notify Me Post Live",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Prompt + History": {
      "main": [
        [
          {
            "node": "Generate GBP Post",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Research Trending Topics": {
      "main": [
        [
          {
            "node": "Log Cost: Research Trending Topics",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Prompt + History",
            "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 runs every Monday at 9AM ET to research recent automation topics with Perplexity, generate a Google Business Profile post with Anthropic Claude, publish it to Google Business Profile, log the published post to Supabase, and send a confirmation email via Microsoft…

Source: https://n8n.io/workflows/16318/ — 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

Complete PostgreSQL-backed system: Keyword scoring → AI research → Multi-part content generation → fal.ai Nano Banana image generation → WordPress publishing

WordPress, OpenAI, Perplexity +8
AI & RAG

This workflow is for beauty salons who want consistent, high‑quality social media content without writing every post manually. It also suits agencies and automation builders who manage multiple beauty

Telegram, Google Sheets Trigger, Agent +26
AI & RAG

Automate Microsoft Teams Meeting Analysis with GPT-4.1, Outlook & Mem.ai Watch the YouTube video to get started Follow along with the blog post

Postgres, OpenAI Chat, HTTP Request +3
AI & RAG

Created by: Peyton Leveillee Last updated: October 2025

OpenAI Chat, Google Sheets, HTTP Request +5
AI & RAG

System Architecture Two integrated N8N workflows providing automated US stock portfolio management through Telegram:

Output Parser Autofixing, OpenAI Chat, Perplexity +10