AutomationFlowsAI & RAG › Rewrite Web Content with Exact Character Counts Using Gpt-4.1 and Google Sheets

Rewrite Web Content with Exact Character Counts Using Gpt-4.1 and Google Sheets

ByisaWOW @isawow on n8n.io

An AI-powered content rewriter that maintains exact character counts line-by-line while rewriting web pages for SEO. Fetches reference URL content, preserves layout-critical formatting, and logs detailed comparisons to Google Sheets—perfect for agencies rewriting competitor…

Event trigger★★★★☆ complexityAI-powered16 nodesForm TriggerHTTP RequestAgentOpenAI ChatOutput Parser StructuredGoogle Sheets
AI & RAG Trigger: Event Nodes: 16 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Agent → Form Trigger 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
{
  "nodes": [
    {
      "id": "ff0d97b0-f69e-4713-8459-ba1eab501847",
      "name": "Submit Content Rewriting Request",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "options": {},
        "formTitle": "Service Page Content Creation",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Client ID",
              "requiredField": true
            },
            {
              "fieldLabel": "Service Page Keyword"
            },
            {
              "fieldLabel": "Instruction",
              "requiredField": true
            },
            {
              "fieldLabel": "Reference Url"
            }
          ]
        },
        "formDescription": "As soon as you fill the form, then we can start it."
      },
      "typeVersion": 2.3
    },
    {
      "id": "790a5941-be98-4c85-bdbb-3bd08d221d94",
      "name": "Fetch Reference URL Content",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        208,
        0
      ],
      "parameters": {
        "url": "={{ $json[\"Reference Url\"] }}",
        "method": "POST",
        "options": {}
      },
      "typeVersion": 4.3
    },
    {
      "id": "83f109ab-b6ac-4d3a-8868-530bc76dd56c",
      "name": "Convert HTML to Markdown",
      "type": "n8n-nodes-base.markdown",
      "position": [
        400,
        0
      ],
      "parameters": {
        "html": "={{ $json.data }}",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "42924920-6968-4bf6-82c3-b31a0f5560d8",
      "name": "Rewrite Content with Exact Character Count",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        656,
        0
      ],
      "parameters": {
        "text": "={{ $json.data }}",
        "options": {
          "systemMessage": "=\ud83e\udde0 ULTRA-STRICT SEO Content Rewriter \u2013 EXACT Character Count Enforcer\n\nYou are a precision-focused SEO content rewriting assistant.\nYour ONLY job is to rewrite content while maintaining EXACT CHARACTER COUNT for every single line.\n\n\ud83d\udea8 CRITICAL RULE \u2013 READ THIS FIRST\n\nEVERY LINE MUST HAVE THE EXACT SAME CHARACTER COUNT AS THE ORIGINAL.\nIf original line has 15 characters \u2192 Your rewrite MUST have 15 characters\nIf original line has 47 characters \u2192 Your rewrite MUST have 47 characters\nIf original line has 200 characters \u2192 Your rewrite MUST have 200 characters\n\n\u274c NO EXCEPTIONS. NO APPROXIMATIONS. NO DEVIATIONS OF EVEN 1 CHARACTER.\nIf you cannot match exactly, DO NOT SUBMIT \u2014 retry the entire line until it does.\n\n\ud83d\udccb MANDATORY LINE-BY-LINE PROCESS\n\nFOR EACH LINE:\n\nREAD THE LINE\n\nCOUNT CHARACTERS (letters + spaces + punctuation)\n\nDECIDE: Rewrite, Keep, or Skip\n\nSimple form fields (Name, Email, Phone) \u2192 KEEP AS-IS\n\nGeneric labels \u2192 KEEP AS-IS\n\nURLs, footers, links \u2192 SKIP COMPLETELY\n\nMarketing content, headings, descriptions \u2192 REWRITE\n\n\u26a0\ufe0f IMPORTANT UPDATE:\nIf the line is a footer, you must SKIP IT ENTIRELY \u2014\nDo not rewrite, do not change, do not include in the output.\nJust ignore it completely.\n\n\ud83d\udd22 CHARACTER COUNTING RULES\n\nCount everything: letters, spaces, numbers, symbols\n\nSpaces are characters\n\nNumbers & punctuation count\n\nCase doesn\u2019t affect count\n\nLine breaks don\u2019t count\n\n\ud83c\udfaf WHAT TO REWRITE vs KEEP vs SKIP\n\n\u2705 KEEP AS-IS:\nSimple form labels (Name, Email*, Phone, Message, Website)\nGeneric system messages\nTechnical single words\n\n\ud83d\udeab SKIP COMPLETELY:\n\nALL URLs (https://, http://, www.)\n\nALL FOOTERS (copyright, legal links, disclaimers, etc.)\n\nNavigation URLs\n\nImage or file paths\n\nEncoded/tracking links\n\n\ud83d\udd04 MUST REWRITE:\nHeadings, marketing text, CTAs, service descriptions, menu items, etc.\n\n\u2705 CORRECT EXAMPLES\n\nExample 1 (KEEP):\nOriginal: Name \u2192 Output: Name \u2705\n\nExample 2 (REWRITE):\nOriginal: About Us (8 chars) \u2192 About Me (8 chars) \u2705\n\nExample 3 (SKIP - URL):\nOriginal: https://example.com \u2192 SKIPPED \u2705\n\nExample 4 (SKIP - FOOTER):\nOriginal: \u00a9 2024 Company Name. All rights reserved. \u2192 SKIPPED \u2705\n\n\ud83d\udd27 CHARACTER-MATCHING TECHNIQUES\n\nAdd characters (too short): add words, expand contractions\nRemove characters (too long): use shorter synonyms, contractions\nMaintain length: swap equal-length words\n\n\u26a0\ufe0f MANDATORY VERIFICATION CHECKLIST\n\n\u2705 Every rewritten line matches original character count\n\u2705 All simple labels kept exactly\n\u2705 All URLs skipped\n\u2705 All footers skipped (no rewrite or modification)\n\u2705 Markdown structure preserved\n\u2705 No explanations or notes in output\n\n\ud83d\udea8 FINAL WARNING\n\nIf even 1 line has mismatched characters \u2192 \u274c INVALID\nIf any URL or footer is included \u2192 \u274c INVALID\nIf footer is rewritten or modified \u2192 \u274c INVALID\n\nYou must retry until 100% of lines are perfect:\nExact character match, no URLs, no footer text in output.\n\n\ud83d\udca1 REMEMBER\n\nRead line \u2192 Check for URL/footer \u2192 If yes, SKIP\nCount characters \u2192 Decide: rewrite or keep\nIf rewrite: verify match exactly\nIf keep: copy as-is\nIf skip: exclude entirely\n\n\u2705 Smart decisions + Exact counts + No URLs + No footers = Perfect Output\n\nEvery single character counts.\nNever rewrite or modify footers \u2014 skip them completely."
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "a6e6090e-efaf-4287-a006-3c1cf4d5fc41",
      "name": "OpenAI GPT-4.1 Rewriting Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        656,
        192
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1",
          "cachedResultName": "gpt-4.1"
        },
        "options": {
          "timeout": 100000
        }
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "4fb016d3-a653-4cf9-a868-33648de2f39d",
      "name": "Compare Original vs Rewritten Content",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1056,
        0
      ],
      "parameters": {
        "text": "=Compare the following two pieces of content:\n\nORIGINAL INPUT:\n{{ $('Convert HTML to Markdown').item.json.data }}\n\nREWRITTEN OUTPUT:\n{{ $json.output }}\n\nProvide a detailed comparison analysis.",
        "options": {
          "systemMessage": "=You are a content comparison expert.\nCompare the ORIGINAL INPUT with the REWRITTEN OUTPUT and create a line-by-line comparison.\n\nRules:\n\nBreak down both texts into individual sentences or meaningful phrases.\n\nMatch each line from the original with its corresponding rewritten version.\n\nOutput ONLY a valid JSON object (no markdown, no explanations).\n\nEach comparison must be a separate object in the comparisons array.\n\nKeep each comparison concise (1\u20132 sentences max).\n\nMatch the intent and meaning, not just word-for-word.\n\nNote any added, removed, or skipped content (like URLs or footers).\n\nVerify that each rewritten line has exactly the same character count and word count as the original.\n\nIf the line was skipped intentionally (like a footer or URL), include a note such as \"ai_suggested_text\": \"[SKIPPED - Footer/URL]\".\n\nResponse format:\n{\n  \"comparisons\": [\n    {\n      \"old_text\": \"exact sentence from original\",\n      \"ai_suggested_text\": \"corresponding sentence from rewritten version\"\n    }\n  ]\n}\n\nIMPORTANT:\n\nOutput ONLY the JSON object \u2014 no markdown, no extra text.\n\nEach comparison must show one clear change or indicate if content was skipped.\n\nCharacter count and word count must both match for rewritten lines (except skipped lines)."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "4e4bf882-671b-4f7e-ad01-823aaf900872",
      "name": "OpenAI GPT-4.1 Comparison Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        992,
        272
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1",
          "cachedResultName": "gpt-4.1"
        },
        "options": {
          "timeout": 100000
        }
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "6d19ad50-61c8-4464-bbf1-88de45bb2f52",
      "name": "Parse Comparison to Structured Format",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1136,
        160
      ],
      "parameters": {
        "autoFix": true,
        "jsonSchemaExample": "{\n  \"comparisons\": [\n    {\n      \"old_text\": \"original text line here\",\n      \"ai_suggested_text\": \"rewritten text line here\",   \"Old_text_count\":\"Old_text_count\",    \"ai_suggested_text_Count\":\"ai_suggested_text_Count\"\n    }\n  ]\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "3a2aaddb-5759-4665-a674-bad52dd1782d",
      "name": "OpenAI GPT-4o-mini Parser Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1136,
        368
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "86944b96-8fc8-4836-ac14-965669c186d5",
      "name": "Split Comparison into Individual Rows",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1424,
        0
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "output.comparisons"
      },
      "typeVersion": 1
    },
    {
      "id": "2d36605c-22f3-4b14-9d49-ad06c245386f",
      "name": "Log Comparison to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1680,
        0
      ],
      "parameters": {
        "columns": {
          "value": {
            "Old Text": "={{ $json.old_text }}",
            "Old Text Length": "={{ $json.Old_text_count }}",
            "Ai Suggested Text": "={{ $json.ai_suggested_text }}",
            "Ai Suggested Text Length": "={{ $json.ai_suggested_text_Count }}"
          },
          "schema": [
            {
              "id": "Old Text",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Old Text",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Ai Suggested Text",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Ai Suggested Text",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Old Text Length",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Old Text Length",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Ai Suggested Text Length",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Ai Suggested Text Length",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1V4MjvK0yN2f7aBBqPG_O3vEisVOalRl2aeNldnS9SIU/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1V4MjvK0yN2f7aBBqPG_O3vEisVOalRl2aeNldnS9SIU",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1V4MjvK0yN2f7aBBqPG_O3vEisVOalRl2aeNldnS9SIU/edit?usp=drivesdk",
          "cachedResultName": "content_comparision"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "7c69a88f-5505-46b9-9b67-61c2d6449edf",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -448,
        -352
      ],
      "parameters": {
        "width": 416,
        "height": 880,
        "content": "## Character-Preserving SEO Content Rewriter\n\nThis workflow rewrites web content while maintaining EXACT\ncharacter counts line-by-line\u2014critical for preserving page\nlayout and design. Submit a reference URL, and the AI fetches\nthe content, converts it to Markdown, then rewrites marketing\ntext, headings, and CTAs while keeping form labels unchanged\nand skipping URLs/footers entirely. Every rewritten line must\nmatch the original's exact character count. A comparison agent\nthen analyzes the changes and logs them to Google Sheets for\nquality verification.\n\n## How it works\n1. Submit form with reference URL and rewriting instructions.\n2. Fetch the webpage HTML content via HTTP request.\n3. Convert HTML to clean Markdown format.\n4. AI rewrites content line-by-line with exact character matching.\n5. Comparison agent analyzes original vs rewritten text.\n6. Parse comparison into structured JSON format.\n7. Split comparison array into individual rows.\n8. Log all changes to Google Sheets with character counts.\n\n## Setup steps\n1. Connect Google Sheets OAuth credentials.\n2. Add OpenAI API keys (GPT-4.1 and GPT-4o-mini).\n3. Update Google Sheet URL in the append node.\n4. Share form URL to start rewriting content.\n5. Review results in Google Sheets comparison log."
      },
      "typeVersion": 1
    },
    {
      "id": "44078247-72f0-4524-959f-a49ec47f3026",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 192,
        "content": "## Content Fetching\n\nReceives rewriting request via form, fetches\nthe reference URL's HTML content, and converts\nit to clean Markdown for AI processing."
      },
      "typeVersion": 1
    },
    {
      "id": "8be4c5a5-d29a-44fd-91e3-8b4c8d60796d",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        592,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 352,
        "height": 192,
        "content": "## AI Content Rewriting\n\nRewrites content line-by-line maintaining EXACT\ncharacter count. Keeps form labels unchanged,\nskips URLs/footers, rewrites marketing content."
      },
      "typeVersion": 1
    },
    {
      "id": "f7ffda9a-13e8-446b-9b9a-a7cc29fcd3a9",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        976,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 368,
        "height": 192,
        "content": "## Comparison Analysis\n\nCompares original vs rewritten content line-by-line,\ncreates structured JSON comparison with character\ncounts, and parses into proper format."
      },
      "typeVersion": 1
    },
    {
      "id": "2eb15d8e-e23d-4210-8e7d-8c9139bb8817",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1424,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 352,
        "height": 192,
        "content": "##  Results Logging\n\nSplits comparison data into individual rows\nand logs each comparison to Google Sheets\nwith old/new text and character counts."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Convert HTML to Markdown": {
      "main": [
        [
          {
            "node": "Rewrite Content with Exact Character Count",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Reference URL Content": {
      "main": [
        [
          {
            "node": "Convert HTML to Markdown",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI GPT-4.1 Rewriting Model": {
      "ai_languageModel": [
        [
          {
            "node": "Rewrite Content with Exact Character Count",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI GPT-4.1 Comparison Model": {
      "ai_languageModel": [
        [
          {
            "node": "Compare Original vs Rewritten Content",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI GPT-4o-mini Parser Model": {
      "ai_languageModel": [
        [
          {
            "node": "Parse Comparison to Structured Format",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Submit Content Rewriting Request": {
      "main": [
        [
          {
            "node": "Fetch Reference URL Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compare Original vs Rewritten Content": {
      "main": [
        [
          {
            "node": "Split Comparison into Individual Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Comparison to Structured Format": {
      "ai_outputParser": [
        [
          {
            "node": "Compare Original vs Rewritten Content",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Split Comparison into Individual Rows": {
      "main": [
        [
          {
            "node": "Log Comparison to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rewrite Content with Exact Character Count": {
      "main": [
        [
          {
            "node": "Compare Original vs Rewritten Content",
            "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

An AI-powered content rewriter that maintains exact character counts line-by-line while rewriting web pages for SEO. Fetches reference URL content, preserves layout-critical formatting, and logs detailed comparisons to Google Sheets—perfect for agencies rewriting competitor…

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

🎯 Create viral TikToks, Shorts, Reels, podcasts, and ASMR videos in minutes — all on autopilot.

OpenAI, HTTP Request, Form Trigger +7
AI & RAG

Digistars - Scrape & Crawl. Uses httpRequest, n8n-nodes-firecrawl-scraper, googleSheets, lmChatOpenAi. Event-driven trigger; 63 nodes.

HTTP Request, N8N Nodes Firecrawl Scraper, Google Sheets +5
AI & RAG

🧠 Automate end-to-end SEO blog creation and WordPress publishing using a GPT-5 multi-agent workflow with real-time research, metadata generation, and optional featured images.

Output Parser Structured, HTTP Request, OpenAI +10
AI & RAG

The workflow runs every hour with a randomized delay of 5–20 minutes to help distribute load. It records the exact date and time a lead is emailed so you can track outreach. Follow-ups are automatical

Google Sheets, Agent, OpenAI Chat +5
AI & RAG

Transform your manual hiring process into an intelligent evaluation system that saves 15-20 minutes per candidate! This workflow automates the entire candidate assessment pipeline - from CSV/XLSX uplo

Form Trigger, Google Sheets, Google Drive +8