{
  "openapi": "3.0.1",
  "info": {
    "title": "Mac App Store Reviews Scraper – iTunes Reviews, Any Country",
    "description": "Extract Apple App Store reviews for any iOS or Mac app and country storefront: rating, title, text, version, author, date, app metadata, per-star ratings breakdown, and sort by most recent, most helpful, favorable or critical. Pay per review. Track app store ratings over time with watch mode.",
    "version": "0.1",
    "x-build-id": "ii38jdbS2rtbjTCRA"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/fetchsmith~app-store-reviews-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-fetchsmith-app-store-reviews-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/fetchsmith~app-store-reviews-scraper/runs": {
      "post": {
        "operationId": "runs-sync-fetchsmith-app-store-reviews-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/fetchsmith~app-store-reviews-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-fetchsmith-app-store-reviews-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "apps": {
            "title": "Apps",
            "type": "array",
            "description": "App Store URLs or numeric app IDs, e.g. https://apps.apple.com/us/app/notion/id1232780281 or 1232780281. Leading/trailing spaces are ignored. Leave empty if you use \"appNames\" instead.",
            "default": [
              "https://apps.apple.com/us/app/notion-notes-docs-tasks/id1232780281"
            ],
            "items": {
              "type": "string"
            }
          },
          "appNames": {
            "title": "App names (auto-resolve)",
            "type": "array",
            "description": "Free-text app names, e.g. \"Notion\". Each is resolved to an app id via Apple's search API and added to \"apps\". Apple's search almost never returns zero results (even gibberish gets an unrelated hit), so a name is only accepted if it shares a real word with the matched app's name/developer/bundle id — otherwise it's skipped with a \"no match found\" warning instead of silently using the wrong app. Prefer numeric app IDs or Store URLs when you need certainty.",
            "items": {
              "type": "string"
            }
          },
          "includeMacApps": {
            "title": "Also search the Mac App Store",
            "type": "boolean",
            "description": "When resolving \"appNames\", also search Mac App Store apps (Apple's app-name search is iOS-only by default, so Mac-only apps like Final Cut Pro are never found without this). Reviews for a Mac app are fetched the same way as for an iOS app. Not needed when you pass a numeric id or App Store URL in \"apps\" — those already work for Mac apps.",
            "default": false
          },
          "countries": {
            "title": "Countries",
            "type": "array",
            "description": "Storefront country codes to pull reviews from (each has its own reviews). Two-letter ISO-3166-1 alpha-2 codes — the UK is \"gb\", not \"uk\"; a code that isn't one fails the run immediately instead of returning nothing.",
            "default": [
              "us"
            ],
            "items": {
              "type": "string"
            }
          },
          "countryFallback": {
            "title": "Fall back to another storefront when a country is empty",
            "type": "boolean",
            "description": "Apple's review feed sometimes returns nothing for an app in one storefront while other storefronts have plenty. With this on, the Actor automatically retrieves that app's reviews from a storefront that does have them (rows carry the real 'country' plus 'requestedCountry' and 'fallbackUsed'), instead of finishing with zero results.",
            "default": false
          },
          "sort": {
            "title": "Sort",
            "enum": [
              "mostRecent",
              "mostHelpful",
              "favorable",
              "critical"
            ],
            "type": "string",
            "description": "mostRecent or mostHelpful scan Apple's feed in that order and deliver rows as found. favorable/critical scan under mostRecent, then buffer and re-order the whole scanned set by star rating before delivery (favorable = 5-to-1, critical = 1-to-5, newest first within a tied rating) — cannot be combined with watchLabel. Apple's feed is sometimes empty for one sort order and full for the other on the very same app — if mostRecent/mostHelpful returns nothing, the Actor automatically retries under the other one, and every row records which order it came from in 'sortUsed'.",
            "default": "mostRecent"
          },
          "maxReviewsPerApp": {
            "title": "Max reviews per app per country",
            "minimum": 1,
            "maximum": 500,
            "type": "integer",
            "description": "Apple exposes up to 500 (10 pages of 50). Counted before the review filters (rating/keyword/length/votes/date) are applied — a low cap combined with a narrow filter can miss matches deeper in the feed (see README FAQ).",
            "default": 200
          },
          "includeAppInfo": {
            "title": "Include app metadata",
            "type": "boolean",
            "description": "Attach app name, developer, average rating and rating count to every review.",
            "default": true
          },
          "maxResults": {
            "title": "Max results (total)",
            "minimum": 1,
            "maximum": 50000,
            "type": "integer",
            "description": "Overall cap on the number of reviews across all apps and countries.",
            "default": 2000
          },
          "minRating": {
            "title": "Minimum star rating",
            "minimum": 1,
            "maximum": 5,
            "type": "integer",
            "description": "Only keep reviews with a star rating >= this (1-5)."
          },
          "maxRating": {
            "title": "Maximum star rating",
            "minimum": 1,
            "maximum": 5,
            "type": "integer",
            "description": "Only keep reviews with a star rating <= this (1-5)."
          },
          "keyword": {
            "title": "Keyword filter",
            "type": "string",
            "description": "Only keep reviews whose title or content contains this word/phrase (case-insensitive). Leading/trailing spaces are ignored. Accented letters are Unicode-normalized before matching, so \"café\" matches regardless of which Unicode form (composed or decomposed) you typed it in."
          },
          "minReviewLength": {
            "title": "Minimum review length (characters)",
            "minimum": 0,
            "type": "integer",
            "description": "Only keep reviews whose body text is at least this many characters. Counts the review body only (the title is a separate field), so one-word \"Great!\" reviews are dropped without discarding a short review that happens to have a long headline."
          },
          "reviewsAfter": {
            "title": "Reviews after (ISO date)",
            "type": "string",
            "description": "Only keep reviews posted on or after this date (e.g. 2026-01-01). Forces \"sort\" to mostRecent (Apple's date-ordered feed) and stops paging as soon as older reviews are reached, so a narrow window on a high-volume app doesn't scan/charge through hundreds of pages first."
          },
          "reviewsBefore": {
            "title": "Reviews before (ISO date)",
            "type": "string",
            "description": "Only keep reviews posted on or before this date (e.g. 2026-06-01). A bare date includes the whole of that day. Combine with \"Reviews after\" for a date range. Unlike \"Reviews after\" this cannot cut pagination short (the newest reviews sort first), so it filters rather than saves scanning."
          },
          "minVoteSum": {
            "title": "Minimum helpful votes (net)",
            "minimum": 0,
            "type": "integer",
            "description": "Only keep reviews with at least this many net helpful votes (Apple's im:voteSum). NOTE: Apple only populates vote counts on the \"mostHelpful\" feed — under sort \"mostRecent\" every review returns 0 votes, so set sort to mostHelpful when using this."
          },
          "minVoteCount": {
            "title": "Minimum total votes",
            "minimum": 0,
            "type": "integer",
            "description": "Only keep reviews with at least this many total helpfulness votes (Apple's im:voteCount, helpful + unhelpful). Same caveat as \"Minimum helpful votes\": populated on the \"mostHelpful\" feed only."
          },
          "watchLabel": {
            "title": "Watch label (alert mode)",
            "type": "string",
            "description": "Set a name (e.g. \"my-app-reviews\") to turn this run into a watch: the FIRST run for a given label + filter set records which reviews already exist and returns nothing (0 charged). Every run after that returns only reviews posted since the last run under the same label, so you can schedule this Actor and get alerted on new reviews without re-paying for ones you already have. Changing any filter (apps/appNames/countries/countryFallback/sort/minRating/maxRating/keyword/minReviewLength/reviewsAfter/reviewsBefore/minVoteSum/minVoteCount) starts a fresh baseline. Leave empty for normal one-off runs."
          },
          "watchEvents": {
            "title": "Watch events to report",
            "type": "array",
            "description": "Optional. Only report these kinds of change in watch mode — e.g. pick \"Star rating edited\" alone to be alerted only when an existing reviewer downgrades or upgrades their score, and never pay for anything else. Leave empty for both. Apple lets a reviewer edit a review in place (same review id, the feed's own \"updated\" date advances) — without this event an already-delivered review that later drops from 5★ to 1★ is invisible to a watch forever. There is no developer-reply field anywhere in this review feed (unlike Google Play), so that is not an event this Actor can offer. Score-change events compare against the rating recorded the last time the review was delivered, so they only start firing on the second run after a baseline created before this feature existed. Ignored when \"Watch label\" is empty.",
            "items": {
              "type": "string",
              "enum": [
                "new",
                "scoreChanged"
              ],
              "enumTitles": [
                "New review",
                "Star rating edited (reviewer changed their own score)"
              ]
            },
            "default": []
          },
          "webhookUrl": {
            "title": "Webhook URL (notify on completion)",
            "type": "string",
            "description": "Optional. An http(s) URL to POST a small JSON summary to when the run finishes — reviews pushed, watch-label new count if Watch label is set, and the run's dataset ID so you can fetch the results. A convenience for callers who want a completion ping without setting up an Apify platform webhook (which needs separate Console/API configuration per Task, not per run). Best-effort: a failed or slow webhook is logged as a warning and never fails the run or affects charging — it fires after every review has already been pushed and charged. Leave empty to skip."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}