{
  "data": {
    "id": "5sUVXMCnWoObzQLM5",
    "actId": "XWYg10KEeEDb00gfo",
    "userId": "IYgBDiXtHOijAaUel",
    "startedAt": "2026-11-11T11:10:15.401Z",
    "finishedAt": "2026-11-11T11:10:26.627Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 11140,
      "runTimeSecs": 11.14,
      "computeUnits": 0.012377777777777777,
      "imageSizeBytes": 319110144
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "QYo53EZkJk0prePWY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"Google Workspace Marketplace App Review Extractor Input\",\n  \"description\": \"Extract public reviews for one or more Google Workspace Marketplace apps by App ID or app URL. No login, API key or proxy needed.\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"appIds\": {\n      \"title\": \"App IDs or app URLs\",\n      \"type\": \"array\",\n      \"editor\": \"stringList\",\n      \"description\": \"One or more Google Workspace Marketplace apps. Paste numeric App IDs (e.g. 539341275670) or full app URLs. Duplicate IDs are removed automatically.\",\n      \"sectionCaption\": \"Apps\",\n      \"sectionDescription\": \"Each app is scraped separately and its reviews are combined in one dataset.\",\n      \"prefill\": [\n        \"539341275670\"\n      ],\n      \"items\": {\n        \"type\": \"string\"\n      }\n    },\n    \"sortBy\": {\n      \"title\": \"Sort reviews by\",\n      \"type\": \"string\",\n      \"description\": \"Most relevant and Most helpful use Google's helpful ranking. Newest uses the date ranking. Highest rated and Lowest rated sort the fetched reviews in the actor; increase Max reviews per app to widen the window.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"MostRelevant\",\n        \"MostHelpful\",\n        \"Newest\",\n        \"HighestRated\",\n        \"LowestRated\"\n      ],\n      \"enumTitles\": [\n        \"Most relevant (Google default)\",\n        \"Most helpful first\",\n        \"Newest first\",\n        \"Highest rated first\",\n        \"Lowest rated first\"\n      ],\n      \"default\": \"MostRelevant\",\n      \"prefill\": \"MostRelevant\",\n      \"sectionCaption\": \"Review filters\",\n      \"sectionDescription\": \"All filters are applied to the reviews that the Marketplace serves for the selected language.\"\n    },\n    \"reviewLanguage\": {\n      \"title\": \"Review language\",\n      \"type\": \"string\",\n      \"description\": \"The Marketplace serves reviews one language at a time. Pick a language for a complete slice, or All languages for the mixed stream the site shows under 'All languages'.\",\n      \"editor\": \"select\",\n      \"enum\": [\n        \"en\",\n        \"all\",\n        \"de\",\n        \"es\",\n        \"fr\",\n        \"pt-BR\",\n        \"it\",\n        \"ru\",\n        \"ja\",\n        \"ko\",\n        \"zh-CN\",\n        \"zh-TW\",\n        \"id\",\n        \"vi\",\n        \"nl\",\n        \"pl\",\n        \"tr\",\n        \"ar\",\n        \"hi\",\n        \"th\",\n        \"he\",\n        \"uk\",\n        \"sv\",\n        \"da\",\n        \"fi\",\n        \"no\",\n        \"cs\",\n        \"hu\",\n        \"fil\"\n      ],\n      \"enumTitles\": [\n        \"English\",\n        \"All languages (mixed stream)\",\n        \"German\",\n        \"Spanish\",\n        \"French\",\n        \"Portuguese (Brazil)\",\n        \"Italian\",\n        \"Russian\",\n        \"Japanese\",\n        \"Korean\",\n        \"Chinese (Simplified)\",\n        \"Chinese (Traditional)\",\n        \"Indonesian\",\n        \"Vietnamese\",\n        \"Dutch\",\n        \"Polish\",\n        \"Turkish\",\n        \"Arabic\",\n        \"Hindi\",\n        \"Thai\",\n        \"Hebrew\",\n        \"Ukrainian\",\n        \"Swedish\",\n        \"Danish\",\n        \"Finnish\",\n        \"Norwegian\",\n        \"Czech\",\n        \"Hungarian\",\n        \"Filipino\"\n      ],\n      \"default\": \"en\",\n      \"prefill\": \"en\"\n    },\n    \"minRating\": {\n      \"title\": \"Minimum star rating\",\n      \"type\": \"integer\",\n      \"description\": \"Only include reviews with this rating or higher (1-5). Leave empty for all ratings.\",\n      \"minimum\": 1,\n      \"maximum\": 5\n    },\n    \"maxRating\": {\n      \"title\": \"Maximum star rating\",\n      \"type\": \"integer\",\n      \"description\": \"Only include reviews with this rating or lower (1-5). Use 2 to collect complaints only. Leave empty for all ratings.\",\n      \"minimum\": 1,\n      \"maximum\": 5\n    },\n    \"sinceDate\": {\n      \"title\": \"Reviews from\",\n      \"type\": \"string\",\n      \"editor\": \"textfield\",\n      \"description\": \"Only reviews posted on or after this date. Use an ISO date (2026-01-01), an ISO datetime, or a relative period such as '30 days', '2 weeks' or '6 months'.\"\n    },\n    \"untilDate\": {\n      \"title\": \"Reviews until\",\n      \"type\": \"string\",\n      \"editor\": \"textfield\",\n      \"description\": \"Only reviews posted on or before this date. Use an ISO date (2026-12-31) or an ISO datetime. A bare date includes the whole day.\"\n    },\n    \"reviewKeyword\": {\n      \"title\": \"Review text contains\",\n      \"type\": \"string\",\n      \"editor\": \"textfield\",\n      \"description\": \"Case-insensitive text that must appear in the review. Useful for complaints, feature names or product terms. Leave empty for all reviews.\"\n    },\n    \"maxItems\": {\n      \"title\": \"Max reviews (total)\",\n      \"type\": \"integer\",\n      \"description\": \"Maximum number of reviews to save across all apps.\",\n      \"minimum\": 1,\n      \"maximum\": 5000,\n      \"default\": 100,\n      \"prefill\": 3,\n      \"sectionCaption\": \"Output limits\",\n      \"sectionDescription\": \"Caps keep runs fast and predictable. Unused slots are offered to the next app.\"\n    },\n    \"maxReviewsPerApp\": {\n      \"title\": \"Max reviews per app\",\n      \"type\": \"integer\",\n      \"description\": \"Maximum reviews to save for any single app. Raise this to scan deeper for sparse filters or rating sorts.\",\n      \"minimum\": 1,\n      \"maximum\": 2000,\n      \"default\": 2000,\n      \"prefill\": 3\n    }\n  },\n  \"required\": []\n}",
    "readme": "# Google Workspace Marketplace App Review Extractor\n\nCollect the public user reviews of any Google Workspace Marketplace app - stars, review text, date, reviewer, helpful votes and the developer's replies - for one app or a whole watchlist. No Google account, cookie, API key or proxy is needed.\n\nThe actor paginates the public review list and deduplicates overlapping pages, so a request for 100 reviews returns 100 unique reviews instead of repeated first-page rows.\n\n## What this actor does\n\n- **One row per review** - rating, text, date, reviewer, helpful votes and developer replies\n- **Multiple apps** - pass app IDs or full Marketplace URLs in one run\n- **Pagination** - follows the public review list page by page and removes duplicates\n- **Filters** - rating range, date window and review-text keyword\n- **Languages** - 28 Marketplace language slices or the mixed \"All languages\" stream\n- **App context** - developer, listing rating, exact installs, pricing class, icon and links\n- **Empty fields are omitted** - never `null`, blank or placeholder values\n\n## Output per review\n\nOne row per review:\n\n| Field | Meaning |\n|---|---|\n| `reviewId` | Marketplace review identifier |\n| `appId`, `appName`, `appUrl`, `sourceUrl` | App identity and listing URL |\n| `rating` | 1-5 stars |\n| `reviewText` | Review body (omitted for rating-only reviews) |\n| `reviewDate`, `reviewTimestamp` | Posting date and full UTC timestamp |\n| `reviewerName`, `reviewerAvatarUrl` | Public reviewer identity and avatar |\n| `helpfulCount` | Other users' helpful votes |\n| `reviewLanguage` | Language slice when a specific language is requested |\n| `developerReply`, `developerReplyDate`, `developerReplyTimestamp`, `developerReplyAuthor` | Latest developer reply |\n| `developerReplies[]` | Every reply on the review (`text`, `date`, `timestamp`, `author`, `avatarUrl`, `replyId`) |\n| `hasDeveloperReply`, `replyCount` | Reply flags |\n| `appDeveloper`, `appDeveloperWebsite` | Publisher identity |\n| `appRating`, `appReviewCount`, `appInstallCount`, `appInstallsLabel` | Listing rating, rating count and exact installs |\n| `appPricingModel` | Free, Free trial, Freemium or Paid (omitted when unpublished) |\n| `appIconUrl`, `appWorksWith[]`, `appLastUpdated` | Listing media, Google apps it plugs into, last update date |\n| `appTermsUrl`, `appPrivacyUrl`, `appSupportUrl`, `appWebsiteUrl` | Published listing links |\n| `recordType`, `scrapedAt` | Record marker and scrape time |\n\nEmpty values are omitted at every depth, so every row contains only real data.\n\n## Input\n\n| Input | Default | What it does |\n|---|---|---|\n| `appIds` | `[\"539341275670\"]` | App IDs or full Marketplace URLs. Duplicates are removed. Legacy saved tasks that send a single `appId` still work. |\n| `maxItems` | `100` | Total reviews saved across all apps. |\n| `maxReviewsPerApp` | `2000` | Hard per-app ceiling; unused slots are offered to the next app. |\n| `sortBy` | `MostRelevant` | `MostRelevant` / `MostHelpful` use Google's helpful ranking; `Newest` uses the date ranking; `HighestRated` / `LowestRated` sort the fetched reviews. |\n| `reviewLanguage` | `en` | 28 Marketplace language slices, or `all` for the site's mixed \"All languages\" stream. |\n| `minRating`, `maxRating` | - | Star range (1-5). `maxRating: 2` keeps complaints only. |\n| `sinceDate`, `untilDate` | - | ISO date/datetime, or a relative period such as `30 days`, `2 weeks`, `6 months`. |\n| `reviewKeyword` | - | Case-insensitive text that must appear in the review. |\n\nOnly `appIds` (or the legacy `appId`) is needed. Everything else has a working default.\n\n### Examples\n\nOne app, newest first:\n\n```json\n{\n  \"appIds\": [\"539341275670\"],\n  \"maxItems\": 100,\n  \"sortBy\": \"Newest\"\n}\n```\n\nA watchlist of IDs and URLs, complaints from the last 90 days:\n\n```json\n{\n  \"appIds\": [\n    \"539341275670\",\n    \"https://workspace.google.com/marketplace/app/form_presenter+timer/93519377337\"\n  ],\n  \"maxItems\": 200,\n  \"maxReviewsPerApp\": 100,\n  \"maxRating\": 2,\n  \"sinceDate\": \"90 days\"\n}\n```\n\nGerman reviews that mention a specific word:\n\n```json\n{\n  \"appIds\": [\"218858140171\"],\n  \"reviewLanguage\": \"de\",\n  \"reviewKeyword\": \"Rechnung\",\n  \"maxItems\": 50\n}\n```\n\n## Reliability and coverage\n\n- **Pagination** stops at the source total, repeated pages with no new review IDs, the per-app cap, or a safety page cap. Review IDs are deduplicated, so page overlap never produces duplicate rows.\n- **Replies** are attached to the reviews that carry them.\n- **Rating, date and keyword filters** are applied to the fetched reviews. Restrictive filters scan more pages automatically; raise `maxReviewsPerApp` for deeper history.\n- **Network errors** are retried on 429/5xx. A bad App ID is skipped with a clear status message, and the remaining apps still run.\n- **No proxy, no cookies**: no account, login, cookie, API key or proxy setup is needed.\n\n## Use cases\n\n- **App due diligence** - read recent complaints and developer responses before adopting an add-on\n- **Review monitoring** - track new reviews for a watchlist of Marketplace apps\n- **Competitive research** - compare ratings, installs and feedback across similar apps\n- **Product quality** - surface recurring issues by rating, date or keyword\n- **Localization QA** - inspect reviews in a specific language slice\n\n## FAQ\n\n**How many reviews can I collect?** Up to 2,000 per app (`maxReviewsPerApp`) and up to 5,000 per run (`maxItems`). The Marketplace serves text reviews in 10-review pages; rating-only reviews have no body and are not part of the text review total.\n\n**Why does an app show thousands of ratings but fewer text reviews?** The listing's rating count includes rating-only reviews. The review service returns reviews with text, split by language. Both numbers are real.\n\n**Why pick a language?** The site serves one language slice at a time. `reviewLanguage` gives the complete slice for that language. `all` uses the site's mixed \"All languages\" stream, whose total can be shorter than the sum of the individual language slices.\n\n**Are review names always present?** Most reviews show a public name and avatar; some are anonymous. Those fields are omitted rather than filled with a placeholder.\n\n**Do all apps have developer replies?** Replies are shown when the developer posted one. They are attached to the reviews that carry them; the actor never invents a reply.\n\n**Are `HighestRated` and `LowestRated` real Marketplace sorts?** The Marketplace only offers helpful and newest ordering. The actor fetches newest reviews and sorts that window by stars. Increase `maxReviewsPerApp` to widen the window.\n\n**Can I search for apps by keyword?** This actor takes app IDs or URLs. Keyword app discovery is a separate Marketplace surface; use the ID from any app URL.\n\n**Can I monitor new reviews?** Use `sinceDate` (for example `7 days`) on a schedule; the actor returns only reviews in that window. Cross-run \"new since last run\" state is not part of this extractor.\n\n**A URL field looks broken?** App icons, banners and reviewer avatars are public `lh3.googleusercontent.com` URLs and return images without cookies. Listing pages are public HTML. If an app's own terms/privacy/support link is dead, that is the publisher's link, not a scrape error.\n\n**What about an invalid App ID?** The Marketplace returns HTTP 400 for an unknown ID. The actor reports it in the status message and continues with the other apps.\n\n## Limitations\n\n- Caps are 2,000 reviews per app and 5,000 per run.\n- The Marketplace exposes two real server sorts; `HighestRated`/`LowestRated` sort the fetched window client-side.\n- Reviewer names, avatars and developer replies can be absent upstream; missing values are omitted, never filled.\n- Per-review permalinks are not published; `sourceUrl` is the app page.\n- Restrictive filters scan a bounded page budget; raise `maxReviewsPerApp` for deeper history.\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "google-workspace-marketplace-app-review-extractor",
      "title": "Google Workspace Marketplace App Review Extractor",
      "description": "Extract public Google Workspace Marketplace reviews for one or more apps by App ID or URL: star rating, review text, date, reviewer, helpful votes and developer replies, with language, rating, date and keyword filters plus correct pagination.",
      "version": "2.0",
      "buildTag": "latest",
      "dockerfile": "./Dockerfile",
      "readme": "# Google Workspace Marketplace App Review Extractor\n\nCollect the public user reviews of any Google Workspace Marketplace app - stars, review text, date, reviewer, helpful votes and the developer's replies - for one app or a whole watchlist. No Google account, cookie, API key or proxy is needed.\n\nThe actor paginates the public review list and deduplicates overlapping pages, so a request for 100 reviews returns 100 unique reviews instead of repeated first-page rows.\n\n## What this actor does\n\n- **One row per review** - rating, text, date, reviewer, helpful votes and developer replies\n- **Multiple apps** - pass app IDs or full Marketplace URLs in one run\n- **Pagination** - follows the public review list page by page and removes duplicates\n- **Filters** - rating range, date window and review-text keyword\n- **Languages** - 28 Marketplace language slices or the mixed \"All languages\" stream\n- **App context** - developer, listing rating, exact installs, pricing class, icon and links\n- **Empty fields are omitted** - never `null`, blank or placeholder values\n\n## Output per review\n\nOne row per review:\n\n| Field | Meaning |\n|---|---|\n| `reviewId` | Marketplace review identifier |\n| `appId`, `appName`, `appUrl`, `sourceUrl` | App identity and listing URL |\n| `rating` | 1-5 stars |\n| `reviewText` | Review body (omitted for rating-only reviews) |\n| `reviewDate`, `reviewTimestamp` | Posting date and full UTC timestamp |\n| `reviewerName`, `reviewerAvatarUrl` | Public reviewer identity and avatar |\n| `helpfulCount` | Other users' helpful votes |\n| `reviewLanguage` | Language slice when a specific language is requested |\n| `developerReply`, `developerReplyDate`, `developerReplyTimestamp`, `developerReplyAuthor` | Latest developer reply |\n| `developerReplies[]` | Every reply on the review (`text`, `date`, `timestamp`, `author`, `avatarUrl`, `replyId`) |\n| `hasDeveloperReply`, `replyCount` | Reply flags |\n| `appDeveloper`, `appDeveloperWebsite` | Publisher identity |\n| `appRating`, `appReviewCount`, `appInstallCount`, `appInstallsLabel` | Listing rating, rating count and exact installs |\n| `appPricingModel` | Free, Free trial, Freemium or Paid (omitted when unpublished) |\n| `appIconUrl`, `appWorksWith[]`, `appLastUpdated` | Listing media, Google apps it plugs into, last update date |\n| `appTermsUrl`, `appPrivacyUrl`, `appSupportUrl`, `appWebsiteUrl` | Published listing links |\n| `recordType`, `scrapedAt` | Record marker and scrape time |\n\nEmpty values are omitted at every depth, so every row contains only real data.\n\n## Input\n\n| Input | Default | What it does |\n|---|---|---|\n| `appIds` | `[\"539341275670\"]` | App IDs or full Marketplace URLs. Duplicates are removed. Legacy saved tasks that send a single `appId` still work. |\n| `maxItems` | `100` | Total reviews saved across all apps. |\n| `maxReviewsPerApp` | `2000` | Hard per-app ceiling; unused slots are offered to the next app. |\n| `sortBy` | `MostRelevant` | `MostRelevant` / `MostHelpful` use Google's helpful ranking; `Newest` uses the date ranking; `HighestRated` / `LowestRated` sort the fetched reviews. |\n| `reviewLanguage` | `en` | 28 Marketplace language slices, or `all` for the site's mixed \"All languages\" stream. |\n| `minRating`, `maxRating` | - | Star range (1-5). `maxRating: 2` keeps complaints only. |\n| `sinceDate`, `untilDate` | - | ISO date/datetime, or a relative period such as `30 days`, `2 weeks`, `6 months`. |\n| `reviewKeyword` | - | Case-insensitive text that must appear in the review. |\n\nOnly `appIds` (or the legacy `appId`) is needed. Everything else has a working default.\n\n### Examples\n\nOne app, newest first:\n\n```json\n{\n  \"appIds\": [\"539341275670\"],\n  \"maxItems\": 100,\n  \"sortBy\": \"Newest\"\n}\n```\n\nA watchlist of IDs and URLs, complaints from the last 90 days:\n\n```json\n{\n  \"appIds\": [\n    \"539341275670\",\n    \"https://workspace.google.com/marketplace/app/form_presenter+timer/93519377337\"\n  ],\n  \"maxItems\": 200,\n  \"maxReviewsPerApp\": 100,\n  \"maxRating\": 2,\n  \"sinceDate\": \"90 days\"\n}\n```\n\nGerman reviews that mention a specific word:\n\n```json\n{\n  \"appIds\": [\"218858140171\"],\n  \"reviewLanguage\": \"de\",\n  \"reviewKeyword\": \"Rechnung\",\n  \"maxItems\": 50\n}\n```\n\n## Reliability and coverage\n\n- **Pagination** stops at the source total, repeated pages with no new review IDs, the per-app cap, or a safety page cap. Review IDs are deduplicated, so page overlap never produces duplicate rows.\n- **Replies** are attached to the reviews that carry them.\n- **Rating, date and keyword filters** are applied to the fetched reviews. Restrictive filters scan more pages automatically; raise `maxReviewsPerApp` for deeper history.\n- **Network errors** are retried on 429/5xx. A bad App ID is skipped with a clear status message, and the remaining apps still run.\n- **No proxy, no cookies**: no account, login, cookie, API key or proxy setup is needed.\n\n## Use cases\n\n- **App due diligence** - read recent complaints and developer responses before adopting an add-on\n- **Review monitoring** - track new reviews for a watchlist of Marketplace apps\n- **Competitive research** - compare ratings, installs and feedback across similar apps\n- **Product quality** - surface recurring issues by rating, date or keyword\n- **Localization QA** - inspect reviews in a specific language slice\n\n## FAQ\n\n**How many reviews can I collect?** Up to 2,000 per app (`maxReviewsPerApp`) and up to 5,000 per run (`maxItems`). The Marketplace serves text reviews in 10-review pages; rating-only reviews have no body and are not part of the text review total.\n\n**Why does an app show thousands of ratings but fewer text reviews?** The listing's rating count includes rating-only reviews. The review service returns reviews with text, split by language. Both numbers are real.\n\n**Why pick a language?** The site serves one language slice at a time. `reviewLanguage` gives the complete slice for that language. `all` uses the site's mixed \"All languages\" stream, whose total can be shorter than the sum of the individual language slices.\n\n**Are review names always present?** Most reviews show a public name and avatar; some are anonymous. Those fields are omitted rather than filled with a placeholder.\n\n**Do all apps have developer replies?** Replies are shown when the developer posted one. They are attached to the reviews that carry them; the actor never invents a reply.\n\n**Are `HighestRated` and `LowestRated` real Marketplace sorts?** The Marketplace only offers helpful and newest ordering. The actor fetches newest reviews and sorts that window by stars. Increase `maxReviewsPerApp` to widen the window.\n\n**Can I search for apps by keyword?** This actor takes app IDs or URLs. Keyword app discovery is a separate Marketplace surface; use the ID from any app URL.\n\n**Can I monitor new reviews?** Use `sinceDate` (for example `7 days`) on a schedule; the actor returns only reviews in that window. Cross-run \"new since last run\" state is not part of this extractor.\n\n**A URL field looks broken?** App icons, banners and reviewer avatars are public `lh3.googleusercontent.com` URLs and return images without cookies. Listing pages are public HTML. If an app's own terms/privacy/support link is dead, that is the publisher's link, not a scrape error.\n\n**What about an invalid App ID?** The Marketplace returns HTTP 400 for an unknown ID. The actor reports it in the status message and continues with the other apps.\n\n## Limitations\n\n- Caps are 2,000 reviews per app and 5,000 per run.\n- The Marketplace exposes two real server sorts; `HighestRated`/`LowestRated` sort the fetched window client-side.\n- Reviewer names, avatars and developer replies can be absent upstream; missing values are omitted, never filled.\n- Per-review permalinks are not published; `sourceUrl` is the app page.\n- Restrictive filters scan a bounded page budget; raise `maxReviewsPerApp` for deeper history.\n",
      "input": {
        "title": "Google Workspace Marketplace App Review Extractor Input",
        "description": "Extract public reviews for one or more Google Workspace Marketplace apps by App ID or app URL. No login, API key or proxy needed.",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "appIds": {
            "title": "App IDs or app URLs",
            "type": "array",
            "editor": "stringList",
            "description": "One or more Google Workspace Marketplace apps. Paste numeric App IDs (e.g. 539341275670) or full app URLs. Duplicate IDs are removed automatically.",
            "sectionCaption": "Apps",
            "sectionDescription": "Each app is scraped separately and its reviews are combined in one dataset.",
            "prefill": [
              "539341275670"
            ],
            "items": {
              "type": "string"
            }
          },
          "sortBy": {
            "title": "Sort reviews by",
            "type": "string",
            "description": "Most relevant and Most helpful use Google's helpful ranking. Newest uses the date ranking. Highest rated and Lowest rated sort the fetched reviews in the actor; increase Max reviews per app to widen the window.",
            "editor": "select",
            "enum": [
              "MostRelevant",
              "MostHelpful",
              "Newest",
              "HighestRated",
              "LowestRated"
            ],
            "enumTitles": [
              "Most relevant (Google default)",
              "Most helpful first",
              "Newest first",
              "Highest rated first",
              "Lowest rated first"
            ],
            "default": "MostRelevant",
            "prefill": "MostRelevant",
            "sectionCaption": "Review filters",
            "sectionDescription": "All filters are applied to the reviews that the Marketplace serves for the selected language."
          },
          "reviewLanguage": {
            "title": "Review language",
            "type": "string",
            "description": "The Marketplace serves reviews one language at a time. Pick a language for a complete slice, or All languages for the mixed stream the site shows under 'All languages'.",
            "editor": "select",
            "enum": [
              "en",
              "all",
              "de",
              "es",
              "fr",
              "pt-BR",
              "it",
              "ru",
              "ja",
              "ko",
              "zh-CN",
              "zh-TW",
              "id",
              "vi",
              "nl",
              "pl",
              "tr",
              "ar",
              "hi",
              "th",
              "he",
              "uk",
              "sv",
              "da",
              "fi",
              "no",
              "cs",
              "hu",
              "fil"
            ],
            "enumTitles": [
              "English",
              "All languages (mixed stream)",
              "German",
              "Spanish",
              "French",
              "Portuguese (Brazil)",
              "Italian",
              "Russian",
              "Japanese",
              "Korean",
              "Chinese (Simplified)",
              "Chinese (Traditional)",
              "Indonesian",
              "Vietnamese",
              "Dutch",
              "Polish",
              "Turkish",
              "Arabic",
              "Hindi",
              "Thai",
              "Hebrew",
              "Ukrainian",
              "Swedish",
              "Danish",
              "Finnish",
              "Norwegian",
              "Czech",
              "Hungarian",
              "Filipino"
            ],
            "default": "en",
            "prefill": "en"
          },
          "minRating": {
            "title": "Minimum star rating",
            "type": "integer",
            "description": "Only include reviews with this rating or higher (1-5). Leave empty for all ratings.",
            "minimum": 1,
            "maximum": 5
          },
          "maxRating": {
            "title": "Maximum star rating",
            "type": "integer",
            "description": "Only include reviews with this rating or lower (1-5). Use 2 to collect complaints only. Leave empty for all ratings.",
            "minimum": 1,
            "maximum": 5
          },
          "sinceDate": {
            "title": "Reviews from",
            "type": "string",
            "editor": "textfield",
            "description": "Only reviews posted on or after this date. Use an ISO date (2026-01-01), an ISO datetime, or a relative period such as '30 days', '2 weeks' or '6 months'."
          },
          "untilDate": {
            "title": "Reviews until",
            "type": "string",
            "editor": "textfield",
            "description": "Only reviews posted on or before this date. Use an ISO date (2026-12-31) or an ISO datetime. A bare date includes the whole day."
          },
          "reviewKeyword": {
            "title": "Review text contains",
            "type": "string",
            "editor": "textfield",
            "description": "Case-insensitive text that must appear in the review. Useful for complaints, feature names or product terms. Leave empty for all reviews."
          },
          "maxItems": {
            "title": "Max reviews (total)",
            "type": "integer",
            "description": "Maximum number of reviews to save across all apps.",
            "minimum": 1,
            "maximum": 5000,
            "default": 100,
            "prefill": 3,
            "sectionCaption": "Output limits",
            "sectionDescription": "Caps keep runs fast and predictable. Unused slots are offered to the next app."
          },
          "maxReviewsPerApp": {
            "title": "Max reviews per app",
            "type": "integer",
            "description": "Maximum reviews to save for any single app. Raise this to scan deeper for sparse filters or rating sorts.",
            "minimum": 1,
            "maximum": 2000,
            "default": 2000,
            "prefill": 3
          }
        },
        "required": []
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "Google Workspace Marketplace App Review Extractor Output",
        "description": "One row per Google Workspace Marketplace review with stars, text, date, reviewer, helpful votes, developer replies and app context.",
        "properties": {
          "reviews": {
            "type": "string",
            "title": "App reviews",
            "description": "Dataset containing every scraped review. Each row also carries the app's name, developer, rating, install count, pricing model and other listing context.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          }
        }
      },
      "defaultRunOptions": {
        "memoryMbytes": 1024,
        "timeoutSecs": 3600
      },
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "views": {
            "overview": {
              "title": "App Reviews",
              "transformation": {
                "fields": [
                  "reviewId",
                  "appName",
                  "appId",
                  "rating",
                  "reviewText",
                  "reviewDate",
                  "reviewerName",
                  "helpfulCount",
                  "hasDeveloperReply",
                  "reviewLanguage",
                  "scrapedAt"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "reviewId": {
                    "label": "Review ID",
                    "format": "text"
                  },
                  "appName": {
                    "label": "App",
                    "format": "text"
                  },
                  "appId": {
                    "label": "App ID",
                    "format": "text"
                  },
                  "rating": {
                    "label": "Stars",
                    "format": "number"
                  },
                  "reviewText": {
                    "label": "Review",
                    "format": "text"
                  },
                  "reviewDate": {
                    "label": "Date",
                    "format": "text"
                  },
                  "reviewerName": {
                    "label": "Reviewer",
                    "format": "text"
                  },
                  "helpfulCount": {
                    "label": "Helpful",
                    "format": "number"
                  },
                  "hasDeveloperReply": {
                    "label": "Reply",
                    "format": "boolean"
                  },
                  "reviewLanguage": {
                    "label": "Language",
                    "format": "text"
                  },
                  "scrapedAt": {
                    "label": "Scraped at",
                    "format": "text"
                  }
                }
              }
            }
          }
        }
      }
    },
    "buildNumber": "2.0.1",
    "imageDigest": "6cf520f6a0f9bbd18f4aec411c88ea5c0d74ed8aa57035495808637cf74734d5",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "2.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.012377777777777777
    }
  }
}