보고서 자동화
고급
이것은자동화 워크플로우로, 16개의 노드를 포함합니다.주로 Code, Slack, GoogleDocs, ScheduleTrigger, OpenAi 등의 노드를 사용하며. GPT-4o와 Google Docs를 사용하여 주간 마케팅 성과 보고서 생성并보내기로 Slack
사전 요구사항
- •Slack Bot Token 또는 Webhook URL
- •OpenAI API Key
카테고리
-
워크플로우 미리보기
노드 연결 관계를 시각적으로 표시하며, 확대/축소 및 이동을 지원합니다
워크플로우 내보내기
다음 JSON 구성을 복사하여 n8n에 가져오면 이 워크플로우를 사용할 수 있습니다
{
"id": "E32wcwtKunq0Tibz",
"meta": {
"instanceId": "6615d3df9d365bf328b0a329fe952ab6b434c9ecc8f5a2517849ec1f68f0d9b0",
"templateCredsSetupCompleted": true
},
"name": "Reporting Automation",
"tags": [
{
"id": "OYNCvrDxVQHw2gvR",
"name": "Upwork",
"createdAt": "2025-10-02T10:34:02.340Z",
"updatedAt": "2025-10-02T10:34:02.340Z"
},
{
"id": "ZcM21JDfzTQclYLn",
"name": "Templated on N8N",
"createdAt": "2025-10-14T17:00:09.847Z",
"updatedAt": "2025-10-14T17:00:09.847Z"
}
],
"nodes": [
{
"id": "d5ec0af7-cb90-4cd6-91dc-69857fe7bca9",
"name": "스케줄 트리거",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
144,
256
],
"parameters": {
"rule": {
"interval": [
{
"daysInterval": 7,
"triggerAtHour": 7
}
]
}
},
"typeVersion": 1.2
},
{
"id": "7381727c-9a29-4da8-aaf3-cff59a138738",
"name": "스티키 노트",
"type": "n8n-nodes-base.stickyNote",
"position": [
-416,
-80
],
"parameters": {
"color": 6,
"width": 496,
"height": 384,
"content": "## 📊 What the Automation Does\n- Runs automatically on a schedule (e.g. every Monday). \n- Pulls campaign performance data (here: demo data for Google Ads, Meta, TikTok, YouTube). \n- Uses AI (LLM) to write a clear executive summary with wins, issues, and recommendations. \n- Builds a structured report in Markdown (totals, channel performance, top campaigns). \n- Creates a Google Doc with the full report. \n- Notifies the team in Slack with topline numbers + report link. \n- Emails the report directly to stakeholders or clients."
},
"typeVersion": 1
},
{
"id": "f9fc4b70-f2dd-44f8-8ba1-245bf9f6a116",
"name": "Google Ads Demo",
"type": "n8n-nodes-base.code",
"position": [
368,
256
],
"parameters": {
"jsCode": "// Reproducible dummy metrics for last 7 days, by channel & campaign.\n// No external API needed. Good for demos.\n\n// --- helpers ---\nfunction seededRandom(seed) {\n // simple LCG\n let s = seed % 2147483647;\n if (s <= 0) s += 2147483646;\n return () => (s = s * 16807 % 2147483647) / 2147483647;\n}\nconst seed = 20250601; // fix for reproducible demo\nconst rand = seededRandom(seed);\n\nfunction round(n, d=0) {\n const p = Math.pow(10,d);\n return Math.round(n*p)/p;\n}\n\nfunction dateISO(d) {\n return d.toISOString().slice(0,10);\n}\n\n// --- period (last 7 days) ---\nconst end = new Date(); // today\nconst start = new Date(end);\nstart.setDate(end.getDate() - 6); // inclusive 7 days\n\n// --- channels & base volumes ---\nconst channels = [\n { key: 'google_ads', name: 'Google Ads', baseImp: 140000, baseCpc: 0.6, baseConvRate: 0.018 },\n { key: 'meta_ads', name: 'Meta Ads', baseImp: 120000, baseCpc: 0.45, baseConvRate: 0.015 },\n { key: 'tiktok_ads', name: 'TikTok Ads', baseImp: 90000, baseCpc: 0.35, baseConvRate: 0.012 },\n { key: 'youtube_ads', name: 'YouTube Ads', baseImp: 110000, baseCpc: 0.40, baseConvRate: 0.010 },\n];\n\nconst campaignsByChannel = {\n google_ads: ['Brand Search', 'Competitor Search', 'Non-Brand Generic'],\n meta_ads: ['Prospecting Video', 'Retargeting Carousel', 'Broad Static'],\n tiktok_ads: ['Spark Ads UGC', 'Creator Whitelist', 'TopView Test'],\n youtube_ads: ['In-Stream Skippable', 'In-Feed Shorts', 'Remarketing']\n};\n\n// --- generate data ---\nlet totals = { impressions: 0, clicks: 0, conversions: 0, spend: 0, revenue: 0 };\nconst byChannel = [];\n\nfor (const ch of channels) {\n const chImpressions = Math.floor(ch.baseImp * (0.9 + rand()*0.3)); // ±15%\n const chClicks = Math.floor(chImpressions * (0.01 + rand()*0.02)); // 1%–3%\n const chCpc = round(ch.baseCpc * (0.85 + rand()*0.3), 2);\n const chSpend = round(chClicks * chCpc, 2);\n const chConvRate = ch.baseConvRate * (0.8 + rand()*0.4); // ±20%\n const chConversions = Math.floor(chClicks * chConvRate);\n const aov = 38 + rand()*22; // average order value 38–60\n const chRevenue = round(chConversions * aov, 2);\n const chRoas = chSpend > 0 ? round(chRevenue / chSpend, 2) : null;\n\n // campaigns\n const campNames = campaignsByChannel[ch.key];\n const campaigns = [];\n let remImp = chImpressions, remClicks = chClicks, remConv = chConversions, remSpend = chSpend, remRev = chRevenue;\n\n for (let i=0;i<campNames.length;i++) {\n const share = i < campNames.length-1 ? (0.3 + rand()*0.5) : 1; // last gets remainder\n const imp = i < campNames.length-1 ? Math.max(0, Math.floor(remImp * share * 0.4)) : remImp;\n const clk = i < campNames.length-1 ? Math.max(0, Math.floor(remClicks * share * 0.4)) : remClicks;\n const conv= i < campNames.length-1 ? Math.max(0, Math.floor(remConv * share * 0.4)) : remConv;\n const sp = i < campNames.length-1 ? round(remSpend * share * 0.4, 2) : round(remSpend,2);\n const rev = i < campNames.length-1 ? round(remRev * share * 0.4, 2) : round(remRev,2);\n campaigns.push({\n name: campNames[i],\n impressions: imp,\n clicks: clk,\n conversions: conv,\n spend: sp,\n revenue: rev,\n roas: sp>0 ? round(rev/sp,2) : null,\n cpc: clk>0 ? round(sp/clk,2) : null,\n ctr: imp>0 ? round((clk/imp)*100,2) : null,\n convRate: clk>0 ? round((conv/clk)*100,2) : null,\n });\n remImp -= imp; remClicks -= clk; remConv -= conv; remSpend = round(remSpend - sp,2); remRev = round(remRev - rev,2);\n }\n\n totals.impressions += chImpressions;\n totals.clicks += chClicks;\n totals.conversions += chConversions;\n totals.spend = round(totals.spend + chSpend, 2);\n totals.revenue = round(totals.revenue + chRevenue, 2);\n\n byChannel.push({\n key: ch.key,\n name: ch.name,\n impressions: chImpressions,\n clicks: chClicks,\n conversions: chConversions,\n spend: chSpend,\n revenue: chRevenue,\n roas: chRoas,\n cpc: chCpc,\n ctr: chImpressions>0 ? round((chClicks/chImpressions)*100,2) : null,\n convRate: chClicks>0 ? round((chConversions/chClicks)*100,2) : null,\n campaigns\n });\n}\n\nconst period = { start: dateISO(start), end: dateISO(end) };\nconst summary = {\n impressions: totals.impressions,\n clicks: totals.clicks,\n conversions: totals.conversions,\n spend: totals.spend,\n revenue: totals.revenue,\n roas: totals.spend>0 ? round(totals.revenue/totals.spend,2) : null,\n ctr: totals.impressions>0 ? round((totals.clicks/totals.impressions)*100,2) : null,\n convRate: totals.clicks>0 ? round((totals.conversions/totals.clicks)*100,2) : null,\n};\n\nreturn {\n period,\n summary,\n byChannel\n};"
},
"typeVersion": 2
},
{
"id": "c335b635-893a-4e1d-aeeb-ecc4c4947bbd",
"name": "모델에 메시지 전송",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
592,
256
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "GPT-4O-MINI"
},
"options": {},
"messages": {
"values": [
{
"content": "=Create a short executive summary (120–180 words) for a weekly ad performance report.\nUse the provided JSON metrics. Include: key wins, issues, and 1-2 high-impact recommendations.\n\nPeriod: {{ $json.period.start }} → {{ $json.period.end }}\nTotals: {{ $json.summary }}\nChannels: {{ $json.byChannel[0] }}"
},
{
"role": "system",
"content": "You are a senior performance marketer. Write concise, actionable summaries."
}
]
}
},
"credentials": {
"openAiApi": {
"id": "WVC4WZ1lsahz1CtE",
"name": "OpenAi account"
}
},
"typeVersion": 1.8
},
{
"id": "6a4ebcda-4997-4dc8-ab60-3370c0bf373e",
"name": "JavaScript 코드 실행",
"type": "n8n-nodes-base.code",
"position": [
960,
256
],
"parameters": {
"jsCode": "/**\n * Build a weekly report in Markdown from fake metrics + LLM executive summary.\n * IMPORTANT: Set these to your exact node names in the left sidebar.\n */\nconst METRICS_NODE = \"Google Ads Demo\"; // <— dein Metrics-Code-Node\nconst SUMMARY_NODE = \"Message a model\"; // <— dein LLM-Node\n\n// ---- pull data from the referenced nodes ----\nconst metrics = $node[METRICS_NODE]?.json;\nif (!metrics) {\n throw new Error(`Metrics node \"${METRICS_NODE}\" not found or has no JSON output.`);\n}\nconst period = metrics.period || {};\nconst S = metrics.summary || {};\nconst channels = metrics.byChannel || [];\n\nconst exec = $node[SUMMARY_NODE]?.json?.message?.content\n || \"No executive summary available.\";\n\n// ---- helpers ----\nfunction fmt(n, d=0) {\n if (n === null || n === undefined) return \"-\";\n return Number(n).toLocaleString(undefined, { maximumFractionDigits: d });\n}\n\nfunction mdChannelTable(rows) {\n const header = `| Channel | Impr. | Clicks | Conv. | Spend | Revenue | ROAS | CTR | CVR |\n|---|---:|---:|---:|---:|---:|---:|---:|---:|`;\n const lines = rows.map(r =>\n `| ${r.name} | ${fmt(r.impressions)} | ${fmt(r.clicks)} | ${fmt(r.conversions)} | $${fmt(r.spend,2)} | $${fmt(r.revenue,2)} | ${fmt(r.roas,2)} | ${fmt(r.ctr,2)}% | ${fmt(r.convRate,2)}% |`\n );\n return [header, ...lines].join('\\n');\n}\n\nfunction mdTopCampaigns(rows) {\n const all = [];\n for (const ch of rows) {\n for (const c of (ch.campaigns || [])) all.push({ channel: ch.name, ...c });\n }\n all.sort((a,b) => (b.roas ?? 0) - (a.roas ?? 0));\n const top = all.slice(0,3);\n const header = `| Campaign | Channel | ROAS | Spend | Revenue | CTR | CVR |\n|---|---|---:|---:|---:|---:|---:|`;\n const lines = top.map(t =>\n `| ${t.name} | ${t.channel} | ${fmt(t.roas,2)} | $${fmt(t.spend,2)} | $${fmt(t.revenue,2)} | ${fmt(t.ctr,2)}% | ${fmt(t.convRate,2)}% |`\n );\n return [header, ...lines].join('\\n');\n}\n\n// ---- assemble markdown ----\nconst md = [\n `# Weekly Performance Report`,\n `**Period:** ${period.start ?? \"-\"} → ${period.end ?? \"-\"}`,\n ``,\n `## Executive Summary`,\n exec,\n ``,\n `## Totals`,\n `- Impressions: ${fmt(S.impressions)}`,\n `- Clicks: ${fmt(S.clicks)}`,\n `- Conversions: ${fmt(S.conversions)}`,\n `- Spend: $${fmt(S.spend,2)}`,\n `- Revenue: $${fmt(S.revenue,2)}`,\n `- ROAS: ${fmt(S.roas,2)}`,\n `- CTR: ${fmt(S.ctr,2)}%`,\n `- Conversion Rate: ${fmt(S.convRate,2)}%`,\n ``,\n `## Performance by Channel`,\n channels.length ? mdChannelTable(channels) : \"_No channel data._\",\n ``,\n `## Top Campaigns (by ROAS)`,\n channels.length ? mdTopCampaigns(channels) : \"_No campaigns available._\",\n ``,\n `*Generated automatically by n8n.*`\n].join('\\n');\n\nreturn {\n report: md,\n period,\n summary: S,\n byChannel: channels\n};"
},
"typeVersion": 2
},
{
"id": "42bceff8-69d9-4d21-9d94-f3f7c2dd82ed",
"name": "문서 생성",
"type": "n8n-nodes-base.googleDocs",
"position": [
1248,
256
],
"parameters": {
"title": "=Weekly Performance Report – {{ $json.period.start }} to {{ $json.period.end }}",
"folderId": "11ih8BSx4EacEniL01PhPSHzRbvaWj83n"
},
"credentials": {
"googleDocsOAuth2Api": {
"id": "9WVdXWeVTwOgO9X6",
"name": "ClickLessAI Google Docs"
}
},
"typeVersion": 2
},
{
"id": "4c463d5e-23a6-4662-b6c9-f1b818e81cd0",
"name": "문서 업데이트",
"type": "n8n-nodes-base.googleDocs",
"position": [
1520,
256
],
"parameters": {
"actionsUi": {
"actionFields": [
{
"text": "={{ $('Code in JavaScript').item.json.report }}",
"action": "insert"
}
]
},
"operation": "update",
"documentURL": "={{ $json.id }}"
},
"credentials": {
"googleDocsOAuth2Api": {
"id": "9WVdXWeVTwOgO9X6",
"name": "ClickLessAI Google Docs"
}
},
"typeVersion": 2
},
{
"id": "b9a2b5f0-0b83-439a-9acd-04031d27ed27",
"name": "메시지 전송",
"type": "n8n-nodes-base.slack",
"position": [
1808,
256
],
"webhookId": "8e51042f-918e-4efb-bf65-86e675e65a65",
"parameters": {
"text": "=:bar_chart: Weekly report is ready\nPeriod: {{ $('Code in JavaScript').item.json.period.start }} → {{ $('Code in JavaScript').item.json.period.end }}\nTopline: ROAS {{ $('Code in JavaScript').item.json.summary.roas }} | Spend ${{ $('Code in JavaScript').item.json.summary.spend }}\n\nOpen Doc: https://docs.google.com/document/d/{{ $json.documentId }}/edit",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C09HKQVAKB7",
"cachedResultName": "demo"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"id": "G4NvdInPNhmhP1e9",
"name": "Slack account"
}
},
"typeVersion": 2.3
},
{
"id": "d01c3e2e-abc4-4cf8-8136-22b5c4b15c62",
"name": "스티키 노트1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-416,
320
],
"parameters": {
"color": 4,
"width": 496,
"height": 368,
"content": "## 💡 Why This Is Valuable\n- Saves time – no manual copy-paste across ad platforms or spreadsheets. \n- Standardizes reporting – same structure and clarity every week. \n- Adds insights – AI summary highlights wins, problems, and recommendations automatically. \n- Improves transparency – team + client get instant access in Slack/Docs/Email. \n- Scales easily – works for multiple clients/campaigns with minimal changes. \n- Professional client experience – polished reports delivered consistently on time."
},
"typeVersion": 1
},
{
"id": "177d41bb-20ff-46da-af5d-3e8e863b5e71",
"name": "스티키 노트2",
"type": "n8n-nodes-base.stickyNote",
"position": [
288,
-16
],
"parameters": {
"color": 3,
"height": 448,
"content": "## 📊 Generate Metrics (Demo)\nProduces fake ad performance data for Google Ads, Meta, TikTok & YouTube.\n\n👉 Replace with real API connectors (Google Ads, Meta Ads, TikTok, YouTube) if you want live data."
},
"typeVersion": 1
},
{
"id": "ef227c18-b1f5-4dde-87f0-4bc5fa3c6fd0",
"name": "스티키 노트3",
"type": "n8n-nodes-base.stickyNote",
"position": [
544,
-16
],
"parameters": {
"color": 2,
"width": 320,
"height": 448,
"content": "## 🤖 AI Executive Summary\nSends metrics to OpenAI (LLM) to create a concise summary with wins, issues, and recommendations. \n\n👉 Make sure your **OpenAI credentials** are connected."
},
"typeVersion": 1
},
{
"id": "7007246b-9269-4e94-a243-0e76c1926654",
"name": "스티키 노트4",
"type": "n8n-nodes-base.stickyNote",
"position": [
880,
-16
],
"parameters": {
"color": 4,
"width": 256,
"height": 448,
"content": "## 📝 Build Markdown Report\nCombines raw metrics + AI summary into a structured Markdown report. \nIncludes totals, per-channel table, and top campaigns by ROAS. \n \n👉 Node name references must match exactly (“Google Ads Demo”, “Message a model”)."
},
"typeVersion": 1
},
{
"id": "e8091e8f-7c67-407b-9533-b8a41f339b29",
"name": "스티키 노트5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1152,
-16
],
"parameters": {
"color": 5,
"width": 272,
"height": 448,
"content": "## 📄 Google Docs Creation\nCreates a new Google Doc titled \n**“Weekly Performance Report – [Start Date] to [End Date]”**. \n\n👉 Requires Google Docs OAuth connection."
},
"typeVersion": 1
},
{
"id": "57e73a10-801c-40e6-a840-5f29c8f5a4b3",
"name": "스티키 노트7",
"type": "n8n-nodes-base.stickyNote",
"position": [
1440,
-16
],
"parameters": {
"width": 256,
"height": 448,
"content": "## 🖊️ Update Google Doc\nInserts the Markdown report into the created document. \n👉 You’ll get a polished report ready for sharing."
},
"typeVersion": 1
},
{
"id": "1ed03086-b047-4138-a733-f3566cd69678",
"name": "스티키 노트6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1712,
-16
],
"parameters": {
"color": 6,
"width": 304,
"height": 448,
"content": "## 💬 Slack Notification\nSends a Slack message with topline numbers (ROAS, Spend) + direct link to the Google Doc. \n👉 Connect your Slack account and set the channel ID."
},
"typeVersion": 1
},
{
"id": "28afc12f-f5fb-4262-bcaa-1f1f5900dcad",
"name": "스티키 노트8",
"type": "n8n-nodes-base.stickyNote",
"position": [
528,
480
],
"parameters": {
"width": 1056,
"height": 416,
"content": "## 💡 Extra Recommendation: Use a Google Docs Template\nInstead of creating a blank Google Doc, connect this workflow to a **pre-styled Google Docs template**. \n👉 This makes your reports look more professional right away. \n\n### Benefits:\n- Consistent branding (logo, fonts, colors). \n- Polished design without extra formatting steps. \n- Easier for clients/stakeholders to read. \n\n### How:\n1. Create a Google Docs file with your preferred layout and styles. \n2. Save its **document ID**. \n3. Replace the \"Create Google Doc\" node with a **Copy Document** step that duplicates your template. \n4. Update the copy with the AI-generated report content. \n\n💡 Result: Every report keeps a consistent, branded look while still being updated automatically.\n"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "4e9d3eae-5822-422b-85d9-9b9c0dd0bcbb",
"connections": {
"f9fc4b70-f2dd-44f8-8ba1-245bf9f6a116": {
"main": [
[
{
"node": "c335b635-893a-4e1d-aeeb-ecc4c4947bbd",
"type": "main",
"index": 0
}
]
]
},
"c335b635-893a-4e1d-aeeb-ecc4c4947bbd": {
"main": [
[
{
"node": "6a4ebcda-4997-4dc8-ab60-3370c0bf373e",
"type": "main",
"index": 0
}
]
]
},
"d5ec0af7-cb90-4cd6-91dc-69857fe7bca9": {
"main": [
[
{
"node": "f9fc4b70-f2dd-44f8-8ba1-245bf9f6a116",
"type": "main",
"index": 0
}
]
]
},
"42bceff8-69d9-4d21-9d94-f3f7c2dd82ed": {
"main": [
[
{
"node": "4c463d5e-23a6-4662-b6c9-f1b818e81cd0",
"type": "main",
"index": 0
}
]
]
},
"4c463d5e-23a6-4662-b6c9-f1b818e81cd0": {
"main": [
[
{
"node": "b9a2b5f0-0b83-439a-9acd-04031d27ed27",
"type": "main",
"index": 0
}
]
]
},
"6a4ebcda-4997-4dc8-ab60-3370c0bf373e": {
"main": [
[
{
"node": "42bceff8-69d9-4d21-9d94-f3f7c2dd82ed",
"type": "main",
"index": 0
}
]
]
}
}
}자주 묻는 질문
이 워크플로우를 어떻게 사용하나요?
위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.
이 워크플로우는 어떤 시나리오에 적합한가요?
고급
유료인가요?
이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.
관련 워크플로우 추천
온보딩 통화 점수 시스템
Fireflies.ai, OpenAI 및 Google Sheets를 사용한 영업 통화 점수 매기기 자동화
Code
Gmail
Slack
+
Code
Gmail
Slack
14 노드Emilio Loewenstein
GPT-4와 Apify 기반 AI 기반 경쟁사 및 시장 인텔리전스 시스템
GPT-4와 Apify 기반 AI 기반 경쟁사 및 시장 인텔리전스 시스템
Code
Merge
Slack
+
Code
Merge
Slack
12 노드Marth
시장 조사
AI 부동산 중개인: 종단간 운영 자동화 (웹, 데이터, 음성)
AI 부동산 중개인: 종단간 운영 자동화 (웹, 데이터, 음성)
If
Set
Code
+
If
Set
Code
45 노드Sam Yassine
영업
주식 분석 어시스턴트
AI 기반 주식 시장 요약 봇
If
Set
Code
+
If
Set
Code
21 노드kenandrewmiranda
금융
GPT-4, Google 검색 API 및 Slack을 사용한 뉴스 발견 및 게시 자동화
GPT-4, Google 검색 API 및 Slack을 사용한 뉴스 발견 및 게시 자동화
Code
Slack
Http Request
+
Code
Slack
Http Request
14 노드Kalyxi Ai
기타
Groq, Gemini, Slack 승인 시스템을 사용한 RSS에서 Medium 자동 게시
Groq, Gemini 및 Slack 승인 시스템을 통한 RSS에서 Medium 발행 자동화 워크플로
If
Set
Code
+
If
Set
Code
41 노드ObisDev
콘텐츠 제작
워크플로우 정보
난이도
고급
노드 수16
카테고리-
노드 유형6
저자
Emilio Loewenstein
@emilio-loewensteinEmilio is an 18-year-old AI Engineer and Co-Founder of an AI agency, building intelligent systems that help businesses automate, innovate, and scale.
외부 링크
n8n.io에서 보기 →
이 워크플로우 공유