AutomationFlowsWeb Scraping › Generate Employee Performance Review Summaries with Gpt-4, Gmail and Sheets

Generate Employee Performance Review Summaries with Gpt-4, Gmail and Sheets

ByJitesh Dugar @jiteshdugar on n8n.io

Simplify employee performance reviews with AI-powered automation. This workflow transforms raw feedback and evaluation inputs into clear, structured, and professional performance review summaries — saving hours of manual writing while ensuring consistency and fairness.

Webhook trigger★★★★☆ complexityAI-powered16 nodesOpenAIGmailHTTP RequestGoogle SheetsSlackN8N Nodes Htmlcsstoimage
Web Scraping Trigger: Webhook Nodes: 16 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Gmail → Google Sheets 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
{
  "id": "",
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "AI Performance Review SummaryGenerator",
  "tags": [],
  "nodes": [
    {
      "id": "f5679924-1ba1-49b2-b98a-a48ec4f83770",
      "name": "Process Employee Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1152,
        240
      ],
      "parameters": {
        "jsCode": "// Extract data from webhook body\nconst webhookData = $input.item.json.body;\n\n// Calculate average score from all performance metrics\nconst scores = webhookData.scores;\nconst averageScore = (\n  scores.technical + \n  scores.communication + \n  scores.leadership + \n  scores.productivity + \n  scores.teamwork\n) / 5;\n\n// Determine performance level based on overall rating\nconst getPerformanceLevel = (rating) => {\n  if (rating >= 4.5) return 'Outstanding';\n  if (rating >= 4.0) return 'Exceeds Expectations';\n  if (rating >= 3.0) return 'Meets Expectations';\n  return 'Needs Improvement';\n};\n\n// Determine performance color for visual elements\nconst getPerformanceColor = (rating) => {\n  if (rating >= 4.5) return '#4CAF50'; // Green\n  if (rating >= 4.0) return '#2196F3'; // Blue\n  if (rating >= 3.0) return '#FF9800'; // Orange\n  return '#F44336'; // Red\n};\n\n// Format date for review period\nconst currentDate = new Date().toLocaleDateString('en-US', {\n  year: 'numeric',\n  month: 'long',\n  day: 'numeric'\n});\n\n// Build comprehensive output object\nconst output = {\n  // Employee Information\n  employeeId: webhookData.employeeId,\n  employeeName: webhookData.employeeName,\n  employeeEmail: webhookData.employeeEmail,\n  \n  // Manager Information\n  managerName: webhookData.managerName,\n  managerEmail: webhookData.managerEmail,\n  \n  // Department & Period\n  department: webhookData.department,\n  reviewPeriod: webhookData.reviewPeriod,\n  reviewDate: currentDate,\n  \n  // Performance Scores (Individual)\n  technicalScore: scores.technical,\n  communicationScore: scores.communication,\n  leadershipScore: scores.leadership,\n  productivityScore: scores.productivity,\n  teamworkScore: scores.teamwork,\n  \n  // Calculated Metrics\n  overallRating: webhookData.overallRating,\n  averageScore: parseFloat(averageScore.toFixed(2)),\n  performanceLevel: getPerformanceLevel(webhookData.overallRating),\n  performanceColor: getPerformanceColor(webhookData.overallRating),\n  \n  // Percentage calculations for visual bars\n  technicalPercent: (scores.technical / 5) * 100,\n  communicationPercent: (scores.communication / 5) * 100,\n  leadershipPercent: (scores.leadership / 5) * 100,\n  productivityPercent: (scores.productivity / 5) * 100,\n  teamworkPercent: (scores.teamwork / 5) * 100,\n  \n  // Feedback Details\n  strengthsFeedback: webhookData.feedback.strengths,\n  improvementsFeedback: webhookData.feedback.improvements,\n  managerComments: webhookData.feedback.managerComments,\n  \n  // Flags for conditional logic\n  isLowPerformer: webhookData.overallRating < 3.0,\n  isHighPerformer: webhookData.overallRating >= 4.5,\n  requiresManagerAlert: webhookData.overallRating < 3.0,\n  \n  // Additional metadata\n  scoresObject: scores, // Keep original scores object for reference\n  feedbackObject: webhookData.feedback, // Keep original feedback object\n  \n  // Generate unique review ID\n  reviewId: `REV-${webhookData.employeeId}-${Date.now()}`,\n  \n  // Timestamp\n  processedAt: new Date().toISOString()\n};\n\n// Return the processed data\nreturn { json: output };"
      },
      "typeVersion": 2
    },
    {
      "id": "76459fa7-3cba-4f65-9948-f022768952c0",
      "name": "AI Summary Generator",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1408,
        240
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4",
          "cachedResultName": "GPT-4"
        },
        "options": {
          "temperature": 0.7
        },
        "responses": {
          "values": [
            {
              "role": "system",
              "content": "=You are an expert HR professional specializing in performance reviews. Create concise, professional, and encouraging summaries that highlight achievements while providing constructive developmental guidance. Your tone should be supportive, specific, and actionable. Always format your response as valid JSON."
            },
            {
              "content": "=Create a comprehensive performance review summary for the following employee:\n\nEMPLOYEE INFORMATION:\n- Name: {{ $json.employeeName }}\n- Department: {{ $json.department }}\n- Review Period: {{ $json.reviewPeriod }}\n- Overall Rating: {{ $json.overallRating }}/5.0 ({{ $json.performanceLevel }})\n\nPERFORMANCE SCORES:\n- Technical Skills: {{ $json.technicalScore }}/5.0\n- Communication: {{ $json.communicationScore }}/5.0\n- Leadership: {{ $json.leadershipScore }}/5.0\n- Productivity: {{ $json.productivityScore }}/5.0\n- Teamwork: {{ $json.teamworkScore }}/5.0\n- Average Score: {{ $json.averageScore }}/5.0\n\nMANAGER'S FEEDBACK:\nStrengths: {{ $json.strengthsFeedback }}\nAreas for Improvement: {{ $json.improvementsFeedback }}\nAdditional Comments: {{ $json.managerComments }}\n\nINSTRUCTIONS:\nGenerate a performance review summary with the following structure. Return ONLY valid JSON with no markdown formatting, no code blocks, and no additional text:\n\n{\n  \"executiveSummary\": \"A compelling 2-3 sentence overview that captures the employee's overall performance, key impact, and standing within the team. Be specific and reference actual scores.\",\n  \"keyStrengths\": [\n    \"First major strength with specific example or metric\",\n    \"Second major strength with specific example or metric\",\n    \"Third major strength with specific example or metric\"\n  ],\n  \"developmentAreas\": [\n    \"First development opportunity phrased constructively with actionable steps\",\n    \"Second development opportunity phrased constructively with actionable steps\"\n  ],\n  \"closingStatement\": \"An inspiring, forward-looking statement that motivates the employee and acknowledges their value to the organization. Should be encouraging and personalized.\"\n}\n\nIMPORTANT: \n- Return ONLY the JSON object\n- No markdown code blocks (no ```json or ```)\n- No additional text before or after the JSON\n- Ensure all strings are properly escaped\n- Be specific and reference actual performance metrics\n- Keep a professional yet warm tone"
            }
          ]
        },
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "2b2381b7-6b12-4245-bbb7-557c7f5c3f64",
      "name": "Receive Review Data",
      "type": "n8n-nodes-base.webhook",
      "position": [
        912,
        240
      ],
      "parameters": {
        "path": "performance-review",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "4b00cbde-7e41-456a-ae89-107a020a441a",
      "name": "Parse AI Response",
      "type": "n8n-nodes-base.code",
      "position": [
        1744,
        240
      ],
      "parameters": {
        "jsCode": "// Get the OpenAI response from the new output structure\nconst openaiOutput = $input.item.json.output[0].content[0].text;\n\n// Remove markdown code blocks if present\nlet cleanedResponse = openaiOutput\n  .replace(/```json\\s*/g, '')\n  .replace(/```\\s*/g, '')\n  .trim();\n\n// Parse the JSON\nlet aiSummary;\ntry {\n  aiSummary = JSON.parse(cleanedResponse);\n} catch (error) {\n  // If parsing fails, try to extract JSON from text\n  const jsonMatch = cleanedResponse.match(/\\{[\\s\\S]*\\}/);\n  if (jsonMatch) {\n    aiSummary = JSON.parse(jsonMatch[0]);\n  } else {\n    throw new Error('Could not parse AI response: ' + error.message);\n  }\n}\n\n// Get previous node data (from the Process Employee Data node)\nconst previousData = $('Process Employee Data').item.json;\n\n// Merge everything together\nconst output = {\n  ...previousData, // All employee data from Code node\n  \n  // AI-generated content\n  executiveSummary: aiSummary.executiveSummary,\n  keyStrengths: aiSummary.keyStrengths,\n  developmentAreas: aiSummary.developmentAreas,\n  closingStatement: aiSummary.closingStatement,\n  \n  // Keep original AI response for reference\n  aiResponseRaw: openaiOutput,\n  \n  // Format strengths and development areas as HTML lists for later use\n  strengthsHTML: aiSummary.keyStrengths\n    .map(strength => `<li>${strength}</li>`)\n    .join(''),\n  developmentHTML: aiSummary.developmentAreas\n    .map(area => `<li>${area}</li>`)\n    .join('')\n};\n\nreturn { json: output };\n"
      },
      "typeVersion": 2
    },
    {
      "id": "4fe253db-456b-403d-b9f7-cf017587cc7e",
      "name": "Generate Review Card HTML",
      "type": "n8n-nodes-base.code",
      "position": [
        2000,
        240
      ],
      "parameters": {
        "jsCode": "// Get all the data\nconst data = $input.item.json;\n\n// Generate the complete HTML document\nconst html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Performance Review - ${data.employeeName}</title>\n    <style>\n        * {\n            margin: 0;\n            padding: 0;\n            box-sizing: border-box;\n        }\n        \n        body {\n            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n            padding: 40px;\n            min-height: 100vh;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n        }\n        \n        .review-card {\n            max-width: 900px;\n            width: 100%;\n            background: white;\n            border-radius: 20px;\n            box-shadow: 0 20px 60px rgba(0,0,0,0.3);\n            overflow: hidden;\n        }\n        \n        .header {\n            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n            color: white;\n            padding: 40px;\n            text-align: center;\n        }\n        \n        .header h1 {\n            font-size: 36px;\n            margin-bottom: 10px;\n            font-weight: 700;\n            letter-spacing: -0.5px;\n        }\n        \n        .header .subtitle {\n            font-size: 18px;\n            opacity: 0.95;\n            font-weight: 300;\n        }\n        \n        .content {\n            padding: 40px;\n        }\n        \n        .employee-info {\n            display: grid;\n            grid-template-columns: repeat(3, 1fr);\n            gap: 20px;\n            margin-bottom: 35px;\n            padding-bottom: 25px;\n            border-bottom: 2px solid #f0f0f0;\n        }\n        \n        .info-item {\n            text-align: center;\n        }\n        \n        .info-label {\n            font-size: 11px;\n            color: #999;\n            text-transform: uppercase;\n            letter-spacing: 1.2px;\n            margin-bottom: 8px;\n            font-weight: 600;\n        }\n        \n        .info-value {\n            font-size: 18px;\n            font-weight: 600;\n            color: #333;\n        }\n        \n        .overall-rating {\n            text-align: center;\n            margin-bottom: 35px;\n        }\n        \n        .rating-circle {\n            width: 150px;\n            height: 150px;\n            border-radius: 50%;\n            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            justify-content: center;\n            margin: 0 auto 15px;\n            box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);\n            position: relative;\n        }\n        \n        .rating-circle::before {\n            content: '';\n            position: absolute;\n            width: 130px;\n            height: 130px;\n            border-radius: 50%;\n            background: white;\n            opacity: 0.1;\n        }\n        \n        .rating-score {\n            font-size: 52px;\n            font-weight: 700;\n            color: white;\n            position: relative;\n            z-index: 1;\n        }\n        \n        .rating-max {\n            font-size: 20px;\n            color: rgba(255,255,255,0.85);\n            position: relative;\n            z-index: 1;\n        }\n        \n        .rating-label {\n            font-size: 22px;\n            font-weight: 600;\n            color: ${data.performanceColor};\n            margin-bottom: 5px;\n        }\n        \n        .rating-sublabel {\n            font-size: 14px;\n            color: #888;\n        }\n        \n        .scores-grid {\n            display: grid;\n            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n            gap: 20px;\n            margin-bottom: 35px;\n        }\n        \n        .score-item {\n            background: #f8f9fa;\n            padding: 22px;\n            border-radius: 12px;\n            border-left: 4px solid #667eea;\n            transition: transform 0.2s, box-shadow 0.2s;\n        }\n        \n        .score-item:hover {\n            transform: translateY(-2px);\n            box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n        }\n        \n        .score-name {\n            font-size: 13px;\n            color: #666;\n            margin-bottom: 10px;\n            font-weight: 600;\n            text-transform: uppercase;\n            letter-spacing: 0.5px;\n        }\n        \n        .score-bar-container {\n            background: #e0e0e0;\n            height: 10px;\n            border-radius: 5px;\n            overflow: hidden;\n            margin-bottom: 10px;\n        }\n        \n        .score-bar {\n            height: 100%;\n            background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);\n            border-radius: 5px;\n            transition: width 0.5s ease;\n        }\n        \n        .score-value {\n            font-size: 20px;\n            font-weight: 700;\n            color: #333;\n        }\n        \n        .section {\n            margin-bottom: 35px;\n        }\n        \n        .section-title {\n            font-size: 20px;\n            font-weight: 700;\n            color: #333;\n            margin-bottom: 18px;\n            display: flex;\n            align-items: center;\n        }\n        \n        .section-title::before {\n            content: '';\n            width: 5px;\n            height: 26px;\n            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n            margin-right: 12px;\n            border-radius: 3px;\n        }\n        \n        .ai-summary {\n            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);\n            padding: 28px;\n            border-radius: 14px;\n            border-left: 5px solid #667eea;\n            line-height: 1.9;\n            color: #444;\n            font-size: 15px;\n            box-shadow: 0 2px 8px rgba(0,0,0,0.05);\n        }\n        \n        .strengths-list, .development-list {\n            list-style: none;\n            padding: 0;\n            margin: 0;\n        }\n        \n        .strengths-list li, .development-list li {\n            padding: 18px 24px;\n            margin-bottom: 14px;\n            background: #f8f9fa;\n            border-radius: 12px;\n            border-left: 5px solid #667eea;\n            line-height: 1.7;\n            font-size: 14px;\n            color: #555;\n            box-shadow: 0 2px 6px rgba(0,0,0,0.04);\n        }\n        \n        .development-list li {\n            border-left-color: #ffa726;\n            background: #fff8f0;\n        }\n        \n        .closing-statement {\n            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n            color: white;\n            padding: 32px;\n            border-radius: 14px;\n            text-align: center;\n            font-size: 16px;\n            line-height: 1.9;\n            font-style: italic;\n            box-shadow: 0 8px 20px rgba(102, 126, 234, 0.35);\n        }\n        \n        .footer {\n            text-align: center;\n            padding: 28px;\n            color: #888;\n            font-size: 12px;\n            border-top: 2px solid #f0f0f0;\n            background: #fafafa;\n            line-height: 1.6;\n        }\n        \n        .footer strong {\n            color: #666;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"review-card\">\n        <div class=\"header\">\n            <h1>Performance Review</h1>\n            <div class=\"subtitle\">${data.reviewPeriod}</div>\n        </div>\n        \n        <div class=\"content\">\n            <div class=\"employee-info\">\n                <div class=\"info-item\">\n                    <div class=\"info-label\">Employee</div>\n                    <div class=\"info-value\">${data.employeeName}</div>\n                </div>\n                <div class=\"info-item\">\n                    <div class=\"info-label\">Department</div>\n                    <div class=\"info-value\">${data.department}</div>\n                </div>\n                <div class=\"info-item\">\n                    <div class=\"info-label\">Reviewer</div>\n                    <div class=\"info-value\">${data.managerName}</div>\n                </div>\n            </div>\n            \n            <div class=\"overall-rating\">\n                <div class=\"rating-circle\">\n                    <div class=\"rating-score\">${data.overallRating}</div>\n                    <div class=\"rating-max\">/5.0</div>\n                </div>\n                <div class=\"rating-label\">${data.performanceLevel}</div>\n                <div class=\"rating-sublabel\">Overall Performance Rating</div>\n            </div>\n            \n            <div class=\"section\">\n                <div class=\"section-title\">Performance Metrics</div>\n                <div class=\"scores-grid\">\n                    <div class=\"score-item\">\n                        <div class=\"score-name\">Technical Skills</div>\n                        <div class=\"score-bar-container\">\n                            <div class=\"score-bar\" style=\"width: ${data.technicalPercent}%\"></div>\n                        </div>\n                        <div class=\"score-value\">${data.technicalScore}/5.0</div>\n                    </div>\n                    <div class=\"score-item\">\n                        <div class=\"score-name\">Communication</div>\n                        <div class=\"score-bar-container\">\n                            <div class=\"score-bar\" style=\"width: ${data.communicationPercent}%\"></div>\n                        </div>\n                        <div class=\"score-value\">${data.communicationScore}/5.0</div>\n                    </div>\n                    <div class=\"score-item\">\n                        <div class=\"score-name\">Leadership</div>\n                        <div class=\"score-bar-container\">\n                            <div class=\"score-bar\" style=\"width: ${data.leadershipPercent}%\"></div>\n                        </div>\n                        <div class=\"score-value\">${data.leadershipScore}/5.0</div>\n                    </div>\n                    <div class=\"score-item\">\n                        <div class=\"score-name\">Productivity</div>\n                        <div class=\"score-bar-container\">\n                            <div class=\"score-bar\" style=\"width: ${data.productivityPercent}%\"></div>\n                        </div>\n                        <div class=\"score-value\">${data.productivityScore}/5.0</div>\n                    </div>\n                    <div class=\"score-item\">\n                        <div class=\"score-name\">Teamwork</div>\n                        <div class=\"score-bar-container\">\n                            <div class=\"score-bar\" style=\"width: ${Math.round(data.teamworkPercent)}%\"></div>\n                        </div>\n                        <div class=\"score-value\">${data.teamworkScore}/5.0</div>\n                    </div>\n                </div>\n            </div>\n            \n            <div class=\"section\">\n                <div class=\"section-title\">AI-Generated Executive Summary</div>\n                <div class=\"ai-summary\">\n                    ${data.executiveSummary}\n                </div>\n            </div>\n            \n            <div class=\"section\">\n                <div class=\"section-title\">Key Strengths</div>\n                <ul class=\"strengths-list\">\n                    ${data.strengthsHTML}\n                </ul>\n            </div>\n            \n            <div class=\"section\">\n                <div class=\"section-title\">Development Opportunities</div>\n                <ul class=\"development-list\">\n                    ${data.developmentHTML}\n                </ul>\n            </div>\n            \n            <div class=\"section\">\n                <div class=\"closing-statement\">\n                    ${data.closingStatement}\n                </div>\n            </div>\n        </div>\n        \n        <div class=\"footer\">\n            <strong>Performance Review</strong> \u2022 ${data.reviewPeriod} \u2022 Review ID: ${data.reviewId}<br>\n            Generated on ${data.reviewDate} \u2022 Confidential Document\n        </div>\n    </div>\n</body>\n</html>`;\n\n// Return all data plus the HTML\nreturn {\n  json: {\n    ...data,\n    html: html\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "56077bfe-f3d6-430a-8a2c-931039994e0c",
      "name": "Send Review to Employee",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2528,
        240
      ],
      "parameters": {
        "sendTo": "={{ $('Parse AI Response').item.json.employeeEmail }}",
        "message": "=<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <style>\n        body { \n            font-family: 'Segoe UI', Arial, sans-serif; \n            line-height: 1.6; \n            color: #333; \n            margin: 0;\n            padding: 0;\n            background: #f5f5f5;\n        }\n        .email-container { \n            max-width: 600px; \n            margin: 20px auto; \n            background: #ffffff;\n            border-radius: 8px;\n            overflow: hidden;\n            box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n        }\n        .email-header { \n            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n            color: white; \n            padding: 40px 30px; \n            text-align: center; \n        }\n        .email-header h1 { \n            font-size: 28px; \n            margin: 0 0 10px 0; \n            font-weight: 700; \n        }\n        .email-header p { \n            font-size: 16px; \n            margin: 0; \n            opacity: 0.95; \n        }\n        .email-content { \n            padding: 40px 30px; \n        }\n        .greeting { \n            font-size: 16px; \n            margin-bottom: 20px; \n        }\n        .rating-box {\n            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);\n            padding: 30px;\n            border-radius: 12px;\n            text-align: center;\n            margin: 25px 0;\n            border-left: 5px solid #667eea;\n            box-shadow: 0 2px 8px rgba(0,0,0,0.05);\n        }\n        .rating-box-label {\n            font-size: 12px;\n            color: #888;\n            text-transform: uppercase;\n            letter-spacing: 1px;\n            margin-bottom: 10px;\n            font-weight: 600;\n        }\n        .rating-score {\n            font-size: 56px;\n            font-weight: 700;\n            color: #667eea;\n            margin: 10px 0;\n            line-height: 1;\n        }\n        .rating-label {\n            font-size: 20px;\n            color: #555;\n            font-weight: 600;\n            margin-top: 5px;\n        }\n        .highlights {\n            background: #f8f9fa;\n            padding: 25px;\n            border-radius: 12px;\n            margin: 25px 0;\n            border-left: 4px solid #667eea;\n        }\n        .highlights h3 {\n            color: #667eea;\n            margin: 0 0 15px 0;\n            font-size: 18px;\n            font-weight: 600;\n        }\n        .highlights p {\n            margin: 0;\n            line-height: 1.8;\n            color: #555;\n        }\n        .highlights ul {\n            margin: 15px 0 0 0;\n            padding-left: 20px;\n        }\n        .highlights li {\n            margin-bottom: 10px;\n            line-height: 1.6;\n            color: #555;\n        }\n        .info-box {\n            background: #fff8f0;\n            padding: 20px;\n            border-radius: 10px;\n            border-left: 4px solid #ffa726;\n            margin: 25px 0;\n        }\n        .info-box h4 {\n            color: #ff6f00;\n            margin: 0 0 10px 0;\n            font-size: 16px;\n        }\n        .info-box ul {\n            margin: 10px 0 0 0;\n            padding-left: 20px;\n        }\n        .info-box li {\n            margin-bottom: 8px;\n            line-height: 1.6;\n            color: #666;\n        }\n        .cta-button { \n            display: inline-block; \n            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n            color: white !important; \n            padding: 15px 35px; \n            text-decoration: none; \n            border-radius: 8px; \n            margin: 25px 0; \n            font-weight: 600;\n            font-size: 16px;\n            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);\n            transition: all 0.3s ease;\n        }\n        .attachment-notice {\n            background: #e3f2fd;\n            padding: 20px;\n            border-radius: 10px;\n            border-left: 4px solid #2196f3;\n            margin: 25px 0;\n            display: flex;\n            align-items: center;\n        }\n        .attachment-icon {\n            font-size: 32px;\n            margin-right: 15px;\n        }\n        .signature {\n            margin-top: 35px;\n            padding-top: 25px;\n            border-top: 2px solid #e0e0e0;\n        }\n        .email-footer { \n            text-align: center; \n            padding: 25px 30px; \n            color: #888; \n            font-size: 12px; \n            border-top: 2px solid #efefef; \n            background: #fafafa;\n            line-height: 1.6;\n        }\n        .email-footer strong {\n            color: #666;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"email-container\">\n        <div class=\"email-header\">\n            <h1>\ud83c\udfaf Performance Review Complete</h1>\n            <p>{{ $('Parse AI Response').item.json.reviewPeriod }}</p>\n        </div>\n        \n        <div class=\"email-content\">\n            <div class=\"greeting\">\n                <p>Dear <strong>{{ $('Parse AI Response').item.json.employeeName }}</strong>,</p>\n            </div>\n            \n            <p>Your performance review for <strong>{{ $('Parse AI Response').item.json.reviewPeriod }}</strong> has been completed by {{ $('Parse AI Response').item.json.managerName }}. We're pleased to share your comprehensive evaluation and feedback.</p>\n            \n            <div class=\"rating-box\">\n                <div class=\"rating-box-label\">Your Overall Performance Rating</div>\n                <div class=\"rating-score\">{{ $('Parse AI Response').item.json.overallRating }}/5.0</div>\n                <div class=\"rating-label\">{{ $('Parse AI Response').item.json.performanceLevel }}</div>\n            </div>\n            \n            <div class=\"highlights\">\n                <h3>\ud83d\udcca Executive Summary</h3>\n                <p>{{ $('Parse AI Response').item.json.executiveSummary }}</p>\n            </div>\n            \n            <div class=\"highlights\">\n                <h3>\u2728 Performance Highlights</h3>\n                <ul>\n                    <li><strong>Technical Skills:</strong> {{ $('Parse AI Response').item.json.technicalScore }}/5.0</li>\n                    <li><strong>Productivity:</strong> {{ $('Parse AI Response').item.json.productivityScore }}/5.0</li>\n                    <li><strong>Communication:</strong> {{ $('Parse AI Response').item.json.communicationScore }}/5.0</li>\n                    <li><strong>Teamwork:</strong> {{ $('Parse AI Response').item.json.teamworkScore }}/5.0</li>\n                    <li><strong>Leadership:</strong> {{ $('Parse AI Response').item.json.leadershipScore }}/5.0</li>\n                </ul>\n            </div>\n            \n            <div class=\"attachment-notice\">\n                <div class=\"attachment-icon\">\ud83d\udcce</div>\n                <div>\n                    <strong style=\"display: block; margin-bottom: 5px;\">Detailed Review Card Attached</strong>\n                    Your complete performance review card is attached as a high-quality image. It includes detailed metrics, AI-generated insights, key strengths, and personalized development recommendations.\n                </div>\n            </div>\n            \n            <div class=\"info-box\">\n                <h4>\ud83d\udcc5 Next Steps</h4>\n                <p>We encourage you to schedule a follow-up meeting with {{ $('Parse AI Response').item.json.managerName }} to discuss:</p>\n                <ul>\n                    <li>Your career development goals for the upcoming quarter</li>\n                    <li>Training and professional growth opportunities</li>\n                    <li>Questions or clarifications about your review</li>\n                    <li>Resources and support to help you succeed</li>\n                </ul>\n            </div>\n            \n            <center>\n                <a href=\"#\" class=\"cta-button\">\ud83d\udcc5 Schedule Your 1-on-1 Meeting</a>\n            </center>\n            \n            <div class=\"signature\">\n                <p>Thank you for your continued dedication and valuable contributions to the {{ $('Parse AI Response').item.json.department }} team. We appreciate your hard work and commitment to excellence.</p>\n                \n                <p style=\"margin-top: 20px;\"><strong>Best regards,</strong><br>\n                Human Resources Department<br>\n                {{ $('Parse AI Response').item.json.department }} Division</p>\n            </div>\n        </div>\n        \n        <div class=\"email-footer\">\n            <strong>Confidential Performance Review</strong><br>\n            Review ID: {{ $('Parse AI Response').item.json.reviewId }}<br>\n            Generated on {{ $('Parse AI Response').item.json.reviewDate }}<br>\n            <br>\n            <em>This document contains confidential information. Please do not share without authorization.</em>\n        </div>\n    </div>\n</body>\n</html>",
        "options": {
          "attachmentsUi": {
            "attachmentsBinary": [
              {
                "property": "=data"
              }
            ]
          }
        },
        "subject": "=Your {{ $('Parse AI Response').item.json.reviewPeriod }} Performance Review - {{ $('Parse AI Response').item.json.performanceLevel }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "97f6e05e-8ec9-44d8-b874-13810b22343f",
      "name": "Download Image",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2368,
        240
      ],
      "parameters": {
        "url": "={{ $json.image_url }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "774ae079-daec-45e7-bef7-5291c3a85644",
      "name": "Log to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2768,
        240
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $('Parse AI Response').item.json.reviewDate }}",
            "Image URL": "={{ $('Convert HTML to Image').item.json.image_url }}",
            "Review ID": "={{ $('Parse AI Response').item.json.reviewId }}",
            "Department": "={{ $('Parse AI Response').item.json.department }}",
            "Email Sent": "Yes",
            "Employee ID": "={{ $('Parse AI Response').item.json.employeeId }}",
            "Manager Name": "={{ $('Parse AI Response').item.json.managerName }}",
            "Average Score": "={{ $('Parse AI Response').item.json.averageScore }}",
            "Employee Name": "={{ $('Parse AI Response').item.json.employeeName }}",
            "Review Period": "={{ $('Parse AI Response').item.json.reviewPeriod }}",
            "Employee Email": "={{ $('Parse AI Response').item.json.employeeEmail }}",
            "Overall Rating": "={{ $('Parse AI Response').item.json.overallRating }}",
            "Teamwork Score": "={{ $('Parse AI Response').item.json.teamworkScore }}",
            "Technical Score": "={{ $('Parse AI Response').item.json.technicalScore }}",
            "Leadership Score": "={{ $('Parse AI Response').item.json.leadershipScore }}",
            "Executive Summary": "={{ $('Parse AI Response').item.json.executiveSummary }}",
            "Performance Level": "={{ $('Parse AI Response').item.json.performanceLevel }}",
            "Productivity Score": "={{ $('Parse AI Response').item.json.productivityScore }}",
            "Communication Score": "={{ $('Parse AI Response').item.json.communicationScore }}",
            "Low Performer Alert": "={{ $('Parse AI Response').item.json.isLowPerformer ? 'Yes' : 'No' }}"
          },
          "schema": [
            {
              "id": "Review ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Review ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Employee ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Employee ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Employee Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Employee Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Employee Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Employee Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Department",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Department",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Manager Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Manager Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Review Period",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Review Period",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Overall Rating",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Overall Rating",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Performance Level",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Performance Level",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Technical Score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Technical Score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Communication Score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Communication Score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Leadership Score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Leadership Score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Productivity Score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Productivity Score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Teamwork Score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Teamwork Score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Average Score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Average Score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Image URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Image URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email Sent",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email Sent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Low Performer Alert",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Low Performer Alert",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Executive Summary",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Executive Summary",
              "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/YOUR_DOCUMENT_ID/edit#gid=0",
          "cachedResultName": "YOUR_SHEET_NAME"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_DOCUMENT_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_DOCUMENT_ID/edit?usp=drivesdk",
          "cachedResultName": "YOUR_DOCUMENT_NAME"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "c5280bdf-bbd5-4c3b-8cb3-6191097a30a4",
      "name": "Notify HR Team",
      "type": "n8n-nodes-base.slack",
      "position": [
        2944,
        240
      ],
      "parameters": {
        "text": "=\u2705 *Performance Review Successfully Processed*\n\n*Employee:* {{ $('Parse AI Response').item.json.employeeName }}\n*Department:* {{ $('Parse AI Response').item.json.department }}\n*Review Period:* {{ $('Parse AI Response').item.json.reviewPeriod }}\n\n*Performance Summary:*\n- Overall Rating: {{ $('Parse AI Response').item.json.overallRating }}/5.0 - {{ $('Parse AI Response').item.json.performanceLevel }}\n- Technical: {{ $('Parse AI Response').item.json.technicalScore }}/5 | Communication: {{ $('Parse AI Response').item.json.communicationScore }}/5\n- Leadership: {{ $('Parse AI Response').item.json.leadershipScore }}/5 | Productivity: {{ $('Parse AI Response').item.json.productivityScore }}/5\n- Teamwork: {{ $('Parse AI Response').item.json.teamworkScore }}/5\n\n*Status:*\n\u2709\ufe0f Email sent to: {{ $('Parse AI Response').item.json.employeeEmail }}\n\ud83d\udccb Manager CC'd: {{ $('Parse AI Response').item.json.managerEmail }}\n\ud83d\udcf8 Review card: <{{ $('Convert HTML to Image').item.json.image_url }}|View Image>\n\ud83d\udcdd Review ID: {{ $('Parse AI Response').item.json.reviewId }}\n\n{{ $('Parse AI Response').item.json.isLowPerformer ? '\u26a0\ufe0f *Low performer alert triggered - Manager notified*' : '\u2705 Performance within normal range' }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SLACK_CHANNEL_ID",
          "cachedResultName": "YOUR_CHANNEL_NAME"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "abef2c32-c886-4ac6-83d4-cc4d8dca7bf8",
      "name": "Convert HTML to Image",
      "type": "n8n-nodes-htmlcsstoimage.htmlCssToImage",
      "position": [
        2192,
        240
      ],
      "parameters": {
        "html_content": "={{ $json.html }}",
        "response_format_html": "png"
      },
      "credentials": {
        "htmlcsstoimgApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "a8883617-c50f-4dfd-b2c5-b9ac26a31cd7",
      "name": "Send Webhook Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        3104,
        240
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={\n  \"success\": true,\n  \"message\": \"Performance review processed successfully\",\n  \"reviewId\": \"={{ $('Parse AI Response').item.json.reviewId }}\",\n  \"employeeName\": \"={{ $('Parse AI Response').item.json.employeeName }}\",\n  \"overallRating\": \"={{ $('Parse AI Response').item.json.overallRating }}\",\n  \"performanceLevel\": \"={{ $('Parse AI Response').item.json.performanceLevel }}\",\n  \"imageUrl\": \"={{ $('Convert HTML to Image').item.json.image_url }}\",\n  \"emailSent\": true,\n  \"timestamp\": \"={{ $('Parse AI Response').item.json.processedAt }}\"\n}"
      },
      "typeVersion": 1.5
    },
    {
      "id": "5e1444e4-24a8-4c8d-a396-10f88e7a408f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        400,
        -128
      ],
      "parameters": {
        "width": 448,
        "height": 496,
        "content": "### How it works\nThis workflow automates AI-powered performance reviews. It receives employee data via webhook, processes scores and feedback, uses OpenAI to generate professional summaries, creates a visual review card as an image, emails it to employees with detailed metrics, logs everything to Google Sheets, and sends Slack notifications to HR.\n\n### Setup steps\nConnect these credentials before running:\n* **OpenAI** - Generate AI summaries\n* **HTMLCSS to Image** - Create review card images  \n* **Gmail** - Send review emails\n* **Slack** - HR notifications\n* **Google Sheets** - Log review data\n\n### Customization\nModify AI prompts in \"AI Summary Generator\" node to adjust tone. Update HTML template in \"Generate Review Card HTML\" for different visual styles. Configure performance thresholds in \"Process Employee Data\" for custom alert triggers."
      },
      "typeVersion": 1
    },
    {
      "id": "b3662988-dbf8-4640-b831-2da3b77ae0e5",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        864,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 224,
        "content": "## Input Collection\nWebhook receives employee performance data including scores, feedback, and review period details."
      },
      "typeVersion": 1
    },
    {
      "id": "6a03f803-36b9-429e-9cab-cbc2013d89f3",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1376,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 272,
        "content": "## AI Review Generation\nOpenAI analyzes performance metrics and generates structured summaries with strengths, improvements, and closing statements."
      },
      "typeVersion": 1
    },
    {
      "id": "2079169f-1550-49fc-bbbe-56a4fe895c75",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1952,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 272,
        "content": "## Formatting & Delivery\nConverts AI summary to HTML, generates image via HTMLCSS to Image API, downloads it, and emails to employee with detailed metrics."
      },
      "typeVersion": 1
    },
    {
      "id": "c80a3de8-72f7-4137-8747-07fe5fe20314",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2704,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 608,
        "height": 272,
        "content": "## Workflow Complete\nLogs review to Google Sheets, notifies HR via Slack, and sends webhook response confirming success."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "",
  "connections": {
    "Download Image": {
      "main": [
        [
          {
            "node": "Send Review to Employee",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify HR Team": {
      "main": [
        [
          {
            "node": "Send Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Response": {
      "main": [
        [
          {
            "node": "Generate Review Card HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive Review Data": {
      "main": [
        [
          {
            "node": "Process Employee Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Summary Generator": {
      "main": [
        [
          {
            "node": "Parse AI Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Google Sheets": {
      "main": [
        [
          {
            "node": "Notify HR Team",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert HTML to Image": {
      "main": [
        [
          {
            "node": "Download Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Employee Data": {
      "main": [
        [
          {
            "node": "AI Summary Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Review to Employee": {
      "main": [
        [
          {
            "node": "Log to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Review Card HTML": {
      "main": [
        [
          {
            "node": "Convert HTML to Image",
            "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

Simplify employee performance reviews with AI-powered automation. This workflow transforms raw feedback and evaluation inputs into clear, structured, and professional performance review summaries — saving hours of manual writing while ensuring consistency and fairness.

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

More Web Scraping workflows → · Browse all categories →

Related workflows

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

Web Scraping

This comprehensive workflow automates the entire testimonial collection and publishing process, from submission to social media-ready content. It uses AI to enhance testimonials, generates beautiful b

OpenAI, N8N Nodes Htmlcsstoimage, HTTP Request +3
Web Scraping

This workflow automates the entire pre-issuance process of workshop participation certificates. When an attendee submits a registration form via a webhook, the workflow validates the data, verifies th

Google Drive, Gmail, Google Sheets +4
Web Scraping

Automated Email Verification & Digital Health Card Generator

HTTP Request, Google Drive, Gmail +5
Web Scraping

Fully automated meeting documentation workflow that uses AI to transform raw transcripts into professional PDFs and actionable tasks. AI-powered summary generation (GPT-4) Automatic action item extrac

OpenAI, N8N Nodes Htmlcsstopdf, Gmail +4
Web Scraping

Automatically transform resolved support tickets into professional, AI-powered PDF documentation with complete tracking and team notifications.

OpenAI, Google Drive, Google Sheets +3