AutomationFlowsAI & RAG › Generate and Post Apple App Store Review Replies with Anthropic Claude

Generate and Post Apple App Store Review Replies with Anthropic Claude

ByErtay Kaya @ertay on n8n.io

This workflow empowers app developers and community management teams by automating the generation and posting of responses to user reviews on the Apple App Store. Designed to streamline the engagement process, it drastically reduces the manual workload on community managers by…

Cron / scheduled trigger★★★★★ complexityAI-powered44 nodesJwtHTTP RequestSlackData TableGoogle DriveChain LlmAnthropic ChatOutput Parser Structured
AI & RAG Trigger: Cron / scheduled Nodes: 44 Complexity: ★★★★★ AI nodes: yes Added:

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

This workflow follows the Chainllm → Google Drive 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
{
  "nodes": [
    {
      "id": "8730f723-83fa-4dcb-8324-bbdc095efa29",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        -32
      ],
      "parameters": {
        "width": 640,
        "height": 928,
        "content": "## Generate and post Apple App Store review replies with Anthropic Claude, Google Drive and App Store Connect API \nThis workflow empowers app developers and community management teams by automating the generation and posting of responses to user reviews on the Apple App 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* App Store Connect API credentials: To fetch and respond to app reviews.\n* LLM credentials (e.g., Anthropic): Required for generating responses.\n* Slack account\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 (Apple App Store apps) to retrieve a list of applications with their app id and name, essential for identifying review sources.\n\n**3. Collect App Store Reviews:** Retrieves previous day's reviews from the App Store Connect API 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*. A Slack message is sent with the URL of the file\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 Apple App Store using App Store Connect API. 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": "e53b3d28-02d2-40b2-9108-2e19b4f9f082",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        864,
        -64
      ],
      "parameters": {
        "color": 6,
        "width": 256,
        "height": 240,
        "content": "## FIRST STEP: GENERATE AI RESPONSES\nAt 10 am, download the previous day's reviews from Apple App Store and generate AI responses in a spreadsheet in *ToReview* folder. Send a Slack message with the url of the file"
      },
      "typeVersion": 1
    },
    {
      "id": "49138ab4-878a-434a-bf9d-29a4027375d8",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        864,
        336
      ],
      "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": "4aac0d74-1e71-4104-8032-e956d9b3cbf5",
      "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 Apple App Store Connect API, create execution logs and move the processed spreadsheets to a different folder called *Archived*"
      },
      "typeVersion": 1
    },
    {
      "id": "e20d885f-8c4f-479c-874a-bef5845079ed",
      "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": "a2b60e1f-7cd5-4f4f-8e73-dd9b221d6293",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1600,
        704
      ],
      "parameters": {
        "color": 7,
        "width": 192,
        "height": 240,
        "content": "Download responses sheet"
      },
      "typeVersion": 1
    },
    {
      "id": "617041ff-cab9-49b6-92e1-49c68d65be21",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2064,
        688
      ],
      "parameters": {
        "color": 7,
        "width": 384,
        "height": 256,
        "content": "Post responses using App Store Connect API: https://developer.apple.com/documentation/appstoreconnectapi/post-v1-customerreviewresponses"
      },
      "typeVersion": 1
    },
    {
      "id": "f852eebe-7a34-427a-9896-dcb5e9cf5eba",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2480,
        528
      ],
      "parameters": {
        "color": 7,
        "width": 368,
        "height": 544,
        "content": "### Data table fields\n* reviewID: App Store Identifier for each review.\n* app_id: Corresponding application's app id.\n* successful: Boolean status indicating the posting success."
      },
      "typeVersion": 1
    },
    {
      "id": "e10dd702-4236-44c7-a92e-5584fb611090",
      "name": "Trigger posting responses",
      "type": "n8n-nodes-base.scheduleTrigger",
      "notes": "daily at 5pm",
      "position": [
        1200,
        768
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 17
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 1.2
    },
    {
      "id": "c3a99a3c-d3aa-4089-865a-de1791889dc8",
      "name": "JWT",
      "type": "n8n-nodes-base.jwt",
      "position": [
        2160,
        144
      ],
      "parameters": {
        "options": {
          "kid": "K11111111"
        },
        "useJson": true,
        "claimsJson": "={\n  \"iss\": \"iss_here\",\n  \"aud\": \"appstoreconnect-v1\",\n  \"bid\": \"bundle.id\",\n  \"exp\": {{ Math.floor((new Date().getTime() + 10 * 60 * 1000) / 1000) }}\n}\n"
      },
      "credentials": {
        "jwtAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6ade90b9-751a-4f1f-aa06-ceedf052c626",
      "name": "Fetch app id and name",
      "type": "n8n-nodes-base.set",
      "position": [
        1680,
        -16
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "4d914a6b-b4cc-411e-9edc-6eae7b19cb4c",
              "name": "app_id",
              "type": "string",
              "value": "={{ $json.app_id }}"
            },
            {
              "id": "c26e6fa1-6a56-433a-9c7c-45cd5009860c",
              "name": "name",
              "type": "string",
              "value": "={{ $json.name }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "49b71085-3bc1-4991-ad9e-dbcce799a205",
      "name": "HTTP Request - App Store Reviews",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2368,
        144
      ],
      "parameters": {
        "url": "=https://api.appstoreconnect.apple.com/v1/apps/{{ $('Loop over apps').item.json.app_id }}/customerReviews?sort=-createdDate",
        "options": {
          "pagination": {
            "pagination": {
              "nextURL": "={{$response.body.links[\"next\"]}}",
              "maxRequests": 5,
              "paginationMode": "responseContainsNextURL",
              "limitPagesFetched": true,
              "completeExpression": "={{$response.body.links[\"next\"] == null}}",
              "paginationCompleteWhen": "other"
            }
          }
        },
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "typeVersion": 4.2
    },
    {
      "id": "1154b9d7-77ad-46cb-8274-ed9d796a96a7",
      "name": "Sticky Note14",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1376,
        -192
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 352,
        "content": "### Data table fields \n* app_id: Apple app id for each app. App id can be found in the Apple App Store url of the app. For example the app id of the app with url https://apps.apple.com/us/app/claude-by-anthropic/id6473753684 is 6473753684\n* name: The application\u2019s name (eg. Claude by Anthropic)"
      },
      "typeVersion": 1
    },
    {
      "id": "548e6542-150b-43e9-bb0e-aa3c1563584d",
      "name": "Sticky Note15",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2112,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 624,
        "height": 224,
        "content": "Collect all the reviews and responses in a spreadsheet, sorted by rating"
      },
      "typeVersion": 1
    },
    {
      "id": "cc9bbad3-9cf5-4ae7-a8cf-52ddabf29251",
      "name": "Sticky Note16",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2752,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 208,
        "height": 224,
        "content": "Upload the spreadsheet to \"ToReview* folder"
      },
      "typeVersion": 1
    },
    {
      "id": "59b82ea7-7228-4f32-8717-53b99fa5b3fc",
      "name": "Send to Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        3024,
        -160
      ],
      "parameters": {
        "text": "=Hello, a new list is ready for review: {{ $json.webViewLink }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "C11111111111"
        },
        "otherOptions": {
          "includeLinkToWorkflow": false
        }
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "be34c4db-073c-488e-85a1-0de8bf5a5cf6",
      "name": "Sticky Note17",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2976,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 224,
        "height": 224,
        "content": "Send the Google Drive url of the file in a Slack message"
      },
      "typeVersion": 1
    },
    {
      "id": "4a3091d3-3d2f-4e9a-ab59-cbedceb60366",
      "name": "Sticky Note18",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2112,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 240,
        "content": "Fetch reviews from App Store Connect API: https://developer.apple.com/documentation/appstoreconnectapi/get-v1-apps-_id_-customerreviews"
      },
      "typeVersion": 1
    },
    {
      "id": "abdde680-74ae-4030-9e18-8c1dadd069d2",
      "name": "Split Out fetched reviews",
      "type": "n8n-nodes-base.splitOut",
      "onError": "continueErrorOutput",
      "position": [
        2592,
        144
      ],
      "parameters": {
        "include": "=",
        "options": {
          "destinationFieldName": ""
        },
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "69752f2d-a82c-42b8-bf10-4e03ad23a36e",
      "name": "Sticky Note19",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2960,
        32
      ],
      "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": "9aac9cb5-2770-4fd5-9528-0664b1a74140",
      "name": "Fetch list of applications",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        1440,
        -16
      ],
      "parameters": {
        "operation": "get",
        "returnAll": true,
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "e7fEo2CHu9iNjHJV",
          "cachedResultUrl": "/projects/Y78nQ4fOsYH80VvD/datatables/e7fEo2CHu9iNjHJV",
          "cachedResultName": "Apple App Store apps"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "625eb4c8-1d01-4505-a158-2ca5a64e9edb",
      "name": "Loop over apps",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1888,
        -16
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "076db3bc-2b0f-4fc9-9c7f-637cda4cd507",
      "name": "Get rid of empty items",
      "type": "n8n-nodes-base.filter",
      "position": [
        2160,
        -160
      ],
      "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": "df97eb53-a4d4-4655-a4b5-e9781c252ef1",
      "name": "Sort",
      "type": "n8n-nodes-base.sort",
      "position": [
        2368,
        -160
      ],
      "parameters": {
        "options": {},
        "sortFieldsUi": {
          "sortField": [
            {
              "fieldName": "starRating"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e7c03979-0c11-4775-8835-4ed88bcc468f",
      "name": "Convert to File",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        2592,
        -160
      ],
      "parameters": {
        "options": {
          "fileName": "=Apple_{{ $now.format('yyyy-MM-dd-HH-mm-ss') }}_all_review_responses",
          "headerRow": true
        },
        "operation": "xlsx"
      },
      "typeVersion": 1.1
    },
    {
      "id": "2a843a6f-d36b-40db-907d-9b4e7ae0014b",
      "name": "Upload file",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2816,
        -160
      ],
      "parameters": {
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "0AMSgS_z8k1A-Uk9PVA",
          "cachedResultUrl": "https://drive.google.com/drive/folders/0NASgS_z8k1A-Uk9PVA",
          "cachedResultName": "n8n drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "1BFjKINf7etQH5Z4E-EW4Inem3sXEzo6-",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1BFjKINf7etQH5Z5D-EW4Inem3sXEzo6-",
          "cachedResultName": "ToReview"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "67e1ba4d-46a3-4257-af6f-9e4552a3fd1c",
      "name": "Fetch yesterday's reviews",
      "type": "n8n-nodes-base.filter",
      "onError": "continueRegularOutput",
      "position": [
        2816,
        144
      ],
      "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.data.attributes.createdDate.toDateTime().format('yyyy-MM-dd') }}",
              "rightValue": "={{$today.minus({days: 1}).format('yyyy-MM-dd')}}\n"
            }
          ]
        }
      },
      "notesInFlow": false,
      "typeVersion": 2.2,
      "alwaysOutputData": true
    },
    {
      "id": "aeb78c41-9235-422d-897b-8f742411e9f3",
      "name": "Any reviews yesterday?",
      "type": "n8n-nodes-base.if",
      "position": [
        3008,
        144
      ],
      "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.data.id }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "ad840df5-221a-436d-b734-2080ad620816",
      "name": "Fetch fields required by LLM",
      "type": "n8n-nodes-base.set",
      "position": [
        3248,
        128
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "85404f02-cef9-459b-bf0c-7c727ffc9652",
              "name": "reviewId",
              "type": "string",
              "value": "={{ $json.data.id }}"
            },
            {
              "id": "72583513-5359-4f3d-b51d-e77675c2ce9e",
              "name": "title",
              "type": "string",
              "value": "={{ $json.data.attributes.title }}"
            },
            {
              "id": "aadd7f83-ce56-4b74-8523-bc00d3e7daf9",
              "name": "body",
              "type": "string",
              "value": "={{ $json.data.attributes.body }}"
            },
            {
              "id": "d02c296d-8842-4f99-9cac-79556cb8a4da",
              "name": "rating",
              "type": "number",
              "value": "={{ $json.data.attributes.rating }}"
            },
            {
              "id": "ba23cd7d-33e0-456f-a121-e01be8a9c768",
              "name": "territory",
              "type": "string",
              "value": "={{ $json.data.attributes.territory }}"
            },
            {
              "id": "a99df95a-f666-4088-aa70-0fd52207cee0",
              "name": "app_id",
              "type": "string",
              "value": "={{ $('Loop over apps').item.json.app_id }}"
            },
            {
              "id": "01d0b8a3-e582-4aad-b22e-16a8f7d70da6",
              "name": "app_name",
              "type": "string",
              "value": "={{ $('Loop over apps').item.json.name }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e409e93c-a51e-48d9-82fb-be178b89659a",
      "name": "Aggregate reviews for LLM use",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        3456,
        128
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "reviews"
      },
      "typeVersion": 1
    },
    {
      "id": "5f6cdf29-e9ee-42ef-9c78-cbc51f587f4a",
      "name": "LLM Response Generator",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "onError": "continueErrorOutput",
      "position": [
        3664,
        128
      ],
      "parameters": {
        "text": "=You are a helpful community manager of a mobile apps company and your job is to read the player reviews on Apple App 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): Apple App 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* Title (title): Title of the review or feedback provided by the player.\n* Body (body): Body of the review or feedback provided by the player. The lower the star rating the more likely that the review will be a negative one. \n* Apple App Store  id of the app (app_id).\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- app_id: The Apple id of the application.\n- reviewId: A unique identifier for the review.\n- title: The title of the review submitted by the user.\n- body: The body of the review submitted 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    \"app_id\": \"6608975929\",\n    \"app_name\": \"App Name1\",\n    \"reviewId\": \"64f8b751-7fba-43bd-99re-542693b6c01d\",\n    \"title\": \"Highly recommend!\",\n    \"body\": \"Love this app so much!\",\n    \"starRating\": \"5\",\n    \"response\": \"Thank you for your positive feedback.\"\n  },\n  {\n    \"app_id\": \"5508975929\",\n    \"app_name\": \"App Name2t\",\n    \"reviewId\": \"b7a7b009-5086-441d-9635-27239bd54c19\",\n    \"title\": \"Wouldn't recommend!\",\n    \"body\": \"Full of 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
      },
      "retryOnFail": true,
      "typeVersion": 1.7
    },
    {
      "id": "6f5fc2f9-82db-4c1b-a716-4bd89ce376b7",
      "name": "Anthropic Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        3664,
        352
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-5-20250929",
          "cachedResultName": "Claude Sonnet 4.5"
        },
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "5742ae4d-66d9-42ef-93be-52e61b83e8cc",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        3824,
        352
      ],
      "parameters": {
        "jsonSchemaExample": "[\n  {\n    \"app_id\": \"5508975929\",\n    \"app_name\": \"App Name 1\",\n    \"reviewId\": \"64f8b751-7fba-43bd-99db-654393b6c01d\",\n    \"title\": \"Highly recommend!\",\n    \"body\": \"Love this app so much!\",\n    \"starRating\": \"5\",\n    \"response\": \"Thank you for your positive feedback.\"\n  },\n  {\n    \"app_id\": \"6608975929\",\n    \"app_name\": \"App Name2\",\n    \"reviewId\": \"b7a7b+1234456790d-9635-27239be45c19\",\n    \"title\": \"Wouldn't recommend!\",\n    \"body\": \"Full of 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": "dca8dcf4-f7f8-4e87-b208-ca52a72c7d46",
      "name": "Split responses",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        3984,
        128
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "output"
      },
      "typeVersion": 1
    },
    {
      "id": "1f488681-a855-4173-a024-3feb0570bb75",
      "name": "Trigger download",
      "type": "n8n-nodes-base.scheduleTrigger",
      "notes": "daily at 10am",
      "position": [
        1200,
        -16
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 10
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 1.2
    },
    {
      "id": "8935b8c3-b1d4-4125-b195-7487a6d5c6ec",
      "name": "JWT1",
      "type": "n8n-nodes-base.jwt",
      "position": [
        2096,
        768
      ],
      "parameters": {
        "options": {
          "kid": "key_id_here"
        },
        "useJson": true,
        "claimsJson": "={\n  \"iss\": \"iss_here\",\n  \"aud\": \"appstoreconnect-v1\",\n  \"bid\": \"bundle_id_here\",\n  \"exp\": {{ Math.floor((new Date().getTime() + 10 * 60 * 1000) / 1000) }}\n}\n"
      },
      "credentials": {
        "jwtAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "87eb3f9f-b743-49db-a967-7aee526bb63b",
      "name": "HTTP Request - Respond to App Store reviews",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        2288,
        768
      ],
      "parameters": {
        "url": "=https://api.appstoreconnect.apple.com/v1/customerReviewResponses",
        "body": "={\n  \"data\": {\n    \"type\": \"customerReviewResponses\",\n    \"relationships\": {\n      \"review\": {\n        \"data\": {\n          \"type\": \"customerReviews\",\n          \"id\": \"{{ $('Switch').item.json.reviewId }}\"\n        }\n      }\n    },\n    \"attributes\": {\n      \"responseBody\": \"{{ $('Switch').item.json.response }}\"\n    }\n  }\n}",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "raw",
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "rawContentType": "application/json",
        "genericAuthType": "httpBearerAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "2ddb4501-0666-4c89-9b8f-cf473dc01269",
      "name": "Sticky Note12",
      "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": "3e5ede65-72ed-4593-89e4-0313d196fe04",
      "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-Uk9FRA",
            "cachedResultUrl": "https://drive.google.com/drive/folders/0ERSgS_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": "446dc214-1342-4baa-bbf6-5f1772b601ef",
      "name": "Download file",
      "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": "adf83d9e-1c59-4dd0-b1e6-1c76b578c62b",
      "name": "Extract from File",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        1872,
        768
      ],
      "parameters": {
        "options": {
          "headerRow": true
        },
        "operation": "xlsx"
      },
      "typeVersion": 1.1
    },
    {
      "id": "60b7ee93-9e28-4914-9e92-ef285ee27654",
      "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/0AFRgS_z8k1A-Uk9PVA",
          "cachedResultName": "n8n drive"
        },
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "1_a0VKmCKx8K4VWSh8EJ5B86NhN9PPhxu",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1_a0VKmCKx8K4VWSh6yt5B86NhN9PPhxu",
          "cachedResultName": "Archived"
        },
        "operation": "move",
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "0fd8bee9-f926-45a9-a094-2deb0748012f",
      "name": "Create a success log for the review",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        2560,
        688
      ],
      "parameters": {
        "columns": {
          "value": {
            "app_id": "={{ $('Extract from File1').item.json.app_id }}",
            "reviewID": "={{ $('Extract from File1').item.json.reviewId }}",
            "successful": true
          },
          "schema": [
            {
              "id": "reviewID",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "reviewID",
              "defaultMatch": false
            },
            {
              "id": "app_id",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "app_id",
              "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": "IzigR44QzLukW3V1",
          "cachedResultUrl": "/projects/Y78nQ4fOsYH80VvD/datatables/IzigR44QzLukW3V1",
          "cachedResultName": "Apple App Store review response logs"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b701bacd-df4a-4608-a74d-b918936bd4d3",
      "name": "Create an errror log for the review",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        2560,
        880
      ],
      "parameters": {
        "columns": {
          "value": {
            "app_id": "={{ $('Extract from File1').item.json.app_id }}",
            "reviewID": "={{ $('Extract from File1').item.json.reviewId }}",
            "successful": false
          },
          "schema": [
            {
              "id": "reviewID",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "reviewID",
              "defaultMatch": false
            },
            {
              "id": "app_id",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "app_id",
              "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": "IzigR44QzLukW3V1",
          "cachedResultUrl": "/projects/Y78nQ4fOsYH80VvD/datatables/IzigR44QzLukW3V1",
          "cachedResultName": "Apple App Store review response logs"
        }
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "JWT": {
      "main": [
        [
          {
            "node": "HTTP Request - App Store Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JWT1": {
      "main": [
        [
          {
            "node": "HTTP Request - Respond to App Store reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sort": {
      "main": [
        [
          {
            "node": "Convert to File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload file": {
      "main": [
        [
          {
            "node": "Send to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download file": {
      "main": [
        [
          {
            "node": "Extract from File",
            "type": "main",
            "index": 0
          },
          {
            "node": "Move spreadsheet to Archived folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop over apps": {
      "main": [
        [
          {
            "node": "Get rid of empty items",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "JWT",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert to File": {
      "main": [
        [
          {
            "node": "Upload file",
            "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 from File": {
      "main": [
        [
          {
            "node": "JWT1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Anthropic Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "LLM Response Generator",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Fetch app id and name": {
      "main": [
        [
          {
            "node": "Loop over apps",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any reviews yesterday?": {
      "main": [
        [
          {
            "node": "Fetch fields required by LLM",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop over apps",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get rid of empty items": {
      "main": [
        [
          {
            "node": "Sort",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LLM Response Generator": {
      "main": [
        [
          {
            "node": "Split responses",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop over apps",
            "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
          }
        ],
        [
          {
            "node": "Loop over apps",
            "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 id and name",
            "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
          }
        ]
      ]
    },
    "HTTP Request - App Store Reviews": {
      "main": [
        [
          {
            "node": "Split Out fetched reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search responses ready to be posted": {
      "main": [
        [
          {
            "node": "Download file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request - Respond to App Store reviews": {
      "main": [
        [
          {
            "node": "Create a success log for the review",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create an errror log for the review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow empowers app developers and community management teams by automating the generation and posting of responses to user reviews on the Apple App Store. Designed to streamline the engagement process, it drastically reduces the manual workload on community managers by…

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

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

This 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 engageme

Anthropic Chat, Output Parser Structured, Data Table +3
AI & RAG

The Recap AI - Short Form News Script Generator. Uses httpRequest, s3, chainLlm, slack. Scheduled trigger; 42 nodes.

HTTP Request, S3, Chain Llm +3
AI & RAG

This workflow is designed for Japanese-speaking professionals, and learners who want to efficiently stay up to date with practical productivity, lifehack, and efficiency-related insights from Japanese

RSS Feed Read, Chain Llm, Google Gemini Chat +7
AI & RAG

Transform simple ideas into viral-ready Bigfoot vlogs! This automated workflow creates charming 8-scene video content featuring "Sam" the Bigfoot - a lovable, outdoorsy character inspired by popular Y

Form Trigger, Anthropic Chat, Chain Llm +4
AI & RAG

Content - Newsletter Agent. Uses formTrigger, chainLlm, outputParserStructured, httpRequest. Event-driven trigger; 87 nodes.

Form Trigger, Chain Llm, Output Parser Structured +7