{
  "nodes": [
    {
      "id": "c2a94739-ae45-41ee-abda-66c7b43645c4",
      "name": "Anthropic Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        3456,
        384
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-5-20250929",
          "cachedResultName": "Claude Sonnet 4.5"
        },
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "c432ea5d-1dd7-4fe8-8764-d7a7b4cbede3",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        3616,
        384
      ],
      "parameters": {
        "jsonSchemaExample": "[\n  {\n    \"bundleId\": \"com.........\",\n    \"reviewId\": \"64f8b751-235a-43bd-99db-542693b6c91a\",\n    \"userComment\": \"Great app!\",\n    \"starRating\": \"5\",\n    \"response\": \"Thank you for your positive feedback.\"\n  },\n  {\n    \"bundleId\": \"com..........\",\n    \"reviewId\": \"b7a7b+1234567890d-9635-27239bd54d92\",\n    \"userComment\": \"Not satisfied, too many ads.\",\n    \"starRating\": \"2\",\n    \"response\": \"We're sorry for the inconvenience. Please contact us to discuss further.\"\n  }\n]\n"
      },
      "typeVersion": 1.3
    },
    {
      "id": "bd519b52-088d-48e1-8c84-d7fc82a6d5ca",
      "name": "Fetch list of applications",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        1424,
        32
      ],
      "parameters": {
        "operation": "get",
        "returnAll": true,
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "G62Hx71zBJA0QzdT",
          "cachedResultUrl": "/projects/Y78nQ4fOsYH80VvD/datatables/G62Hx71zBJA0QzdT",
          "cachedResultName": "Google Play apps"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "dda81596-5ebb-4ff9-97d1-90cd05557981",
      "name": "Fetch app bundle id and name",
      "type": "n8n-nodes-base.set",
      "position": [
        1648,
        32
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "4d914a6b-b4cc-411e-9edc-6eae7b19cb4c",
              "name": "bundle_id",
              "type": "string",
              "value": "={{ $json.bundle_id }}"
            },
            {
              "id": "61454092-3c30-4b0e-abc9-0caa0c1ab394",
              "name": "name",
              "type": "string",
              "value": "={{ $json.name }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "59714a87-67bc-4328-a3a1-f0f2dd6f181e",
      "name": "Loop over apps",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1856,
        32
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "c2a32db0-f17c-4472-bfe6-6763e9fb6593",
      "name": "Fetch reviews from Google Play",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2128,
        176
      ],
      "parameters": {
        "url": "=https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{{ $json.bundle_id }}/reviews",
        "options": {
          "pagination": {
            "pagination": {
              "parameters": {
                "parameters": [
                  {
                    "name": "token",
                    "value": "={{$response.body.tokenPagination.nextPageToken}}"
                  }
                ]
              },
              "maxRequests": 10,
              "requestInterval": 10,
              "limitPagesFetched": true,
              "completeExpression": "={{$response.body.tokenPagination.nextPageToken == null}}",
              "paginationCompleteWhen": "other"
            }
          }
        },
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleApi"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "fa77246f-b163-4413-bec2-22c4acf8b44f",
      "name": "Fetch yesterday's reviews",
      "type": "n8n-nodes-base.filter",
      "onError": "continueRegularOutput",
      "position": [
        2560,
        176
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "e5cc101a-9e06-4f33-8578-63c4acc66042",
              "operator": {
                "type": "dateTime",
                "operation": "equals"
              },
              "leftValue": "={{ $json.comments[0].userComment.lastModified.seconds.toDateTime('s').toISODate() }}",
              "rightValue": "={{$today.minus({days: 1})}}\n"
            }
          ]
        }
      },
      "notesInFlow": false,
      "typeVersion": 2.2,
      "alwaysOutputData": true
    },
    {
      "id": "2546b019-1098-4a78-a9e4-c82b8829ca2c",
      "name": "Any reviews yesterday?",
      "type": "n8n-nodes-base.if",
      "position": [
        2800,
        176
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "405061bb-27c7-4d37-a0c5-450b7d5db4aa",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.reviewId }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "c32f5d87-434b-41e5-b8cf-6a6d590f5480",
      "name": "Fetch fields required by LLM",
      "type": "n8n-nodes-base.set",
      "position": [
        3040,
        160
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "85404f02-cef9-459b-bf0c-7c727ffc9652",
              "name": "reviewId",
              "type": "string",
              "value": "={{ $json.reviewId }}"
            },
            {
              "id": "72583513-5359-4f3d-b51d-e77675c2ce9e",
              "name": "userComment",
              "type": "string",
              "value": "={{ $json.comments[0].userComment.text }}"
            },
            {
              "id": "d02c296d-8842-4f99-9cac-79556cb8a4da",
              "name": "starRating",
              "type": "number",
              "value": "={{ $json.comments[0].userComment.starRating }}"
            },
            {
              "id": "ba23cd7d-33e0-456f-a121-e01be8a9c768",
              "name": "reviewerLanguage",
              "type": "string",
              "value": "={{ $json.comments[0].userComment.reviewerLanguage }}"
            },
            {
              "id": "a99df95a-f666-4088-aa70-0fd52207cee0",
              "name": "bundleID",
              "type": "string",
              "value": "={{ $('Fetch app bundle id and name').item.json.bundle_id }}"
            },
            {
              "id": "01d0b8a3-e582-4aad-b22e-16a8f7d70da6",
              "name": "appName",
              "type": "string",
              "value": "={{ $('Loop over apps').item.json.name }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "134edbf1-b114-4331-bba1-0daea747ac08",
      "name": "LLM Response Generator",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        3456,
        160
      ],
      "parameters": {
        "text": "=You are a helpful community manager of a mobile apps company and your job is to read the player reviews on Google Play Store and to generate a response to be posted on behalf of the company's community team.\n\nReviews have the following elements:\n\n* Review id (reviewId): Google Play Store id of the review.\n* Star rating (starRating): an integer from 1 to 5, 1 being the lowest rating and 5 being the highest.\n* Review (userComment): The review or feedback provided by the user. The lower the star rating the more likely that the review will be a negative one. \n* Reviewer language (reviewerLanguage): User's language. The review might be in this language or a different one.\n* Google Play Store bundle id of the app (bundleId).\n* Name of the app (appName)\n\nFollow these guidelines when generating the response for a review:\n\n* Always start with thanking the user for sharing a review.\n* If the review is a negative one, respond with an apologetic and empathetic tone. Let the user know that we take their feedback seriously and we'd like them to contact us in the app to discuss their feedback. These responses should be 5 sentences max.\n* If the review is a positive one with 5 star rating, respond with a celebratory and grateful tone. These responses should be 2 sentences max.\n* The total length of the responses should be less than 500 characters. \n* Do not use any quotation marks (\", ' etc) in the responses you generate.\n\nHere are some example responses for negative reviews that you can use to generate your responses:\n\n<Add some examples here> \n\nThe response you generate should always be in English, even if the language of the review is a different one. Do not generate a response in any language other than English. \n\nAlways generate a list of customer review responses in JSON format. Each item should contain the following fields:\n* bundleId: Bundle id of the app.\n* reviewId: A unique identifier for the review.\n* userComment: The original comment made by the user.\n* starRating: An integer representing the star rating (1-5).\n* response: The generated response to the review.\n\nExample format:\n[\n  {\n    \"bundleId\": \"com......\",\n    \"reviewId\": \"64f8b751-7rty-43bd-99db-542693b6c23d\",\n    \"userComment\": \"Great app!\",\n    \"starRating\": \"5\",\n    \"response\": \"Thank you for your positive feedback.\"\n  },\n  {\n    \"bundleId\": \"com.......\",\n    \"reviewId\": \"b7a7b009-5086-441d-9635-27239bd54d91\",\n    \"userComment\": \"Not satisfied, too many ads.\",\n    \"starRating\": \"2\",\n    \"response\": \"We're sorry for the inconvenience. Please contact us to discuss further.\"\n  }\n]\n\nEnsure all generated responses conform to this format.\n\nHere are the list of reviews you should generate responses for. Generate a different response for each review and include all reviews and responses in your output:\n\n{{ $json.toJsonString() }}\n",
        "batching": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "52449955-61a6-4919-8273-dbdf8e672b1c",
      "name": "Get rid of empty items",
      "type": "n8n-nodes-base.filter",
      "position": [
        2128,
        -112
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "0d37ae77-c69f-4356-b76d-8698d89109d3",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.reviewId }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "a8bb4636-9efb-4300-a04f-b7079b3d71e5",
      "name": "Search responses ready to be posted",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1424,
        768
      ],
      "parameters": {
        "filter": {
          "driveId": {
            "__rl": true,
            "mode": "list",
            "value": "0AMSgS_z8k1A-Uk9PVA",
            "cachedResultUrl": "https://drive.google.com/drive/folders/0AMSgS_z8k1A-Uk9PVA",
            "cachedResultName": "n8n drive"
          },
          "whatToSearch": "files"
        },
        "options": {
          "fields": [
            "name",
            "id"
          ]
        },
        "resource": "fileFolder",
        "returnAll": true,
        "queryString": "'1YIAYsqrpcCAgWnkeEfzC1jSqs1uEPplW' in parents",
        "searchMethod": "query",
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "a8fa1b3a-3d7e-4bc3-8ee1-3b751463932b",
      "name": "Post responses",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        2080,
        768
      ],
      "parameters": {
        "url": "=https://www.googleapis.com/androidpublisher/v3/applications/{{ $json.bundle_id }}/reviews/{{$json.reviewId}}:reply",
        "body": "={\"replyText\": \"{{ $json.response }}\"}",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "raw",
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "googleApi"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "d1a4fe9c-a09c-4cd8-a1de-aa6a75be2aa0",
      "name": "Create a success log for the review",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        2320,
        672
      ],
      "parameters": {
        "columns": {
          "value": {
            "bundleID": "={{ $('Extract responses').item.json.bundle_id }}",
            "reviewID": "={{ $('Extract responses').item.json.reviewId }}",
            "successful": true
          },
          "schema": [
            {
              "id": "reviewID",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "reviewID",
              "defaultMatch": false
            },
            {
              "id": "bundleID",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "bundleID",
              "defaultMatch": false
            },
            {
              "id": "successful",
              "type": "boolean",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "successful",
              "defaultMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "24XOeDUZaMmW5U8J",
          "cachedResultUrl": "/projects/Y78nQ4fOsYH80VvD/datatables/24XOeDUZaMmW5U8J",
          "cachedResultName": "Google Play review response logs"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f67c121f-b59b-4f60-8e98-e5ec86c14c48",
      "name": "Create an error log for the review",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        2320,
        864
      ],
      "parameters": {
        "columns": {
          "value": {
            "reviewID": "={{ $('Extract responses').item.json.reviewId }}",
            "successful": false
          },
          "schema": [
            {
              "id": "reviewID",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "reviewID",
              "defaultMatch": false
            },
            {
              "id": "bundleID",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "bundleID",
              "defaultMatch": false
            },
            {
              "id": "successful",
              "type": "boolean",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "successful",
              "defaultMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "24XOeDUZaMmW5U8J",
          "cachedResultUrl": "/projects/Y78nQ4fOsYH80VvD/datatables/24XOeDUZaMmW5U8J",
          "cachedResultName": "Google Play review response logs"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7a9d4a66-5966-4a2a-aace-fa24d0084bf3",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        16
      ],
      "parameters": {
        "width": 640,
        "height": 896,
        "content": "## Generate responses for Google Play Store reviews using Anthropic Claude, Google Drive and Google Play Store API \nThis workflow empowers app developers and community management teams by automating the generation and posting of responses to user reviews on the Google Play Store. Designed to streamline the engagement process, it drastically reduces the manual workload on community managers by integrating AI-driven responses with necessary human oversight. By leveraging n8n's workflow automation capabilities, this solution eliminates the need for costly third-party platforms like AppFollow or Appbot, making it a cost-effective and efficient alternative.\n\n**Pre-requisites**\n* Google Drive & Google Sheets access: To store and manage review spreadsheets.\n* Google Play Developer Account / Service account: To fetch and respond to app reviews.\n* LLM credentials (e.g., Anthropic): Required for generating responses.\n\n### Workflow steps\n**1. Initialise and trigger workflow:** The process begins daily at 10 AM through a scheduled trigger.\n\n**2. Fetch application data:** Utilizes a data table (Google Play apps) to retrieve a list of applications with their bundle_id and name, essential for identifying review sources.\n\n**3. Collect Google Play Reviews:** Retrieves previous day's reviews from the Google Play Store based on app data. Stores the reviews in Google Sheets for further processing.\n\n**4. Generate AI Responses:** AI model generates initial responses based on review content. Responses are structured and stored along with reviews within a Google Spreadsheet located in a Google Drive folder called *ToReview*. \n\n**5. Human Review & Modification:** Community managers review and refine AI-generated responses. Reviewed spreadsheets are moved to the *ToSubmit* Google Drive folder by the editor.\n\n**6. Post Verified Responses:** Workflow triggers again at 5 PM to access reviewed spreadsheets in *ToSubmit* folder. It posts the human-verified responses back to the respective reviews on the Google Play Store. Logs are maintained, recording each response's success or failure.\n\n**7. Archive processed spreadsheets:** After posting the responses, workflow moves the processed files from *ToSubmit*  to a different folder called *Archived*\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1d470646-400e-42f1-b097-24e84d9c0797",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        864,
        0
      ],
      "parameters": {
        "color": 6,
        "width": 256,
        "height": 224,
        "content": "## FIRST STEP: GENERATE AI RESPONSES\nAt 10 am, download the previous day's reviews from Google Play Store and generate AI responses in a spreadsheet in *ToReview* folder"
      },
      "typeVersion": 1
    },
    {
      "id": "49e8692c-92f8-46ae-8733-84d2cdf096dd",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        864,
        368
      ],
      "parameters": {
        "color": 6,
        "width": 256,
        "height": 224,
        "content": "## SECOND STEP: HUMAN IN THE LOOP\nA human reviews the spreadsheet, makes any required adjustments to the responses and moves the spreadsheet to a different folder called *ToSubmit*"
      },
      "typeVersion": 1
    },
    {
      "id": "80c24326-18f5-40e6-a5cb-9aa0598d52db",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        864,
        704
      ],
      "parameters": {
        "color": 6,
        "width": 256,
        "height": 224,
        "content": "## THIRD STEP: POST RESPONSES\nAt 5pm, fetch the spreadsheets in *ToSubmit* folder, post the responses using the Google Play Store API, create execution logs and move the processed spreadsheets to a different folder called *Archived*"
      },
      "typeVersion": 1
    },
    {
      "id": "6ff7d7a4-cf93-4af0-9150-0819220cbc97",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2752,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 192,
        "height": 256,
        "content": "If there are no reviews for the app from yesterday, continue the loop with the next app "
      },
      "typeVersion": 1
    },
    {
      "id": "9fa0f3a6-9698-4c3e-ada3-b3af88d36e7e",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2080,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 224,
        "content": "Collect all the reviews and responses in a spreadsheet"
      },
      "typeVersion": 1
    },
    {
      "id": "d849a33e-860e-45db-a6ed-5592158c9479",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2496,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 208,
        "height": 224,
        "content": "Upload the spreadsheet to \"ToReview* folder"
      },
      "typeVersion": 1
    },
    {
      "id": "8ef283b3-185a-4a61-a4b8-acf87aef6186",
      "name": "Upload spreadsheet",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2544,
        -112
      ],
      "parameters": {
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "0AMSgS_z8k1A-Uk9PVA",
          "cachedResultUrl": "https://drive.google.com/drive/folders/0AMSgS_z8k1A-Uk9PVA",
          "cachedResultName": "n8n drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "1BFjKINf7etQH5Z4E-EW4Inem3sXEzo6-",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1BFjKINf7etQH5Z4E-EW4Inem3sXEzo6-",
          "cachedResultName": "ToReview"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "a2981f2b-e0ac-4a64-985f-b3875c698861",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1376,
        704
      ],
      "parameters": {
        "color": 7,
        "width": 192,
        "height": 240,
        "content": "Search the files in *ToSubmit* folder"
      },
      "typeVersion": 1
    },
    {
      "id": "f8e792de-4597-4726-9e3d-faa367e89afa",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1600,
        704
      ],
      "parameters": {
        "color": 7,
        "width": 192,
        "height": 240,
        "content": "Download files in the folder"
      },
      "typeVersion": 1
    },
    {
      "id": "fc40641c-766b-41d4-b3e5-df037cb83a90",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2080,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 192,
        "height": 256,
        "content": "Fetch reviews from Google Play API "
      },
      "typeVersion": 1
    },
    {
      "id": "27606a4c-1586-4ec4-92b7-a9e9d8fba5df",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2048,
        704
      ],
      "parameters": {
        "color": 7,
        "width": 176,
        "height": 240,
        "content": "Post responses using Google Play API"
      },
      "typeVersion": 1
    },
    {
      "id": "58b73198-2b2a-482d-8744-d3b93b60c02f",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1824,
        944
      ],
      "parameters": {
        "color": 7,
        "width": 192,
        "height": 272,
        "content": "After posting all responses, move the spreadsheet to Archived folder"
      },
      "typeVersion": 1
    },
    {
      "id": "94106cc1-92ac-4fd3-bf19-ef0ac948de89",
      "name": "Move spreadsheet to Archived folder",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1872,
        1040
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "0AMSgS_z8k1A-Uk9PVA",
          "cachedResultUrl": "https://drive.google.com/drive/folders/0AMSgS_z8k1A-Uk9PVA",
          "cachedResultName": "n8n drive"
        },
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "1_a0VKmCKx8K4VWSh8EJ5B86NhN9PPhxu",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1_a0VKmCKx8K4VWSh8EJ5B86NhN9PPhxu",
          "cachedResultName": "Archived"
        },
        "operation": "move",
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "f3f27a99-0e61-4027-83c9-375ef3024cb1",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1376,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 352,
        "content": "### Data table fields \n* bundle_id: Google Play Store bundle id for each app. Bundle ids can be found in the Google Play Store url of the app. For example the bundle id of the app with url https://play.google.com/store/apps/details?id=com.anthropic.claude is *com.anthropic.claude*\n* name: The application\u2019s name (eg. Claude by Anthropic)"
      },
      "typeVersion": 1
    },
    {
      "id": "32417b29-40cd-4df6-af83-7d8f8514f2a5",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2256,
        496
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 544,
        "content": "### Data table fields\n* reviewID: Google Play Store Identifier for each review.\n* bundleID: Corresponding application bundle identifier.\n* successful: Boolean status indicating the posting success."
      },
      "typeVersion": 1
    },
    {
      "id": "e38727bc-7f63-4935-bb7f-0dd2801222ce",
      "name": "Split out fetched reviews",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        2336,
        176
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "reviews"
      },
      "typeVersion": 1
    },
    {
      "id": "c157f1bf-199a-4a73-b2db-741019221a46",
      "name": "Aggregate reviews for LLM use",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        3248,
        160
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "reviews"
      },
      "typeVersion": 1
    },
    {
      "id": "38c5b386-713f-41f4-abbc-cfdf6ca4c70b",
      "name": "Split responses",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        3776,
        160
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "output"
      },
      "typeVersion": 1
    },
    {
      "id": "32dc7419-f649-426b-8318-a37474fe910d",
      "name": "Create the spreadsheet",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        2336,
        -112
      ],
      "parameters": {
        "options": {
          "fileName": "={{ $now.format('yyyy-MM-dd-HH-mm-ss') }}_all_review_responses"
        },
        "operation": "xlsx"
      },
      "typeVersion": 1.1
    },
    {
      "id": "334defb9-260a-4869-9f82-24608c203198",
      "name": "Download responses sheet",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1648,
        768
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {},
        "operation": "download",
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "c55f1fd7-b256-4ade-8aa1-7cdfe68ec50e",
      "name": "Extract responses",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        1872,
        768
      ],
      "parameters": {
        "options": {},
        "operation": "xlsx"
      },
      "typeVersion": 1.1
    },
    {
      "id": "3cd9af4c-9501-42c0-9ab9-0f14b9056414",
      "name": "Trigger download",
      "type": "n8n-nodes-base.scheduleTrigger",
      "notes": "daily at 10am",
      "position": [
        1200,
        32
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 10
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 1.2
    },
    {
      "id": "d9ee30a1-d365-44d6-8082-60f248520338",
      "name": "Trigger posting responses",
      "type": "n8n-nodes-base.scheduleTrigger",
      "notes": "daily at 5pm",
      "position": [
        1168,
        768
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 17
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 1.2
    }
  ],
  "connections": {
    "Loop over apps": {
      "main": [
        [
          {
            "node": "Get rid of empty items",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Fetch reviews from Google Play",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post responses": {
      "main": [
        [
          {
            "node": "Create a success log for the review",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create an error log for the review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split responses": {
      "main": [
        [
          {
            "node": "Loop over apps",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger download": {
      "main": [
        [
          {
            "node": "Fetch list of applications",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract responses": {
      "main": [
        [
          {
            "node": "Post responses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Anthropic Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "LLM Response Generator",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Any reviews yesterday?": {
      "main": [
        [
          {
            "node": "Fetch fields required by LLM",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop over apps",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create the spreadsheet": {
      "main": [
        [
          {
            "node": "Upload spreadsheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get rid of empty items": {
      "main": [
        [
          {
            "node": "Create the spreadsheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LLM Response Generator": {
      "main": [
        [
          {
            "node": "Split responses",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download responses sheet": {
      "main": [
        [
          {
            "node": "Extract responses",
            "type": "main",
            "index": 0
          },
          {
            "node": "Move spreadsheet to Archived folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "LLM Response Generator",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Fetch yesterday's reviews": {
      "main": [
        [
          {
            "node": "Any reviews yesterday?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split out fetched reviews": {
      "main": [
        [
          {
            "node": "Fetch yesterday's reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger posting responses": {
      "main": [
        [
          {
            "node": "Search responses ready to be posted",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch list of applications": {
      "main": [
        [
          {
            "node": "Fetch app bundle id and name",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch app bundle id and name": {
      "main": [
        [
          {
            "node": "Loop over apps",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch fields required by LLM": {
      "main": [
        [
          {
            "node": "Aggregate reviews for LLM use",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate reviews for LLM use": {
      "main": [
        [
          {
            "node": "LLM Response Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch reviews from Google Play": {
      "main": [
        [
          {
            "node": "Split out fetched reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search responses ready to be posted": {
      "main": [
        [
          {
            "node": "Download responses sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}