AutomationFlowsData & Sheets › Analyze Customer Review Sentiment Automatically with Google Sheets

Analyze Customer Review Sentiment Automatically with Google Sheets

ByDavid Olusola @dae221 on n8n.io

This workflow watches for new rows in a Google Sheet (e.g., where you manually log customer reviews) and uses a Code node to perform a simple sentiment analysis, then updates the same row with the detected sentiment.

Event trigger★★★★☆ complexity6 nodesGoogle SheetsGoogle Sheets Trigger
Data & Sheets Trigger: Event Nodes: 6 Complexity: ★★★★☆ Added:

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

This workflow follows the Google Sheets → Googlesheetstrigger 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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "46064753-85fe-4f8e-aba1-0e3ba9b994b6",
      "name": "Analyze Sentiment",
      "type": "n8n-nodes-base.code",
      "position": [
        272,
        48
      ],
      "parameters": {
        "jsCode": "const reviewText = $input.first().json['Review Text'];\nconst reviewId = $input.first().json['Review ID'];\n\nlet sentiment = 'Neutral';\nconst positiveKeywords = ['great', 'excellent', 'amazing', 'happy', 'love', 'satisfied', 'good', 'fantastic', 'awesome', 'recommend'];\nconst negativeKeywords = ['bad', 'poor', 'disappointed', 'problem', 'unhappy', 'frustrating', 'issue', 'terrible', 'worst'];\n\nconst lowerCaseReview = reviewText.toLowerCase();\n\nlet positiveCount = 0;\npositiveKeywords.forEach(keyword => {\n    if (lowerCaseReview.includes(keyword)) {\n        positiveCount++;\n    }\n});\n\nlet negativeCount = 0;\nnegativeKeywords.forEach(keyword => {\n    if (lowerCaseReview.includes(keyword)) {\n        negativeCount++;\n    }\n});\n\nif (positiveCount > negativeCount) {\n    sentiment = 'Positive';\n} else if (negativeCount > positiveCount) {\n    sentiment = 'Negative';\n} else if (positiveCount > 0 && negativeCount > 0) {\n    sentiment = 'Mixed'; // For cases with both positive and negative keywords\n}\n\nreturn [{ json: { sentiment: sentiment, reviewId: reviewId } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "c2830312-8cdc-446a-a0ea-cfecabca7e5e",
      "name": "Update Google Sheet with Sentiment",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        496,
        48
      ],
      "parameters": {
        "columns": {
          "value": {
            "Review ID": "={{ $json.reviewId }}",
            "row_number": 0
          },
          "schema": [
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Customer Name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Customer Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Review Text",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Review Text",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Sentiment",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Sentiment",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Review ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Review ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Review ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 789150459,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1SOxZwhOEI8XQNu-0wQ3TiWsf01aLEKu48IAgtbEt2CE/edit#gid=789150459",
          "cachedResultName": "customer_reviews_template"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1SOxZwhOEI8XQNu-0wQ3TiWsf01aLEKu48IAgtbEt2CE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1SOxZwhOEI8XQNu-0wQ3TiWsf01aLEKu48IAgtbEt2CE/edit?usp=drivesdk",
          "cachedResultName": "Customer Review "
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "40bedf02-1897-4b02-b2c6-00e24d3352ff",
      "name": "Google Sheets Trigger",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "position": [
        -224,
        48
      ],
      "parameters": {
        "event": "rowAdded",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 789150459,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1SOxZwhOEI8XQNu-0wQ3TiWsf01aLEKu48IAgtbEt2CE/edit#gid=789150459",
          "cachedResultName": "customer_reviews_template"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1SOxZwhOEI8XQNu-0wQ3TiWsf01aLEKu48IAgtbEt2CE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1SOxZwhOEI8XQNu-0wQ3TiWsf01aLEKu48IAgtbEt2CE/edit?usp=drivesdk",
          "cachedResultName": "Customer Review "
        }
      },
      "credentials": {
        "googleSheetsTriggerOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "41b7911b-7086-45a7-8b8d-dbf75b0351ec",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        -176
      ],
      "parameters": {
        "width": 320,
        "height": 400,
        "content": "## Customer Review Sentiment Analyzer (Google Sheets)\n**Author: David Olusola**\n\nThis workflow watches for new rows in a Google Sheet (e.g., where you manually log customer reviews) and uses a Code node to perform a simple sentiment analysis, then updates the same row with the detected sentiment.\n\nUse Case: Quickly gauge customer satisfaction, identify positive/negative trends, and prioritize follow-ups based on sentiment."
      },
      "typeVersion": 1
    },
    {
      "id": "31fc4a2f-03c4-4cff-a766-c4b22d614a59",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        672,
        -208
      ],
      "parameters": {
        "height": 512,
        "content": "## Setup Steps\n\nTo get this workflow up and running, follow these instructions:\n\nStep 1: Create Google Sheets Credentials in n8n\n\nIn your n8n instance, click on Credentials in the left sidebar.\n\nClick New Credential.\n\nSearch for and select \"Google Sheets OAuth2 API\" and follow the authentication steps with your Google account. Save it.\n\nMake note of the Credential Name (e.g., \"My Google Sheets Account\").\n\nStep 2: Make a copy  of the Google Sheet [Customer Review](https://docs.google.com/spreadsheets/d/1XmyKfySCUAgyTgnAU3p0bz22D_ofAPoTAUw2HuBezrM/edit?usp=sharing)"
      },
      "typeVersion": 1
    },
    {
      "id": "86cd2976-fe14-4238-a2a6-0400eb3f2cde",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        -192
      ],
      "parameters": {
        "height": 464,
        "content": "## Activate and Test the Workflow\n\n\nClick the \"Activate\" toggle button in the top right corner of the n8n workflow editor.\n\nGo to your Google Sheet and manually add a new row with a \"Review Text\" (e.g., \"This product is great, I love it!\"). Leave the \"Sentiment\" column empty.\n\nThe workflow should trigger automatically (it polls every minute by default), analyze the sentiment, and update the \"Sentiment\" column in your Google Sheet. You can also manually \"Execute Workflow\" to test immediately."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Analyze Sentiment": {
      "main": [
        [
          {
            "node": "Update Google Sheet with Sentiment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets Trigger": {
      "main": [
        [
          {
            "node": "Analyze Sentiment",
            "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 watches for new rows in a Google Sheet (e.g., where you manually log customer reviews) and uses a Code node to perform a simple sentiment analysis, then updates the same row with the detected sentiment.

Source: https://n8n.io/workflows/6468/ — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

This n8n workflow watches a Google Sheets appointments list for cancellations, then texts matching waitlist candidates via Twilio to claim the open slot within 20 minutes and, on confirmation, books t

Google Sheets Trigger, Google Sheets, Twilio +1
Data & Sheets

Stickynote Workflow. Uses googleTranslate, googleSheetsTrigger, googleDrive, httpRequest. Event-driven trigger; 22 nodes.

Google Translate, Google Sheets Trigger, Google Drive +2
Data & Sheets

Automate IT asset allocation for new hires with an intelligent, AI-powered workflow 🤖. This automation reads employee data from Google Sheets, determines role-based requirements, and intelligently ass

Google Sheets Trigger, Airtable, HTTP Request +2
Data & Sheets

This workflow contains community nodes that are only compatible with the self-hosted version of n8n.

Google Sheets Trigger, N8N Nodes Sinergiacrm, Google Sheets
Data & Sheets

This powerful no-code workflow automates plagiarism detection using Plagiarism Checker AI Powered. Users submit text through Google Sheets. The system checks for duplication using the API, sends a det

Google Sheets Trigger, HTTP Request, Email Send +1