{
  "openapi": "3.0.1",
  "info": {
    "title": "Trustpilot Scraper: Reviews + Company Contacts, from $0.50/1K",
    "description": "Scrape Trustpilot reviews, company ratings and public contact details (email, phone, address). Discover companies by category and country for lead generation. Handles the language filter that hides most reviews of non-English companies. No login, no cookies.",
    "version": "0.2",
    "x-build-id": "noOzZVxLckT5e2gXJ"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/alexmorain~trustpilot-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-alexmorain-trustpilot-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/alexmorain~trustpilot-scraper/runs": {
      "post": {
        "operationId": "runs-sync-alexmorain-trustpilot-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/alexmorain~trustpilot-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-alexmorain-trustpilot-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": {
          "companyDomains": {
            "title": "Company domains",
            "type": "array",
            "description": "One company per line. Two accepted forms, freely mixed:<br>• the <b>domain</b> as Trustpilot knows it: <code>www.qonto.com</code>, <code>keobiz.fr</code><br>• the full <b>Trustpilot profile URL</b>: <code>https://www.trustpilot.com/review/www.qonto.com</code><br><br><b>Getting the domain right matters:</b> Trustpilot keys profiles on the exact domain, and <code>qonto.com</code> and <code>www.qonto.com</code> can be two different pages. The safe move is to search the company on Trustpilot and paste the profile URL straight from your browser; the Actor extracts the domain from it.<br><br>Leave empty if you are discovering companies by category instead.",
            "items": {
              "type": "string"
            }
          },
          "categorySlugs": {
            "title": "Category slugs",
            "type": "array",
            "description": "Trustpilot category slugs to discover companies from, one per line: <code>accountant</code>, <code>bank</code>, <code>insurance_agency</code>.<br><br><b>Where to find a slug:</b> browse the Trustpilot categories, open the one you want, and take the last part of the URL, <code>trustpilot.com/categories/<b>accountant</b></code>. Underscores are part of the slug.<br><br>You get one row per company, with name, domain, score and review count: a ready-made prospect list for an industry. Combine with the country filter below to make it local.",
            "items": {
              "type": "string"
            }
          },
          "country": {
            "title": "Country (category discovery only)",
            "type": "string",
            "description": "ISO country code used to filter category results: <code>FR</code>, <code>GB</code>, <code>US</code>, <code>DE</code>.<br><br>Only applies to category discovery, and ignored when you scrape company reviews. Leave empty to get the companies of every country."
          },
          "mode": {
            "title": "Mode",
            "enum": [
              "auto",
              "company",
              "category"
            ],
            "type": "string",
            "description": "<b>Leave this on Auto.</b> Auto picks the job from what you filled in: company domains means reviews, category slugs means discovery. With both fields filled, Auto runs both jobs, company reviews first, then category discovery. Set it by hand only to run one of the two from a saved task that keeps both fields filled: <code>company</code> ignores the category slugs, <code>category</code> ignores the company domains.",
            "default": "auto"
          },
          "maxReviewsPerCompany": {
            "title": "Max reviews per company",
            "minimum": 1,
            "type": "integer",
            "description": "Upper bound on reviews collected per company.<br><br><b>Read this before setting a big number.</b> Trustpilot serves at most 200 reviews for any single request, however many thousands it advertises on the page. Above 200 this Actor splits the profile into disjoint rating and language cells and walks each one, which typically brings a 4,500-review profile to 700 or 800 rather than 200. It cannot return the full corpus, because Trustpilot does not serve it, and no scraper can.<br><br>So: <code>200</code> is one fast pass, <code>1000</code> triggers the segmentation and takes noticeably longer for roughly three to four times more reviews. Without a review filter, the run log states what was collected against the advertised total; with a filter it does not, because Trustpilot only advertises the total of the whole profile.",
            "default": 200
          },
          "maxCompaniesPerCategory": {
            "title": "Max companies per category",
            "minimum": 1,
            "type": "integer",
            "description": "Upper bound on companies returned per category, paged 20 at a time. Only applies to category discovery.<br><br>Trustpilot caps its own category listings, so a category often holds a few dozen to a few hundred companies whatever you ask for. The log states the total it found.",
            "default": 100
          },
          "languages": {
            "title": "Review languages",
            "type": "string",
            "description": "Which review languages to collect. <code>all</code>, the default, returns every review whatever its language. A single code such as <code>fr</code> or <code>en</code> returns only that one.<br><br><b>Leave it on <code>all</code> unless you have a specific reason.</b> Trustpilot's own default hides reviews written in other languages, and that quietly guts the result: a French company with 200 reviews can show a single one. Restrict this only when you feed a downstream tool that handles one language.",
            "default": "all"
          },
          "stars": {
            "title": "Star ratings",
            "type": "array",
            "description": "Keep only reviews with these star ratings. Leave empty for every rating, which is the default.<br><br>Example: <code>[1, 2]</code> for the complaints, the usual input of a support or reputation team.<br><br>Filtered by Trustpilot itself, so you never pay for the reviews left out. Above 200 reviews, the rating and language segmentation that gets past Trustpilot's 10-page wall still applies, restricted to the ratings you picked.",
            "items": {
              "type": "integer",
              "minimum": 1,
              "maximum": 5
            }
          },
          "lastDays": {
            "title": "Only reviews from the last N days",
            "minimum": 1,
            "maximum": 3650,
            "type": "integer",
            "description": "Keep only reviews published in the last N days, for example <code>7</code> in a weekly scheduled run. This is the input for reputation monitoring: schedule the Actor, get only what is new.<br><br>The Actor sorts by date and <b>stops paging at the first older review</b>, so a weekly run on a big profile is a single page or two. Trustpilot narrows the search too (last 30 days, 3, 6 or 12 months), and the exact cut-off is applied review by review by the Actor: you are only charged for the reviews returned, while the run time follows the pages read, which the early stop keeps short.<br><br>If you also set <code>publishedAfter</code>, the more recent of the two dates wins."
          },
          "publishedAfter": {
            "title": "Only reviews published after",
            "type": "string",
            "description": "Keep only reviews published on or after this date, <code>YYYY-MM-DD</code>, read as midnight UTC. Same mechanism as <code>lastDays</code>, with a fixed date instead of a rolling window.<br><br>With <code>sortBy</code> set to <code>relevance</code> the Actor cannot stop at the first older review: it still returns only the reviews after the date, but has to page through the rest of the window to find them. You are only charged for the reviews returned, but a longer scan means a longer run."
          },
          "verifiedOnly": {
            "title": "Verified reviews only",
            "type": "boolean",
            "description": "Keep only reviews Trustpilot labels as verified, meaning written after a confirmed purchase or service. Filtered by Trustpilot itself, so the reviews left out are neither fetched nor charged.",
            "default": false
          },
          "withRepliesOnly": {
            "title": "Reviews with a company reply only",
            "type": "boolean",
            "description": "Keep only reviews the company has answered. Useful to audit how a competitor handles complaints. Filtered by Trustpilot itself, so the reviews left out are neither fetched nor charged.",
            "default": false
          },
          "sortBy": {
            "title": "Sort order",
            "enum": [
              "recency",
              "relevance"
            ],
            "type": "string",
            "description": "<code>recency</code>, the default, returns the newest reviews first. <code>relevance</code> uses Trustpilot's own ranking, the order a visitor sees on the profile.<br><br>Keep <code>recency</code> with a date filter: it is what lets the Actor stop paging early.",
            "default": "recency"
          },
          "reviewMode": {
            "title": "Reviews to return",
            "enum": [
              "all",
              "new-only"
            ],
            "type": "string",
            "description": "<b>All matching reviews</b>, the default, returns every review that matches your input, on every run. Use it for a one-off export or to build your first snapshot.<br><br><b>New reviews only</b> keeps, for each company, a persistent registry of every review previous runs already delivered, and returns only the ones never delivered before. Because the registry is per company, you can add companies to a running schedule without paying again for the ones you already follow. Schedule it daily or weekly and you get a feed of fresh reviews: a review you are not shown is a review you are not charged for. The first run in this mode still returns everything it reads, because nothing has been delivered yet.<br><br>What a run still costs on a quiet day: the run fee, plus one company record per company, since the profile (score, review count, contact block) is refreshed on every run. Only reviews are de-duplicated; category discovery is unchanged.<br><br><b>Max reviews per company</b> still caps the reviews <i>read</i>, newest first: the Actor reads that many and returns the unseen ones among them. Pair this mode with <code>lastDays</code> to keep each run to a page or two.",
            "default": "all"
          },
          "registryKey": {
            "title": "Delta registry key",
            "type": "string",
            "description": "Only used by <b>New reviews only</b>. Names the feed: each company in it keeps its own registry of reviews already delivered.<br><br>Leave empty and the feed is derived from the filters that change which reviews qualify (<code>stars</code>, <code>verifiedOnly</code>, <code>withRepliesOnly</code>, <code>languages</code>). That is what you want: the same input always finds its registries again, and two feeds with different filters never pollute each other. Changing <code>lastDays</code>, <code>publishedAfter</code>, <code>sortBy</code>, <b>Max reviews per company</b> or the category fields keeps the same registries, and so does adding or removing a company.<br><br>Set it by hand to name the feed yourself: it replaces the filters, still with one registry per company. Two different keys never share anything; a new key starts over from empty registries."
          },
          "webhookUrl": {
            "title": "Webhook URL",
            "type": "string",
            "description": "If set, the Actor POSTs a small JSON summary to this URL once the scraping is over, whatever the outcome (not when the input is rejected, nor when the run is aborted or times out): <code>runId</code>, <code>datasetId</code>, <code>mode</code> (the value of <b>Reviews to return</b>), <code>status</code> (<code>succeeded</code>, <code>partial</code> or <code>failed</code>), <code>companies</code>, <code>reviews</code>, <code>skippedAlreadySeen</code>, <code>targets</code>, <code>failedTargets</code> and <code>chargeLimitReached</code>. With <b>New reviews only</b> and a schedule, that is a ready trigger via Zapier, Make, n8n or your own endpoint: filter on <code>reviews</code> above 0 to be told only when something new landed. Slack or Discord incoming webhooks do not accept this payload directly; route it through one of those tools.<br><br>Leave empty to skip it. Stored encrypted, since a webhook URL often embeds a token, and never written to the log. Redirects are not followed, except a 307 or 308 which gets the same POST once. An unreachable webhook is logged as a warning and never fails the run."
          },
          "proxyConfiguration": {
            "title": "Proxy",
            "type": "object",
            "description": "<b>Keep residential proxies on.</b> Trustpilot rate-limits by IP and challenges suspicious ones; residential proxies spread the load and keep the success rate high. This is the one Actor here where the proxy setting genuinely matters.<br><br>Switching to datacenter proxies, or to no proxy at all, will get large runs blocked. A company that stays blocked is skipped with an explanation and never stops the rest of the run.",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ]
            }
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}