This workflow corresponds to n8n.io template #6637 — we link there as the canonical source.
This workflow follows the Agent → Gmail 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 →
{
"id": "Ipiegq0ZW8v3UJGF",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AI Content Scout - Weekly Competitor Blogs and News Digest",
"tags": [],
"nodes": [
{
"id": "3e82b98b-de16-43f1-80e2-e3fefd6c9b03",
"name": "Firecrawl_Links",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1620,
-600
],
"parameters": {
"url": "https://api.firecrawl.dev/v1/scrape",
"method": "POST",
"options": {
"batching": {
"batch": {
"batchSize": 1,
"batchInterval": 7000
}
}
},
"jsonBody": "={\n \"url\": \"{{$json.Link}}\",\n \"formats\": [\n \"links\"\n ],\n \"onlyMainContent\": true,\n \"timeout\": 90000 \n} ",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.2,
"waitBetweenTries": 5000
},
{
"id": "b4d59e54-fe55-463f-982b-94e86a0afaf0",
"name": "Split Out",
"type": "n8n-nodes-base.splitOut",
"position": [
-1100,
-600
],
"parameters": {
"options": {},
"fieldToSplitOut": "output"
},
"typeVersion": 1
},
{
"id": "d3a3fb55-ee13-45e8-8dfc-51628b11a272",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
-1080,
-400
],
"parameters": {
"jsonSchemaExample": "[\n { \"url\": \"https://example.com/topic-1\" }\n]"
},
"typeVersion": 1.2
},
{
"id": "13f19f4f-3e34-472e-b9e3-f224bff49c76",
"name": "Structured Output Parser2",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
-440,
-400
],
"parameters": {
"jsonSchemaExample": "[\n {\n \"title\": \"The Main Article Title\",\n \"author\": \"Jane Doe\",\n \"url\": \"https://example.com/article-url\",\n \"summary\": \"This is a concise summary of the article. It captures the key points effectively. The length is about three to four sentences.\",\n \"published_date\": \"2025-06-22\"\n }\n]"
},
"typeVersion": 1.2
},
{
"id": "1a600915-9f55-45e6-a7bc-0e9689c16609",
"name": "Agent: Summarize Each URL",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-680,
-600
],
"parameters": {
"text": "=Extract the required information from the following content and its associated URL.\n\nURL:\n{{ $json.data.metadata['og:url'] }}\n\nMarkdown Content:\n{{ $json.data.markdown }}\n\n",
"options": {
"systemMessage": "=You are a specialized content analysis assistant. Your sole function is to process a markdown document and its associated URL, extract specific fields of information, and return the data in a strictly defined JSON format.\n\n**Extraction Rules:**\nFrom the provided markdown text, you will extract the following fields to populate a single JSON object:\n\n1. **`title`**: Extract the primary, most prominent title of the article.\n2. **`author`**: Extract the name or names of the authors. If no author can be clearly identified, this field should be populated as `NA`.\n3. **`url`**: Use the exact URL provided in the user's prompt. Do not attempt to find a URL in the markdown content itself.\n4. **`summary`**: Generate a concise and neutral summary of the article's main points. The summary should be 3 to 4 sentences long.\n5. **`published_date`**: Find the article's publication date and reformat it to the strict ISO `YYYY-MM-DD` format. If no date is found, this field should be populated as `NA`.\n\n**Output Format (Strict):**\n- The response MUST contain ONLY the raw JSON array.\n- You MUST return a top-level JSON array that contains the single JSON object you created.\n- DO NOT wrap the JSON in markdown code blocks (e.g., ```json), add comments, or include any introductory text like \"Here is the JSON:\". The output must be immediately parsable by a machine."
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2
},
{
"id": "29993d3d-0c0d-4569-9cb7-90d4701111a1",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-660,
-720
],
"parameters": {
"width": 220,
"height": 100,
"content": "From the provided link, extract the following: title, author, url, summary: 3\u20134 sentences, published_date\n"
},
"typeVersion": 1
},
{
"id": "c6193854-c62d-4185-b155-caa444b7d13e",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-920,
-720
],
"parameters": {
"width": 150,
"height": 100,
"content": "Firecrawl Free Tier only allows 10 requests per min (1 request per 6s)"
},
"typeVersion": 1
},
{
"id": "8b2c1996-511b-4870-8ce5-81808474a732",
"name": "Gemini 2.5 Flash: Temp 0",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-760,
-400
],
"parameters": {
"options": {
"temperature": 0
},
"modelName": "models/gemini-2.5-flash"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "8bd2c322-ce8d-4c6f-9f20-49e3ffcfdcba",
"name": "Firecrawl_Markdown",
"type": "n8n-nodes-base.httpRequest",
"position": [
-900,
-600
],
"parameters": {
"url": "https://api.firecrawl.dev/v1/scrape",
"method": "POST",
"options": {
"batching": {
"batch": {
"batchSize": 1,
"batchInterval": 7000
}
}
},
"jsonBody": "={\n \"url\": \"{{ $json.url }}\",\n \"formats\": [\n \"markdown\"\n ],\n \"onlyMainContent\": true,\n \"timeout\": 90000\n} ",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.2,
"waitBetweenTries": 5000
},
{
"id": "8cf17425-1ab7-4126-a0ac-e526a8854c78",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1460,
-780
],
"parameters": {
"width": 280,
"content": "Each link contains candidate URL: \n1) Compare Candidate URL to Existing URl in Read_Url_Summary_Tool\n2) Filter out match URLs\n3) Identify proper URLs (no top level page, navigation, bad URLs, etc.)"
},
"typeVersion": 1
},
{
"id": "8bfc0649-5bf9-4bd0-b127-8ce288382a2d",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1660,
-720
],
"parameters": {
"width": 150,
"height": 100,
"content": "Firecrawl Free Tier only allows 10 requests per min (1 request per 6s)"
},
"typeVersion": 1
},
{
"id": "6671d901-2171-448d-a6dd-e6b5ff86df6e",
"name": "Agent: Identify URLs to Crawl",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-1440,
-600
],
"parameters": {
"text": "=Please process and filter the following list of URLs:\n\nCANDIDATE_URLS: {{ $json.data.links }}\n",
"options": {
"systemMessage": "=### Role & Goal:\nYou are an expert content-analysis assistant specializing in URL filtering. Your mission: receive a list of CANDIDATE_URLS and emit only those that (a) fit the topical rules and (b) are not already present in a Google Sheet.\n\n\n### Tools Available:\nRead_Url_Summary_Tool \u2013 returns a JSON array of {\"url\":\"<https://...>\"} objects from the Google Sheet. Call exactly once per run.\n\n\n### Workflow (follow in order)\n1. Invoke Read_Url_Summary_Tool; store as EXISTING_URLS.\n2. Normalise every URL in both arrays (lower-case host, trim trailing /, strip utm_* params).\n3. Drop any candidate that appears in EXISTING_URLS or is duplicated within CANDIDATE_URLS.\n3. Apply Topical Inclusion + Exclusion Rules.\n4. If no URLs survive, return [].\n\n\n### Topical Inclusion\nIdentify and extract URLs for blog posts, technical articles, tutorials, product updates, thought-leadership pieces, news, or press releases.\n\n\n### Exclusion Rules (Discard if any of these apply):\n1. Invalid Format: Not a valid `http` or `https` URL.\n\n2. Fragments: Contains a URL fragment (`#`).\n\n3. Utility/Boilerplate Pages: Appears to be a login portal, dashboard, contact page, privacy policy, terms of service, or other non-content utility link.\n\n4. Generic Navigation:\n - Homepage: The path is empty, `/`, or a common index file (e.g., `index.html`).\n - Index/Listing Pages: The URL is for a tag, category, search result, or author listing page.\n\n5. Section Landing Pages:\n - Generic Rule: The URL path consists of exactly one segment (e.g., `https://site.com/blog/`, `https://site.com/news`).\n - Specific Rule: The final segment of the URL path is one of the following: `blog`, `products`, `solutions`, `press`, or `press-releases` (e.g., `https://site.com/company/blog`).\n\n\n### Default Behavior:\nIf you are uncertain whether a URL should be excluded, **include it**.\n\n### Output Format (Strict):\n- You MUST return ONLY a raw JSON array of objects.\n- Each object in the array MUST contain a single key-value pair: `{ \"url\": \"https://...\" }`.\n- Do NOT wrap the JSON array in markdown code blocks (e.g., \\`\\`\\`json), do not add comments, and do not include any introductory text or explanations in your response. The output must be immediately parsable.\n"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2
},
{
"id": "d6fb940c-ac63-4b0f-afcd-a5395c8b821b",
"name": "Code",
"type": "n8n-nodes-base.code",
"position": [
80,
-600
],
"parameters": {
"jsCode": "const items = $input.all().map((item) => item.json);\nconst today = new Date().toISOString().slice(0, 10);\nconst filteredItems = items.filter((item) => item[\"Crawled Date\"] === today);\n\nconst groupedItems = filteredItems.reduce((acc, item) => {\n acc[item.Company] = acc[item.Company] || [];\n acc[item.Company].push(item);\n return acc;\n}, {});\n\nlet html = \"\";\n\nfor (const company in groupedItems) {\n html += `<h2>${company}</h2>`;\n html += `<table style=\"border-collapse: collapse;\">`;\n html += `<tr>\n <th style=\"border: 1px solid #000;\">Crawled Date</th>\n <th style=\"border: 1px solid #000;\">Page Type</th>\n <th style=\"border: 1px solid #000;\">Title</th>\n <th style=\"border: 1px solid #000;\">Author</th>\n <th style=\"border: 1px solid #000;\">Published Date</th>\n <th style=\"border: 1px solid #000;\">URL</th>\n <th style=\"border: 1px solid #000;\">Summary</th>\n </tr>`;\n for (const row of groupedItems[company]) {\n html += `<tr>\n <td style=\"border: 1px solid #000;\">${row[\"Crawled Date\"]}</td>\n <td style=\"border: 1px solid #000;\">${row[\"Page Type\"]}</td>\n <td style=\"border: 1px solid #000;\">${row.Title}</td>\n <td style=\"border: 1px solid #000;\">${row.Author}</td>\n <td style=\"border: 1px solid #000;\">${row[\"Published Date\"]}</td>\n <td style=\"border: 1px solid #000;\">${row.URL}</td>\n <td style=\"border: 1px solid #000;\">${row.Summary}</td>\n </tr>`;\n }\n html += `</table>`;\n}\n\nreturn { html };\n"
},
"typeVersion": 2
},
{
"id": "b0ccd551-267d-4e94-87bb-678e05b048ed",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
20,
-720
],
"parameters": {
"width": 210,
"height": 100,
"content": "Create HTML email with following conditions: \n1) Crawled Date == today \n2) Group by Company "
},
"typeVersion": 1
},
{
"id": "b5cee799-67a5-42fa-873c-dbb9a4dfeb7e",
"name": "Schedule Trigger: Every Sun 5AM",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1980,
-600
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 0 5 * * SUN"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "aa902638-34e1-484f-a3e2-fe38d1aecec7",
"name": "Input Links",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1800,
-600
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 288631821,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I/edit#gid=288631821",
"cachedResultName": "Input Links"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I/edit?usp=drivesdk",
"cachedResultName": "URL Summary"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "8668df12-fae8-4e46-a38b-f725e0322e1b",
"name": "Read_Url_Summary_Tool",
"type": "n8n-nodes-base.googleSheetsTool",
"position": [
-1260,
-400
],
"parameters": {
"options": {
"dataLocationOnSheet": {
"values": {
"range": "G:G",
"rangeDefinition": "specifyRangeA1"
}
}
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 751716000,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I/edit#gid=751716000",
"cachedResultName": "Summary"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I/edit?usp=drivesdk",
"cachedResultName": "URL Summary"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "02ccaaa4-8bf0-4838-8735-5f9f66013bcd",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1300,
-240
],
"parameters": {
"width": 150,
"height": 80,
"content": "Filter all columns except for URL"
},
"typeVersion": 1
},
{
"id": "c331f161-9987-4b83-9c8e-489d2eaa9b8f",
"name": "Append row in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-340,
-600
],
"parameters": {
"columns": {
"value": {
"URL": "={{ $json.output[0].url }}",
"Title": "={{ $json.output[0].title }}",
"Author": "={{ $json.output[0].author }}",
"Company": "={{ $('Input Links').item.json.Company }}",
"Summary": "={{ $json.output[0].summary }}",
"Page Type": "={{ $('Input Links').item.json['Page Type'] }}",
"Crawled Date": "={{ $today.toISODate()}} ",
"Published Date": "={{ $json.output[0].published_date }}"
},
"schema": [
{
"id": "Crawled Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Crawled Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Company",
"type": "string",
"display": true,
"required": false,
"displayName": "Company",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Page Type",
"type": "string",
"display": true,
"required": false,
"displayName": "Page Type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Title",
"type": "string",
"display": true,
"required": false,
"displayName": "Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Author",
"type": "string",
"display": true,
"required": false,
"displayName": "Author",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Published Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Published Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "URL",
"type": "string",
"display": true,
"required": false,
"displayName": "URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Summary",
"type": "string",
"display": true,
"required": false,
"displayName": "Summary",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 751716000,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I/edit#gid=751716000",
"cachedResultName": "Summary"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I/edit?usp=drivesdk",
"cachedResultName": "URL Summary"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "deb80efb-a7e9-420c-a32e-69d330240d8f",
"name": "OpenAI o4-mini",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-1500,
-400
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "o4-mini",
"cachedResultName": "o4-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "9d8c297a-3227-4740-8518-65e76aeb6795",
"name": "Get row(s) in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-120,
-600
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 751716000,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I/edit#gid=751716000",
"cachedResultName": "Summary"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1R01ELC8ZTWvyw2ULRPnMogrtqkoVV40ANa4qqVi3F-I/edit?usp=drivesdk",
"cachedResultName": "URL Summary"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"executeOnce": true,
"typeVersion": 4.6
},
{
"id": "4e92d820-b67e-4f19-ad88-aef6ac3b3eb7",
"name": "Send a message",
"type": "n8n-nodes-base.gmail",
"position": [
280,
-600
],
"parameters": {
"sendTo": "user@example.com, user@example.com",
"message": "={{ $json.html }}",
"options": {
"appendAttribution": false
},
"subject": "URL Summary"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"notesInFlow": false,
"typeVersion": 2.1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "dc752747-ec83-4432-a5b1-56911fcc3005",
"connections": {
"Code": {
"main": [
[
{
"node": "Send a message",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Firecrawl_Markdown",
"type": "main",
"index": 0
}
]
]
},
"Input Links": {
"main": [
[
{
"node": "Firecrawl_Links",
"type": "main",
"index": 0
}
]
]
},
"OpenAI o4-mini": {
"ai_languageModel": [
[
{
"node": "Agent: Identify URLs to Crawl",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Send a message": {
"main": [
[]
]
},
"Firecrawl_Links": {
"main": [
[
{
"node": "Agent: Identify URLs to Crawl",
"type": "main",
"index": 0
}
]
]
},
"Firecrawl_Markdown": {
"main": [
[
{
"node": "Agent: Summarize Each URL",
"type": "main",
"index": 0
}
]
]
},
"Append row in sheet": {
"main": [
[
{
"node": "Get row(s) in sheet",
"type": "main",
"index": 0
}
]
]
},
"Get row(s) in sheet": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Read_Url_Summary_Tool": {
"ai_tool": [
[
{
"node": "Agent: Identify URLs to Crawl",
"type": "ai_tool",
"index": 0
}
]
]
},
"Gemini 2.5 Flash: Temp 0": {
"ai_languageModel": [
[
{
"node": "Agent: Summarize Each URL",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Agent: Identify URLs to Crawl",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Agent: Summarize Each URL": {
"main": [
[
{
"node": "Append row in sheet",
"type": "main",
"index": 0
}
]
]
},
"Structured Output Parser2": {
"ai_outputParser": [
[
{
"node": "Agent: Summarize Each URL",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Agent: Identify URLs to Crawl": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger: Every Sun 5AM": {
"main": [
[
{
"node": "Input Links",
"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.
gmailOAuth2googlePalmApigoogleSheetsOAuth2ApihttpHeaderAuthopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Who is this template for? This workflow is perfect for competitive‑intel analysts, product managers, content marketers, and anyone who tracks multiple company blogs or news sources. If you need a weekly snapshot of fresh, on‑topic articles—without wading through dozens of…
Source: https://n8n.io/workflows/6637/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This n8n automation workflow automates the creation, scripting, production, and posting of YouTube videos. It leverages AI (OpenAI), image generation (PIAPI), video rendering (Shotstack), and platform
Created by: Peyton Leveillee Last updated: October 2025
The Multi-Model Agency Content Engine is a high-performance editorial system designed for agencies. It solves the "blank page" problem by alternating between real-world social proof and strategic expe
SEO Blog Article Generation Workflow. Uses outputParserStructured, httpRequest, agent, lmChatOpenAi. Scheduled trigger; 56 nodes.
This workflow was born out of a very real problem.