# Shopify App Review & Reply Watch (`isolovyev/shopify-app-review-watch`) Actor

Monitor Shopify App Store ratings, new or edited reviews and developer reply changes with repeat history. Отслеживание рейтингов, отзывов и ответов разработчиков Shopify.

- **URL**: https://apify.com/isolovyev/shopify-app-review-watch.md
- **Developed by:** [Ivan Solovyev](https://apify.com/isolovyev) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 complete shopify app checks

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Shopify App Review & Reply Watch

### English

Run repeat checks for public Shopify App Store listings. Each complete check produces one Dataset observation with the current rating snapshot, star distribution, and changes in a bounded newest-review window.

#### What each check reports

- current aggregate rating, rating count, and 1 to 5 star counts;
- new and edited reviews in the checked newest-first window;
- new and edited developer replies;
- `baseline`, `changed`, `unchanged`, or `coverage_changed` status;
- source URLs, UTC observation time, and a stable `observationId`.

The first complete run creates a baseline. Reuse the same `watchId` for later checks and run that schedule sequentially, so each comparison uses the preceding accepted state. State is isolated by the Apify user that starts the Actor and by `watchId`.

#### Input

```json
{
  "apps": ["privy", "https://apps.shopify.com/klaviyo"],
  "watchId": "agency-portfolio",
  "maxPagesPerApp": 2,
  "maxReviewsPerApp": 20
}
```

One run accepts up to 5 apps, 5 pages per app, and 50 newest reviews per app. It also enforces 30 HTTP requests, 1 MiB per response, 10 MiB per run, and a 75-second processing deadline inside the 90-second Actor timeout. Each app observation is capped at 512 KiB.

#### Output

Example from the public Privy listing observed on 2026-10-08:

```json
{
  "observationId": "b3ad7a9817e98ab61f0fd28f932abc44",
  "appHandle": "privy",
  "appTitle": "Privy ‑ Email, SMS & Pop Ups",
  "observedAt": "2026-10-08T00:00:00Z",
  "complete": true,
  "pagesFetched": 2,
  "reviewWindowCount": 20,
  "windowIsBounded": true,
  "coverageFingerprint": "shopify-app-store:reviews:newest:v1:pages=2:reviews=20",
  "ratingValue": 4.5,
  "ratingCount": 4208,
  "starCounts": {"5": 3146, "4": 604, "3": 193, "2": 88, "1": 177},
  "changeType": "baseline",
  "newReviews": [],
  "changedReviews": [],
  "newReplies": [],
  "changedReplies": []
}
```

The complete row also contains source URLs, bounded change arrays, aggregate deltas, page coverage, and review-window limits. `baseline` records the first visible window. `changed` reports review, reply, or aggregate-rating changes. `unchanged` confirms a repeated complete check. `coverage_changed` reports an input-window change without classifying newly exposed older reviews as new.

#### Coverage and source health

A Dataset row is written only after every requested page for that app passes HTTP, size, identity, pagination, and rating-total checks. If a requested page cannot be verified, the app status in `SUMMARY` is `unknown`, the prior baseline is retained, and no complete Dataset row is written for that app. A run with only unknown app checks has summary health `unknown`.

The review window is newest-first and bounded by the input. A review leaving that window is retained in compact state and is not reported as removed. A developer reply missing from one observation is not reported as removed or as new when the same reply reappears. Changing `maxPagesPerApp` or `maxReviewsPerApp` produces `coverage_changed`; newly visible older reviews establish the new coverage baseline instead of creating false new-review alerts.

#### Usage unit

A run-start fee applies even when no complete observation is produced. Completed observations are charged separately, including unchanged checks. Apify compute and proxy usage are included in the event prices. See Pricing for the current tariff.

One complete, source-verified app observation delivered as a Dataset row is one usage unit. `baseline`, `changed`, `unchanged`, and `coverage_changed` rows use the same unit. A source failure before a complete observation produces no Dataset row. If a run fails later after a complete row has already been delivered, that delivered observation remains a usage unit.

#### Outputs

- Dataset: one row per complete app observation.
- `SUMMARY`: complete and unknown app statuses, source evidence, and delivery totals.

Schedule the Actor from Apify Console or call it from an integration. Run one `watchId` sequentially so each comparison uses the preceding accepted state.

### Русский

Запускайте повторные проверки публичных страниц Shopify App Store. Каждая полная проверка создаёт одну строку Dataset с текущим рейтингом, распределением оценок и изменениями в ограниченном окне последних отзывов.

#### Что содержит проверка

- текущий средний рейтинг, число оценок и распределение от 1 до 5 звёзд;
- новые и изменённые отзывы в проверенном окне от новых к старым;
- новые и изменённые ответы разработчика;
- статус `baseline`, `changed`, `unchanged` или `coverage_changed`;
- ссылки на источники, время наблюдения в UTC и стабильный `observationId`.

Первый полный запуск создаёт базовый срез. Для следующих проверок повторяйте тот же `watchId` и запускайте это расписание последовательно, чтобы каждое сравнение использовало предыдущее принятое состояние. Состояние разделяется по пользователю Apify, который запустил Actor, и по `watchId`.

#### Входные данные

```json
{
  "apps": ["privy", "https://apps.shopify.com/klaviyo"],
  "watchId": "agency-portfolio",
  "maxPagesPerApp": 2,
  "maxReviewsPerApp": 20
}
```

Один запуск принимает до 5 приложений, до 5 страниц на приложение и до 50 последних отзывов на приложение. Также действуют пределы: 30 HTTP-запросов, 1 МиБ на ответ, 10 МиБ на запуск и 75 секунд обработки внутри 90-секундного таймаута Actor. Строка наблюдения приложения ограничена 512 КиБ.

#### Результат

Пример с публичной страницы Privy, наблюдавшейся 08.10.2026:

```json
{
  "observationId": "b3ad7a9817e98ab61f0fd28f932abc44",
  "appHandle": "privy",
  "appTitle": "Privy ‑ Email, SMS & Pop Ups",
  "observedAt": "2026-10-08T00:00:00Z",
  "complete": true,
  "pagesFetched": 2,
  "reviewWindowCount": 20,
  "windowIsBounded": true,
  "coverageFingerprint": "shopify-app-store:reviews:newest:v1:pages=2:reviews=20",
  "ratingValue": 4.5,
  "ratingCount": 4208,
  "starCounts": {"5": 3146, "4": 604, "3": 193, "2": 88, "1": 177},
  "changeType": "baseline",
  "newReviews": [],
  "changedReviews": [],
  "newReplies": [],
  "changedReplies": []
}
```

Полная строка также содержит ссылки на источники, ограниченные массивы изменений, изменения агрегатов, покрытие страниц и предел окна отзывов. `baseline` сохраняет первое видимое окно. `changed` сообщает об изменении отзыва, ответа или агрегированного рейтинга. `unchanged` подтверждает повторную полную проверку. `coverage_changed` сообщает об изменении входного окна и не считает вновь видимые старые отзывы новыми.

#### Покрытие и состояние источника

Строка Dataset записывается только после того, как все запрошенные страницы приложения прошли проверки HTTP, размера, идентичности, пагинации и итогов оценок. Если запрошенную страницу нельзя подтвердить, приложение получает статус `unknown` в `SUMMARY`, предыдущий базовый срез сохраняется, а полная строка для этого приложения не записывается. Если все проверки приложений неизвестны, состояние источника в сводке равно `unknown`.

Окно отзывов ограничено входными параметрами и отсортировано от новых к старым. Отзыв, который вышел за границу окна, сохраняется в компактном состоянии и не помечается удалённым. Ответ разработчика, отсутствующий в одном наблюдении, не считается удалённым или новым при повторном появлении того же ответа. Изменение `maxPagesPerApp` или `maxReviewsPerApp` создаёт `coverage_changed`; вновь видимые старые отзывы формируют новую базовую линию покрытия и не создают ложные сигналы о новых отзывах.

#### Единица использования

Плата за старт применяется и при отсутствии полной проверки. Полные доставленные проверки оплачиваются отдельно, включая проверки без изменений. Вычисления и прокси Apify включены в цену событий. Актуальный тариф указан в разделе Pricing.

Одна полная, подтверждённая источником проверка приложения, доставленная строкой Dataset, равна одной единице использования. Строки `baseline`, `changed`, `unchanged` и `coverage_changed` используют одну и ту же единицу. Ошибка источника до формирования полного наблюдения не создаёт строку Dataset. Если run завершается ошибкой уже после доставки полной строки, это доставленное наблюдение остаётся единицей использования.

#### Выходные данные

- Dataset: одна строка на полное наблюдение приложения.
- `SUMMARY`: полные и неизвестные статусы приложений, доказательства источника и итоги доставки.

Запускайте Actor по расписанию в Apify Console или вызывайте его из интеграции. Один `watchId` должен выполняться последовательно, чтобы каждое сравнение использовало предыдущее принятое состояние.

# Actor input Schema

## `apps` (type: `array`):

Shopify App Store handles or public listing URLs. Идентификаторы или публичные ссылки Shopify App Store.

## `watchId` (type: `string`):

Reuse this ID for sequential checks. Повторяйте этот ID для последовательных проверок.

## `maxPagesPerApp` (type: `integer`):

Newest-first pages checked for each app. Число проверяемых страниц от новых к старым.

## `maxReviewsPerApp` (type: `integer`):

Bounded newest review window. Ограниченное окно последних отзывов.

## Actor input object example

```json
{
  "apps": [
    "privy"
  ],
  "watchId": "app-review-watch",
  "maxPagesPerApp": 2,
  "maxReviewsPerApp": 20
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "apps": [
        "privy"
    ],
    "watchId": "app-review-watch",
    "maxPagesPerApp": 2,
    "maxReviewsPerApp": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("isolovyev/shopify-app-review-watch").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "apps": ["privy"],
    "watchId": "app-review-watch",
    "maxPagesPerApp": 2,
    "maxReviewsPerApp": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("isolovyev/shopify-app-review-watch").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "apps": [
    "privy"
  ],
  "watchId": "app-review-watch",
  "maxPagesPerApp": 2,
  "maxReviewsPerApp": 20
}' |
apify call isolovyev/shopify-app-review-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,isolovyev/shopify-app-review-watch"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/9lXOUK71J1fhLvzn8/builds/nW2NOAGHoRZCvKAAA/openapi.json
