{
  "name": "Weekly review themes to Google Sheets (ProLevelMax + n8n)",
  "nodes": [
    {
      "parameters": {
        "content": "## Weekly review themes (ProLevelMax)\nEvery Friday at 8:00 AM, ProLevelMax pulls the newest Trustpilot reviews of a company, AI groups them into complaints, praise and one talking point, and the row lands in Google Sheets.\n\n**Before you test**\n1. Get new reviews: create a Bearer Auth credential with a key from prolevelmax.com > API keys.\n2. Find the themes: pick your OpenAI credential (n8n's free OpenAI credits work).\n3. Add this week's row: connect Google and paste your sheet's URL. Row 1 needs: Week, Company, Reviews read, Average rating, Top complaints, Top praise, Talking point.\n\nCost: $0.0012 per review, so 30 reviews is about 4 cents a week. New ProLevelMax users get $1 free.\n\n**Free step-by-step lesson:** learn.ynteractive.com/modules/n8n-prolevelmax-review-digest",
        "height": 580,
        "width": 400,
        "color": 4
      },
      "id": "s0",
      "name": "Sticky Note: overview",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -480,
        -340
      ]
    },
    {
      "parameters": {
        "content": "### Add your ProLevelMax key\nPOST https://prolevelmax.com/v1/run\nAuthentication: Generic > Bearer Auth.\nSource: **procli_trustpilot_a** (Company reviews). Swap `pipedrive.com` for the company you watch. Field names come from the console's Collect form.",
        "height": 240,
        "width": 320,
        "color": 3
      },
      "id": "s1",
      "name": "Sticky Note: key",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        440,
        -300
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                5
              ],
              "triggerAtHour": 8
            }
          ]
        }
      },
      "id": "c1",
      "name": "Every Friday at 8am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://prolevelmax.com/v1/run",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "{\n  \"scraper\": \"procli_trustpilot_a\",\n  \"input\": {\n    \"companyUrls\": [\"pipedrive.com\"],\n    \"maxReviewsPerCompany\": 30,\n    \"sort\": \"recency\",\n    \"languages\": [\"en\"]\n  },\n  \"maxItems\": 30\n}",
        "options": {
          "timeout": 120000
        }
      },
      "id": "c2",
      "name": "Get new reviews (ProLevelMax)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        260,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "// ProLevelMax returns the reviews in `items`. Keep only what the AI needs:\n// rating, title, text (trimmed) and date, for up to 30 reviews.\nconst body = $input.first().json;\nconst items = body.items || body.results || [];\nconst reviews = items.slice(0, 30).map((it) => {\n  const r = it.review || it;\n  return {\n    rating: Number(r.rating ?? r.stars ?? r.score) || null,\n    title: r.title || r.reviewTitle || '',\n    text: String(r.text || r.reviewText || r.body || r.content || '').slice(0, 700),\n    date: r.date || r.publishedDate || r.createdAt || '',\n  };\n});\nconst rated = reviews.filter((r) => r.rating);\nconst average = rated.length ? (rated.reduce((s, r) => s + r.rating, 0) / rated.length).toFixed(1) : '';\nreturn [{ json: { company: 'pipedrive.com', count: reviews.length, average, reviews: JSON.stringify(reviews) } }];"
      },
      "id": "c3",
      "name": "Keep rating and text",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        520,
        0
      ]
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-5-mini",
          "mode": "list",
          "cachedResultName": "GPT-5-MINI"
        },
        "responses": {
          "values": [
            {
              "content": "=You help Fieldstone CRM Consulting advise small businesses on which CRM to choose. Read these {{ $json.count }} recent Trustpilot reviews of {{ $json.company }}.\nUse only what the reviews say. Do not invent numbers.\nReply with JSON only, with these keys:\n- top_complaints: the 3 most common complaints, as one string with \"; \" between them\n- top_praise: the 3 most common things people like, the same way\n- talking_point: one sentence a consultant could tell a client this week\n\nReviews (JSON):\n{{ $json.reviews }}"
            }
          ]
        },
        "builtInTools": {},
        "options": {}
      },
      "id": "c4",
      "name": "Find the themes",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 2.3,
      "position": [
        780,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "// Turn the AI's JSON answer into one row whose keys match the sheet's column names.\nconst src = $('Keep rating and text').first().json;\nconst raw = $input.first().json.output?.[0]?.content?.[0]?.text || '{}';\nlet ai = {};\ntry { ai = JSON.parse(raw.replace(/^```(json)?|```$/g, '').trim()); } catch (e) { ai = { top_complaints: raw }; }\nreturn [{ json: {\n  'Week': new Date().toISOString().slice(0, 10),\n  'Company': src.company,\n  'Reviews read': src.count,\n  'Average rating': src.average,\n  'Top complaints': ai.top_complaints || '',\n  'Top praise': ai.top_praise || '',\n  'Talking point': ai.talking_point || '',\n} }];"
      },
      "id": "c5",
      "name": "Make the sheet row",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        0
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "https://docs.google.com/spreadsheets/d/PASTE_YOUR_SHEET_ID/edit",
          "mode": "url"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Sheet1"
        },
        "columns": {
          "mappingMode": "autoMapInputData",
          "value": {},
          "matchingColumns": [],
          "schema": []
        },
        "options": {}
      },
      "id": "c6",
      "name": "Add this week's row",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.6,
      "position": [
        1360,
        0
      ]
    }
  ],
  "connections": {
    "Every Friday at 8am": {
      "main": [
        [
          {
            "node": "Get new reviews (ProLevelMax)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get new reviews (ProLevelMax)": {
      "main": [
        [
          {
            "node": "Keep rating and text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Keep rating and text": {
      "main": [
        [
          {
            "node": "Find the themes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find the themes": {
      "main": [
        [
          {
            "node": "Make the sheet row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Make the sheet row": {
      "main": [
        [
          {
            "node": "Add this week's row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}
