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

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

Google Translate, Google Sheets Trigger, Google Drive +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
Data & Sheets

This n8n workflow automates outbound phone calls to new leads using VAPI, with built-in timezone detection to ensure you're only calling during business hours.

HTTP Request, Google Sheets Trigger, Google Sheets
Data & Sheets

Julia. Uses googleSheetsTrigger, googleSheets, httpRequest. Event-driven trigger; 16 nodes.

Google Sheets Trigger, Google Sheets, HTTP Request