This workflow corresponds to n8n.io template #7626 — we link there as the canonical source.
This workflow follows the Agent → Google Drive 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": "e76kXc6JxjK4rP5R",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Decodo SaaS Pricing Intelligence Workflow (B2B Pricing Radar)",
"tags": [
{
"id": "vx2KtjCPUPLpD567",
"name": "Decodo",
"createdAt": "2025-09-05T06:01:07.861Z",
"updatedAt": "2025-09-05T06:01:07.861Z"
}
],
"nodes": [
{
"id": "0f69d6dc-d0de-4e52-925e-23e14d379c6e",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
3888,
2864
],
"parameters": {},
"typeVersion": 1
},
{
"id": "c474f487-1bed-485a-8236-52ff805fbaf5",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
4800,
3088
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "c0ffe410-ca5a-4650-bd95-9654aece1cb0",
"name": "Pricing Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
4928,
3088
],
"parameters": {
"jsonSchemaExample": "[\n {\n \"plan_name\": \"Scale\",\n \"monthly_price\": 59,\n \"annual_price\": 590,\n \"currency\": \"USD\",\n \"billing_model\": \"per active seat\",\n \"target_team_size\": \"Growth teams\",\n \"headline_features\": [\n \"Unlimited automations\",\n \"Usage-based discounts\",\n \"Dedicated support\"\n ],\n \"cta_url\": \"https://example.com/pricing/scale\",\n \"notes\": \"Best for teams needing compliance and premium onboarding\"\n }\n]"
},
"typeVersion": 1.3
},
{
"id": "8c5f5964-2f60-4e19-a7b3-c52ddf7036c1",
"name": "Create pricing brief doc",
"type": "n8n-nodes-base.httpRequest",
"position": [
5584,
2864
],
"parameters": {
"url": "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&supportsAllDrives=true",
"body": "\n=--foo_bar_baz\nContent-Type: application/json; charset=UTF-8\n\n{\n \"name\": \"{{ $json.ReportTitle || $json.Today }}\",\n \"mimeType\": \"application/vnd.google-apps.document\",\n \"parents\": [\"{{ $json['Drive Folder ID'] }}\"]\n}\n\n--foo_bar_baz\nContent-Type: text/markdown; charset=UTF-8\n\n{{ $('Build \ud83d\udcbc SaaS Pricing Brief').item.json.markdown }}\n\n--foo_bar_baz--\n",
"method": "POST",
"options": {},
"sendBody": true,
"sendQuery": true,
"contentType": "raw",
"sendHeaders": true,
"authentication": "predefinedCredentialType",
"rawContentType": "multipart/related; boundary=foo_bar_baz",
"queryParameters": {
"parameters": [
{
"name": "uploadType",
"value": "multipart"
},
{
"name": "supportsAllDrives",
"value": "true"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "boundary",
"value": "foo_bar_baz"
}
]
},
"nodeCredentialType": "googleDriveOAuth2Api"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "24e8ee2e-28ca-42bb-8fe0-f0e99a95e05e",
"name": "Convert brief to PDF",
"type": "n8n-nodes-base.googleDrive",
"position": [
5808,
2864
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {
"googleFileConversion": {
"conversion": {
"docsToFormat": "application/pdf"
}
}
},
"operation": "download"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "f566bba5-2967-4643-8c60-9155dd10f90d",
"name": "Configure Google Drive Destination",
"type": "n8n-nodes-base.set",
"position": [
5344,
2864
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "0bc3e13b-b377-4a86-8a2d-be3f88f33af8",
"name": "Drive Folder ID",
"type": "string",
"value": "Replace-with-your-shared-drive-folder-id"
},
{
"id": "a4682fbf-698d-43b2-8eb7-dfbc1bb5ded4",
"name": "Today",
"type": "string",
"value": "={{ $now.format(\"yyyyMMddHHmmss\") }}"
},
{
"id": "bd96128f-6e16-488e-8e30-0f64d266e201",
"name": "ReportTitle",
"type": "string",
"value": "={{ $(\"Configure Target Pricing Page\").item.json.ReportTitle || `SaaS Pricing Brief ${$now.format(\"yyyyMMdd\")}` }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "ac01efa8-1e44-4a80-a62e-458666ac7237",
"name": "Plan Extraction Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
4784,
2864
],
"parameters": {
"text": "=Extract B2B SaaS pricing plans, billing models, and positioning cues from the cleaned page content below.\n{{ $json.text }}",
"options": {
"systemMessage": "You are a SaaS pricing analyst. Return only well-structured JSON plans with numeric prices and short feature bullets."
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.1
},
{
"id": "06ca41cb-2c26-487b-b490-e384378d578f",
"name": "Configure Target Pricing Page",
"type": "n8n-nodes-base.set",
"position": [
4112,
2864
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "4410a5c2-d8e0-4f07-8bbf-476a541e68fc",
"name": "decodoTokenHint",
"type": "string",
"value": "Get token from your Decodo dashboard (https://dashboard.decodo.com/web-scraping-api/scraper)"
},
{
"id": "2e67b243-654f-4fa7-be77-5e4233e30b9d",
"name": "url",
"type": "string",
"value": "https://stripe.com/pricing"
},
{
"id": "a843c1fa-b6cf-422f-a019-a294a07b02e8",
"name": "deviceMode",
"type": "string",
"value": "desktop"
},
{
"id": "61eae5bb-2941-4706-a424-877994c2a204",
"name": "Brand",
"type": "string",
"value": "Stripe"
},
{
"id": "d233a04f-c288-452d-b70e-4974032cb52a",
"name": "ReportTitle",
"type": "string",
"value": "Stripe Pricing Radar"
},
{
"id": "fc75ea9c-48b8-47b8-931f-3c3daf7d39b4",
"name": "Notes",
"type": "string",
"value": "Track PLG plans + highlight feature shifts"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "69c38e1f-b790-45d1-8237-c694a14c073c",
"name": "HTML Response Parser",
"type": "n8n-nodes-base.code",
"position": [
4560,
2864
],
"parameters": {
"jsCode": "// n8n Code node (JavaScript)\n// Input: $input.first().json.results[0].content\n// Output: clean plain text (no HTML/JS/CSS, minimal \\n)\n\nfunction stripAll(html) {\n if (typeof html !== 'string') return '';\n\n // Remove scripts, styles, head, comments, svg, noscript, canvas\n html = html.replace(/<script[\\s\\S]*?<\\/script>/gi, '');\n html = html.replace(/<style[\\s\\S]*?<\\/style>/gi, '');\n html = html.replace(/<head[\\s\\S]*?<\\/head>/gi, '');\n html = html.replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '');\n html = html.replace(/<svg[\\s\\S]*?<\\/svg>/gi, '');\n html = html.replace(/<canvas[\\s\\S]*?<\\/canvas>/gi, '');\n html = html.replace(/<!--[\\s\\S]*?-->/g, '');\n\n // Replace block-level tags with a single newline\n const blockTags = [\n 'p','div','section','article','header','footer','nav','aside','main',\n 'h1','h2','h3','h4','h5','h6','ul','ol','li','table','tr','td','th','br','hr'\n ];\n for (const tag of blockTags) {\n const rxOpen = new RegExp(`<${tag}[^>]*>`, 'gi');\n const rxClose = new RegExp(`</${tag}>`, 'gi');\n html = html.replace(rxOpen, '\\n');\n html = html.replace(rxClose, '\\n');\n }\n\n // Strip all remaining tags\n let text = html.replace(/<\\/?[^>]+>/g, '');\n\n // Decode common HTML entities\n text = text\n .replace(/ /g, ' ')\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\");\n\n // Clean whitespace\n text = text\n .replace(/\\r/g, '')\n .replace(/[ \\t]+/g, ' ') // collapse spaces/tabs\n .replace(/\\n[ \\t]+/g,'') // trim spaces after newlines\n .replace(/\\n{3,}/g, '') // collapse 3+ newlines into 2\n .trim();\n \n return text;\n}\n\n// MAIN\nconst html = $input.first().json?.results?.[0]?.content || '';\nif (!html) {\n return [{ json: { error: 'No HTML found at json.results[0].content' } }];\n}\n\nconst text = stripAll(html);\n\nreturn [{\n json: {\n text,\n chars: text.length\n }\n}];"
},
"typeVersion": 2
},
{
"id": "da09c63d-64fd-428a-b975-75b7c090f1ed",
"name": "Share brief in Slack",
"type": "n8n-nodes-base.slack",
"position": [
6032,
2864
],
"parameters": {
"options": {
"fileName": "=SaaS Pricing Brief {{ $today.format('yyyy-MM-dd') }}",
"channelId": "C09E9SDE99P",
"initialComment": "\ud83d\udcca SaaS Pricing Brief ready \u2014 review tier shifts + highlights."
},
"resource": "file",
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "67a268db-38a3-4573-ab8e-142980a181ca",
"name": "Build \ud83d\udcbc SaaS Pricing Brief",
"type": "n8n-nodes-base.code",
"position": [
5136,
2864
],
"parameters": {
"jsCode": "// n8n Code node (JavaScript)\n// Expected input:\n// items[0].json.output = [ { plan_name, monthly_price, annual_price, currency, billing_model, target_team_size, headline_features[], cta_url, notes } ]\n\nfunction cleanNumber(value) {\n if (value === null || value === undefined || value === '') return null;\n const num = Number(String(value).replace(/[^0-9.]/g, ''));\n return Number.isFinite(num) ? num : null;\n}\n\nfunction mean(nums) {\n const valid = nums.filter(n => Number.isFinite(n));\n return valid.length ? valid.reduce((a, b) => a + b, 0) / valid.length : 0;\n}\n\nfunction currencyFmt(value, currency = 'USD') {\n if (!Number.isFinite(value)) return 'n/a';\n try {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(value);\n } catch (e) {\n return `$${value.toFixed(2)}`;\n }\n}\n\nfunction safe(value, fallback = 'n/a') {\n if (value === undefined || value === null || value === '') return fallback;\n if (Array.isArray(value) && !value.length) return fallback;\n return value;\n}\n\nconst allInputs = $input.all();\n\n// Support both: {output:[...]} and direct array input\nconst plans =\n (allInputs?.[0]?.json?.output && Array.isArray(allInputs[0].json.output))\n ? allInputs[0].json.output\n : (Array.isArray(allInputs?.[0]?.json) ? allInputs[0].json : []);\n\nconst normalized = plans.map(plan => ({\n plan_name: safe(plan.plan_name, 'Unnamed Plan'),\n monthly_price: cleanNumber(plan.monthly_price),\n annual_price: cleanNumber(plan.annual_price),\n currency: safe(plan.currency, 'USD'),\n billing_model: safe(plan.billing_model, 'n/a'),\n target_team_size: safe(plan.target_team_size, 'n/a'),\n headline_features: Array.isArray(plan.headline_features) ? plan.headline_features.slice(0, 6) : [],\n cta_url: safe(plan.cta_url, 'n/a'),\n notes: safe(plan.notes, ''),\n}));\n\nconst currency = normalized.find(p => p.currency)?.currency || 'USD';\nconst monthlyPrices = normalized.map(p => p.monthly_price).filter(Number.isFinite);\nconst annualPrices = normalized.map(p => p.annual_price).filter(Number.isFinite);\n\nconst planCount = normalized.length;\n\nconst avgMonthly = mean(monthlyPrices);\nconst minMonthly = monthlyPrices.length ? Math.min(...monthlyPrices) : null;\nconst maxMonthly = monthlyPrices.length ? Math.max(...monthlyPrices) : null;\n\nconst avgAnnual = mean(annualPrices);\nconst minAnnual = annualPrices.length ? Math.min(...annualPrices) : null;\nconst maxAnnual = annualPrices.length ? Math.max(...annualPrices) : null;\n\nconst bestValue = [...normalized]\n .filter(p => Number.isFinite(p.monthly_price))\n .sort((a, b) => a.monthly_price - b.monthly_price)[0];\n\nconst premium = [...normalized]\n .filter(p => Number.isFinite(p.monthly_price))\n .sort((a, b) => b.monthly_price - a.monthly_price)[0];\n\nconst now = new Date();\nconst date = now.toLocaleString('en-US', { year: 'numeric', month: 'short', day: '2-digit' });\n\nconst tableHeader = '| Plan | Monthly | Annual | Billing Model | Team Fit | Key Features |';\nconst tableDivider = '| --- | --- | --- | --- | --- | --- |';\nconst tableRows = normalized.map(plan => {\n const features = plan.headline_features.length ? plan.headline_features.join('<br>') : '\u2014';\n return `| ${plan.plan_name} | ${currencyFmt(plan.monthly_price, plan.currency)} | ${currencyFmt(plan.annual_price, plan.currency)} | ${plan.billing_model} | ${plan.target_team_size} | ${features} |`;\n});\n\nconst highlightLines = [];\nif (bestValue) {\n highlightLines.push(`**Best self-serve value:** ${bestValue.plan_name} at ${currencyFmt(bestValue.monthly_price, bestValue.currency)} / month.`);\n}\nif (premium) {\n highlightLines.push(`**Top tier / enterprise:** ${premium.plan_name} peaks at ${currencyFmt(premium.monthly_price, premium.currency)} / month.`);\n}\nif (planCount >= 4) {\n highlightLines.push('Packaging spans at least 4 tiers, offering clear land-and-expand motion.');\n}\nif (!highlightLines.length) {\n highlightLines.push('Insufficient pricing variance to highlight standout tiers.');\n}\n\nconst actionItems = [];\nif (maxMonthly && maxMonthly > 0 && minMonthly && minMonthly > 0) {\n const spread = maxMonthly - minMonthly;\n if (spread < 20) {\n actionItems.push('Pricing tiers are tightly grouped \u2014 consider emphasizing feature differentiation.');\n } else {\n actionItems.push('Pricing spread supports multi-tier upsell narrative; map messaging to each persona.');\n }\n}\nif (!annualPrices.length) {\n actionItems.push('No annual pricing advertised \u2014 confirm if annual discounts exist but hidden behind sales.');\n}\nif (normalized.some(p => !p.headline_features || !p.headline_features.length)) {\n actionItems.push('Add at least three hero features per tier to clarify value proposition.');\n}\nif (!actionItems.length) {\n actionItems.push('All key pricing signals captured. Proceed to compare vs. internal packaging.');\n}\n\n// Safely read config node values (won't throw if node missing)\nconst cfg = (() => {\n try {\n return $item(0).$node['Configure Target Pricing Page']?.json || {};\n } catch (e) {\n return {};\n }\n})();\nconst sourceUrl = cfg.url || 'Target URL not provided';\nconst brand = cfg.Brand || 'Target brand';\n\nconst markdown =\n`# \ud83d\udcbc SaaS Pricing Brief\n**Brand:** ${brand}\n\n**Source URL:** ${sourceUrl}\n\n**Captured:** ${date}\n\n---\n\n## KPI Snapshot\n| Metric | Value |\n| --- | --- |\n| Plans detected | ${planCount} |\n| Avg monthly | ${currencyFmt(avgMonthly, currency)} |\n| Range monthly | ${currencyFmt(minMonthly, currency)} \u2013 ${currencyFmt(maxMonthly, currency)} |\n| Avg annual | ${currencyFmt(avgAnnual, currency)} |\n| Range annual | ${currencyFmt(minAnnual, currency)} \u2013 ${currencyFmt(maxAnnual, currency)} |\n\n---\n\n## Tier Comparison\n${tableHeader}\n${tableDivider}\n${tableRows.join('\\n')}\n\n---\n\n## Highlights\n${highlightLines.map(line => `- ${line}`).join('\\n')}\n\n---\n\n## Recommended Next Steps\n${actionItems.map(item => `- ${item}`).join('\\n')}\n`;\n\nconst stats = {\n planCount,\n currency,\n monthly: {\n avg: Number(avgMonthly.toFixed(2)),\n min: minMonthly,\n max: maxMonthly,\n },\n annual: {\n avg: Number(avgAnnual.toFixed(2)),\n min: minAnnual,\n max: maxAnnual,\n },\n};\n\nreturn [\n {\n json: {\n markdown,\n stats,\n }\n }\n];"
},
"typeVersion": 2
},
{
"id": "0fda823d-f492-4b2e-9b40-3f08f3cf0b72",
"name": "Sticky Note Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
2768,
2336
],
"parameters": {
"width": 1040,
"height": 1856,
"content": "# SaaS Pricing Brief Generator (Decodo \u2192 LLM \u2192 Google Docs \u2192 PDF \u2192 Slack)\n## \ud83d\ude80 Try Decodo \u2014 Web Scraping & Data API (Coupon: **TRUNG**)\n\n**Decodo** is a powerful public data access platform offering managed web scraping APIs and proxy infrastructure to collect structured web data at scale. It handles proxies, anti-bot protection, JavaScript rendering, retries, and global IP rotation\u2014so you can focus on data, not scraping complexity.\n**Why Decodo**\n- Managed **Web Scraping API** with anti-bot bypass & high success rates \n- Works with JS-heavy sites; outputs JSON/HTML/CSV \n- Easy integration (Python, Node.js, cURL) for eCommerce, SERP, social & general web data\n**\ud83c\udf9f\ufe0f Special Discount**\nUse coupon **`TRUNG`** to get the **Advanced Scraping API** plan \u2014 ~**23,000 requests for ~$5**.\n\n## Who this workflow is for\nThis workflow is designed for **Presales, Product Managers, Business Analysts, and Sales teams** who need to:\n- Monitor competitor or SaaS pricing pages\n- Convert unstructured pricing content into a structured, comparable format\n- Quickly generate and share an internal **pricing brief** without manual copy/paste\n\nIt is especially useful during **launches, pricing updates, or quarterly reviews**.\n\n## What this workflow does\nAt a high level, the workflow automates the full pricing intelligence pipeline:\n1. Scrapes a live SaaS pricing page using a real browser environment\n2. Cleans and normalizes the HTML for reliable parsing\n3. Uses an LLM agent to extract pricing plans into structured JSON\n4. Builds an executive-ready SaaS pricing brief\n5. Publishes the brief as a Google Doc and PDF\n6. Shares the final PDF directly to Slack\n\nThe output is a consistent, repeatable pricing brief ready for internal distribution.\n\n## How it works\n1. **Manual Trigger** \n The workflow is manually triggered to ensure intentional execution (ideal for known pricing updates).\n\n2. **Configure Target Pricing Page** \n Input the competitor pricing URL, device type, and report metadata.\n\n3. **Decodo Pricing Scraper** \n Renders the full pricing page using JS and device emulation so tier cards, modals, and dynamic content are captured correctly.\n\n4. **HTML Normalization** \n Custom code removes scripts, styles, and noise, leaving clean, readable text for the LLM.\n\n5. **Plan Extraction Agent (LLM)** \n The agent translates messy pricing text into a structured JSON schema including:\n - Plan name\n - Price and billing period\n - Key features\n - CTA / positioning notes\n\n6. **Build SaaS Pricing Brief** \n Transforms structured JSON into an executive-ready markdown brief with:\n - Plan comparison table\n - Key differentiators\n - Observations and suggested next actions\n\n7. **Publish Assets** \n Creates a Google Doc in a predefined Drive folder and converts it to PDF for sharing.\n\n8. **Share in Slack** \n Uploads the PDF directly to a Slack channel (e.g. `#pricing-intel`) for instant visibility.\n\n## Requirements\n- Decodo node configured with a valid plan\n- OpenAI / LLM credentials for the Plan Extraction Agent\n- Google Drive API access\n- Slack workspace and upload permissions\n\n## Notes & best practices\n- Manual trigger avoids unnecessary scraping and rate-limit issues\n- Device emulation ensures accurate pricing capture\n- Structured JSON output enables future extensions (trend tracking, diffing, dashboards)\n- The workflow is modular and easy to adapt for other competitor intelligence use cases"
},
"typeVersion": 1
},
{
"id": "eb7a1b9f-7d66-46e2-9cd6-a9265818f8bb",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
3872,
2672
],
"parameters": {
"color": 7,
"width": 368,
"height": 464,
"content": "### 1. Trigger Workflow & Configure Inputs\nManual trigger keeps the scrape intentional \u2014 ideal when pricing updates are expected (launch days, quarter close, etc.).\nProvide the competitor URL, device preference, and report title. This metadata flows into the report & downstream destinations."
},
"typeVersion": 1
},
{
"id": "0dac3f4d-2d9a-4c01-8ac1-e4a1d46657c5",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
4288,
2672
],
"parameters": {
"color": 7,
"width": 416,
"height": 464,
"content": "### 2. Decodo Pricing Scraper & Normalize HTML\nRuns the official Decodo node to render the entire pricing page (JS + device emulation) so tier cards and popovers are captured.\nCustom code removes scripts/styles and leaves only readable text for the LLM to digest reliably."
},
"typeVersion": 1
},
{
"id": "33fb58d1-103b-4b38-9ca6-82e574cb5d11",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
4752,
2672
],
"parameters": {
"color": 7,
"width": 288,
"height": 592,
"content": "### 3. Plan Extraction Agent\nLLM + structured parser translates messy pricing copy into a predictable JSON schema (plan, price, features, CTA)."
},
"typeVersion": 1
},
{
"id": "392b9ca8-bf49-4f7e-a387-84ba43996f5a",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
5072,
2672
],
"parameters": {
"color": 7,
"width": 416,
"height": 448,
"content": "### 4. Build SaaS Pricing Brief\nTransforms plan JSON into an exec-ready markdown brief with KPIs, tier comparison table, and suggested next steps."
},
"typeVersion": 1
},
{
"id": "5e59323b-9262-4b42-9d14-d8a8bea98762",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
5520,
2672
],
"parameters": {
"color": 7,
"width": 656,
"height": 448,
"content": "### 5. Publish Assets & Share in Slack\nSet Drive folder \u2192 create Google Doc \u2192 convert to PDF. Keeps a doc + PDF version for stakeholders."
},
"typeVersion": 1
},
{
"id": "f3ae0ebf-3bdb-49d5-9187-e30d5ce1e0f4",
"name": "Decodo Pricing Scraper",
"type": "@decodo/n8n-nodes-decodo.decodo",
"position": [
4336,
2864
],
"parameters": {
"geo": "=",
"url": "={{ $json.url }}"
},
"credentials": {
"decodoApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "4fffd8b0-f3dc-4574-bf7d-ca93be22e62c",
"connections": {
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Plan Extraction Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Convert brief to PDF": {
"main": [
[
{
"node": "Share brief in Slack",
"type": "main",
"index": 0
}
]
]
},
"HTML Response Parser": {
"main": [
[
{
"node": "Plan Extraction Agent",
"type": "main",
"index": 0
}
]
]
},
"Plan Extraction Agent": {
"main": [
[
{
"node": "Build \ud83d\udcbc SaaS Pricing Brief",
"type": "main",
"index": 0
}
]
]
},
"Pricing Output Parser": {
"ai_outputParser": [
[
{
"node": "Plan Extraction Agent",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Decodo Pricing Scraper": {
"main": [
[
{
"node": "HTML Response Parser",
"type": "main",
"index": 0
}
]
]
},
"Create pricing brief doc": {
"main": [
[
{
"node": "Convert brief to PDF",
"type": "main",
"index": 0
}
]
]
},
"Build \ud83d\udcbc SaaS Pricing Brief": {
"main": [
[
{
"node": "Configure Google Drive Destination",
"type": "main",
"index": 0
}
]
]
},
"Configure Target Pricing Page": {
"main": [
[
{
"node": "Decodo Pricing Scraper",
"type": "main",
"index": 0
}
]
]
},
"Configure Google Drive Destination": {
"main": [
[
{
"node": "Create pricing brief doc",
"type": "main",
"index": 0
}
]
]
},
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Configure Target Pricing Page",
"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.
decodoApigoogleDriveOAuth2ApiopenAiApislackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Decodo is a powerful public data access platform offering managed web scraping APIs and proxy infrastructure to collect structured web data at scale. It handles proxies, anti-bot protection, JavaScript rendering, retries, and global IP rotation—so you can focus on data, not…
Source: https://n8n.io/workflows/7626/ — 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 workflow contains community nodes that are only compatible with the self-hosted version of n8n.
[](https://www.youtube.com/watch?v=9Kn583UJlqY) > This workflow demos how to use Decodo Scraper API to crawl any public web page (headless JS, device emulation: mobile/desktop/tablet), extract stru
🎯 Create viral TikToks, Shorts, Reels, podcasts, and ASMR videos in minutes — all on autopilot.
Generate AI viral videos with NanoBanana & VEO3, shared on socials via Blotato 2. Uses @blotato/n8n-nodes-blotato, googleSheets, lmChatOpenAi, toolThink. Event-driven trigger; 94 nodes.
The best content automation template in the market is now even better—with “deep research” on time-sensitive topics\! Unlike most n8n content automation templates that are mainly for “demo purposes,”