# Shopify App Opportunity Finder (`signalflow_studio/shopify-app-opportunity-finder`) Actor

Find Shopify app opportunities from up to 20 apps and 120 public reviews by default, with scores, suggested products, and evidence URLs.

- **URL**: https://apify.com/signalflow\_studio/shopify-app-opportunity-finder.md
- **Developed by:** [SignalFlow Studio](https://apify.com/signalflow_studio) (community)
- **Categories:** E-commerce, AI, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

$0.25 / report generated

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Shopify App Opportunity Finder

Shopify App Opportunity Finder turns up to 20 public Shopify App Store apps and 120 merchant reviews by default into evidence-backed product opportunity reports with transparent query planning and optional BYOK AI. It is for Shopify app developers, ecommerce SaaS teams, agencies, and market researchers who want to find weak incumbent workflows and buildable app ideas.

### Run Size and Cost Controls

The default run is bounded so users understand the amount of public data being processed:

- Finds up to 20 Shopify apps from search queries or direct URLs.
- Analyzes up to 8 public reviews per app.
- Analyzes up to 120 reviews total.
- Produces up to 10 ranked opportunities.
- Includes Markdown, JSON, CSV, citations, evidence URLs, and app metadata in one report.

Users can reduce runtime by lowering app/review limits or turning review fetching off. Hard caps are 50 apps, 30 reviews per app, and 500 reviews total.

### What You Get

- Direct answer to your analysis goal.
- Ranked Shopify app opportunities with score and suggested product.
- Evidence URLs back to public Shopify App Store app/review pages.
- Apps mentioned per opportunity.
- Pain frequency, urgency, matched keywords, risks, and validation steps.
- Transparent search plan showing generated and applied search queries.
- Optional BYOK AI enhancement for evidence-grounded report polish and opportunity framing.
- Markdown, JSON, and CSV outputs.

### Typical Use Cases

- Find Shopify app ideas from low-star merchant reviews.
- Identify weak workflows in returns, inventory, subscriptions, reviews, fulfillment, or support apps.
- Monitor competitor review pain before planning product roadmap.
- Build agency service packages around repeated Shopify merchant complaints.
- Feed structured market intelligence into an AI agent or CRM workflow.

### Quick Start

```bash
npm install
npm run sample
npm run validate:sample
npm run smoke
npm run validate:smoke
````

Real-data smoke input:

```json
{
  "searchQueries": ["returns", "inventory sync", "subscriptions"],
  "analysisGoal": "Find Shopify app opportunities with repeated merchant pain, weak incumbent reviews, and clear evidence.",
  "market": "Shopify operations apps",
  "maxApps": 20,
  "includeReviews": true,
  "reviewRatings": ["1", "2", "3"],
  "maxReviewsPerApp": 8,
  "maxTotalReviews": 120,
  "aiProvider": "none",
  "aiMode": "off",
  "maxOpportunities": 10
}
```

Local outputs:

- `outputs/smoke/output.json`
- `outputs/smoke/report.md`
- `outputs/smoke/report.csv`

### Main Inputs

- `searchQueries`: Shopify App Store queries.
- `appUrls`: direct Shopify App Store app URLs.
- `maxApps`: maximum apps to analyze.
- `includeReviews`: fetch public merchant reviews.
- `reviewRatings`: ratings to fetch, usually low ratings for pain discovery.
- `analysisGoal`: report and optional AI analysis direction. It can help generate search queries only when explicit `searchQueries` are empty.
- `market`: market context for query planning and opportunity framing.
- `maxReviewsPerApp`, `maxTotalReviews`: bounded review controls.
- `maxOpportunities`: maximum ranked opportunities to output.
- `minScore`: opportunity score threshold.
- `includeRawReviews`: include raw review rows in the Dataset item.

`searchQueries` and `appUrls` control data collection. `analysisGoal` controls report framing and optional BYOK AI analysis. The output includes `questionPlan` so users can inspect generated and applied search queries.

### AI / BYOK

AI is optional and off by default. The rules-based report always runs without a model key.

Supported BYOK providers:

- DeepSeek
- OpenAI
- OpenRouter
- Anthropic Claude
- Google Gemini
- Custom OpenAI-compatible endpoint

Inputs:

- `aiProvider`: provider name.
- `aiMode`: `off`, `polish`, `cluster`, or `full`.
- `aiApiKey`: user-provided secret key. Model API costs are billed by the selected AI provider to the key owner.
- `aiModel`: model name for the selected provider. DeepSeek defaults to `deepseek-chat`.
- `aiBaseUrl`: optional override for custom or compatible endpoints.
- `maxAiInputChars`, `maxAiOutputTokens`: call-size limits. They reduce risk but are not exact billing caps.

The AI step can improve report wording, opportunity framing, risks, and validation steps. It cannot create opportunities without existing Shopify app/review evidence.

### Output

The first Dataset item includes:

- `answer`: direct answer to the analysis goal.
- `summary`: app, review, signal, opportunity, and fetch counts.
- `questionPlan`: generated and applied Shopify search queries plus warnings.
- `aiEnhancement`: BYOK AI status, provider, mode, model, and usage metadata when available.
- `apps[]`: analyzed Shopify app metadata.
- `opportunities[]`: ranked opportunity objects.
- `topOpportunities[]`: compact agent-friendly opportunity list.
- `signals[]`: extracted evidence signals.
- `citations[]`: evidence URLs and quotes.
- `markdownReport`: full human-readable report.
- `csvReport`: opportunity export.
- `monetization`: PPE charge attempt results.

Each opportunity includes `title`, `score`, `suggestedProduct`, `targetMerchant`, `painSummary`, `evidence[]`, `evidenceUrl`, `appsMentioned`, `painFrequency`, `urgency`, `keywords`, `risks`, and `nextValidationStep`.

### Cost Model

There are two cost layers:

- Actor pay-per-event fees: charged to the run owner only when configured in Apify Console and a successful report is generated.
- Apify platform usage: for the normal PPE mode, this is included in the event price and is deducted from the Actor owner's revenue/profit calculation. If the Actor owner enables "Pay per event + usage", the run owner pays platform usage separately.
- BYOK AI provider usage: charged by the selected AI provider to the owner of `aiApiKey`.

Current public setup: platform usage is not passed through separately, so users see simple PPE event pricing. Higher app/review limits can increase platform usage and reduce the Actor owner's margin, but hard caps and the internal fetch budget keep runs bounded. If monthly PPE revenue does not cover platform costs for this Actor, Apify reports that Actor's profit as zero rather than subtracting the loss from other Actors.

Pricing risk controls:

- Current primary event: `report_generated` at `$0.25`; owner gross revenue after Apify margin is `$0.20` before platform costs.
- Observed cloud platform cost was about `$0.0003` for small real-data runs, far below the primary-event owner gross revenue.
- Public default run size is bounded at 20 apps and 120 reviews; hard caps are 50 apps and 500 reviews.
- Internal Shopify fetch budget is 120 seconds so source fetching should not consume the full Apify run timeout.

The Actor is designed for a simple `report_generated` PPE event. BYOK AI currently does not add a separate Actor PPE event; provider costs are paid by the key owner. The code records charge results in `summary.monetization`.

### Compliance

- Only bounded public Shopify App Store pages are fetched.
- The Actor does not log in, install apps, submit reviews, or bypass access controls.
- Users are responsible for ensuring their use complies with Shopify terms, Apify terms, and applicable laws.
- Use it for product research, market intelligence, and competitor analysis, not spam, harassment, or deceptive republishing of review content.

### Apify Deployment

```bash
npx apify-cli@1.6.1 push
```

Recommended cloud smoke:

```bash
npx apify-cli@1.6.1 call ACTOR_ID --input-file fixtures/smoke-input.json --memory 1024 --timeout 300 --json
```

Cloud Actor:

- Actor ID: `TCZSAa7zwzjIpAZ2n`
- Store URL: `https://apify.com/signalflow_studio/shopify-app-opportunity-finder`
- Latest verified build: pending deployment after BYOK update.
- Default cloud run options: latest build, 1024 MB memory, 600 second timeout.
- Current pricing model: Pay per event with `report_generated`.

Recent verification:

- Local sample: 3 apps, 15 reviews, 6 opportunities, Markdown/CSV/JSON generated.
- Local real-data smoke: 20 apps, 81 reviews, 254 signals, 7 opportunities, Markdown/CSV/JSON generated.
- Local BYOK DeepSeek smoke: 3 apps, 15 reviews, 6 opportunities, `aiEnhancement.enabled: true`, evidence-grounded AI report polish applied.
- Local missing-key AI fallback: 2 apps, 4 reviews, 4 opportunities, `aiEnhancement.reason: missing_user_aiApiKey`, rules-based report still generated.
- Cloud latest pricing/runtime smoke `9aNyAT9DPQ0ox1LCN`: build `0.1.6`, status `SUCCEEDED`, 20 apps, 81 reviews, 254 signals, 7 opportunities, `REPORT.md` generated, `report_generated` charged once in `OUTPUT.json`, platform usage cost about `$0.0011`, default timeout 600 seconds.
- Cloud real-data run `qlbwzRJEBrJAfzp3j`: build `0.1.2`, status `SUCCEEDED`, 3 apps, 12 reviews, 53 signals, 6 opportunities, `REPORT.md` generated, `report_generated` charged once in `OUTPUT.json`, platform usage cost about `$0.0003`.
- Cloud latest-build run `S5e434a8FMaQelVjN`: build `0.1.3`, status `SUCCEEDED`, 2 apps, 6 reviews, 32 signals, 5 opportunities, `report_generated` charged once in `OUTPUT.json`, platform usage cost about `$0.0003`.

Known release note:

- The Actor is public and functional. A custom Actor avatar still needs to be uploaded through Apify Console because the Actor API rejected external `pictureUrl` values with `invalid-picture-url`.

# Actor input Schema

## `searchQueries` (type: `array`):

Shopify App Store search queries. These control what data is collected. If empty and no direct app URLs are provided, the Actor derives queries from Analysis goal and Market.

## `appUrls` (type: `array`):

Optional Shopify App Store app URLs to analyze directly. Direct URLs take priority over generated search queries.

## `maxApps` (type: `integer`):

Maximum Shopify apps to analyze. Default is 20; hard-capped at 50.

## `includeReviews` (type: `boolean`):

Fetch public merchant reviews as evidence. Reviews improve opportunity quality but can increase runtime.

## `reviewRatings` (type: `array`):

Review ratings to fetch. Low ratings usually contain the strongest product-gap signals.

## `analysisGoal` (type: `string`):

Goal for the report and optional BYOK AI analysis. It can help generate search queries when Search queries are empty, but explicit search queries and app URLs always control data collection.

## `market` (type: `string`):

Market context used for query planning and opportunity framing.

## `maxOpportunities` (type: `integer`):

Maximum ranked opportunities to output.

## `minScore` (type: `integer`):

Only output opportunities at or above this score.

## `aiProvider` (type: `string`):

Optional BYOK AI provider. Rules-based analysis always runs first and does not require an AI key.

## `aiMode` (type: `string`):

polish improves report wording, cluster improves opportunity framing, full does both. AI never creates opportunities without existing evidence.

## `aiApiKey` (type: `string`):

User-provided BYOK key. Model API costs are billed by the selected AI provider to the key owner.

## `aiModel` (type: `string`):

Model name for the selected provider, for example deepseek-chat, gpt-4.1-mini, openai/gpt-4.1-mini, claude-3-5-haiku-latest, or gemini-2.0-flash.

## `aiBaseUrl` (type: `string`):

Optional API base URL. Leave empty to use the selected provider default.

## `maxAiInputChars` (type: `integer`):

Maximum characters sent to the AI provider. This limits call size but is not an exact billing cap.

## `maxAiOutputTokens` (type: `integer`):

Maximum AI output tokens. This limits call size but is not an exact billing cap.

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

Maximum public reviews to fetch per app. Default is 8; hard-capped at 30.

## `maxTotalReviews` (type: `integer`):

Maximum reviews to analyze across all apps. Default is 120; hard-capped at 500.

## `includeRawReviews` (type: `boolean`):

Include raw extracted review rows in the Dataset item.

## `outputFormat` (type: `string`):

Primary human-readable report format.

## `proxyType` (type: `string`):

Use none for direct public HTTP requests, or auto to allow Apify proxy in cloud when needed.

## `debug` (type: `boolean`):

Include fetch errors and debug counters in output.

## `businessQuestion` (type: `string`):

Deprecated compatibility field. Use Analysis goal instead.

## Actor input object example

```json
{
  "searchQueries": [
    "returns",
    "inventory sync",
    "subscriptions"
  ],
  "maxApps": 20,
  "includeReviews": true,
  "reviewRatings": [
    "1",
    "2",
    "3"
  ],
  "analysisGoal": "Find Shopify app opportunities with repeated merchant pain, weak incumbent reviews, and clear evidence.",
  "market": "Shopify operations apps",
  "maxOpportunities": 10,
  "minScore": 35,
  "aiProvider": "none",
  "aiMode": "off",
  "maxAiInputChars": 30000,
  "maxAiOutputTokens": 1600,
  "maxReviewsPerApp": 8,
  "maxTotalReviews": 120,
  "includeRawReviews": false,
  "outputFormat": "markdown",
  "proxyType": "none",
  "debug": false
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

Structured JSON output. The first item includes answer, summary, apps, opportunities, topOpportunities, signals, citations, monetization, markdownReport, and csvReport.

## `jsonReport` (type: `string`):

Full JSON report stored in the default key-value store.

## `markdownReport` (type: `string`):

Human-readable Markdown report stored in the default key-value store.

## `csvReport` (type: `string`):

CSV export of opportunity rows stored in the default key-value store.

# 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 = {
    "searchQueries": [
        "returns",
        "inventory sync",
        "subscriptions"
    ],
    "analysisGoal": "Find Shopify app opportunities with repeated merchant pain, weak incumbent reviews, and clear evidence.",
    "market": "Shopify operations apps"
};

// Run the Actor and wait for it to finish
const run = await client.actor("signalflow_studio/shopify-app-opportunity-finder").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 = {
    "searchQueries": [
        "returns",
        "inventory sync",
        "subscriptions",
    ],
    "analysisGoal": "Find Shopify app opportunities with repeated merchant pain, weak incumbent reviews, and clear evidence.",
    "market": "Shopify operations apps",
}

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

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

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

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "returns",
    "inventory sync",
    "subscriptions"
  ],
  "analysisGoal": "Find Shopify app opportunities with repeated merchant pain, weak incumbent reviews, and clear evidence.",
  "market": "Shopify operations apps"
}' |
apify call signalflow_studio/shopify-app-opportunity-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=signalflow_studio/shopify-app-opportunity-finder",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Shopify App Opportunity Finder",
        "description": "Find Shopify app opportunities from up to 20 apps and 120 public reviews by default, with scores, suggested products, and evidence URLs.",
        "version": "0.1",
        "x-build-id": "4a7ZSNjlAuQgA57Yh"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/signalflow_studio~shopify-app-opportunity-finder/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-signalflow_studio-shopify-app-opportunity-finder",
                "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/signalflow_studio~shopify-app-opportunity-finder/runs": {
            "post": {
                "operationId": "runs-sync-signalflow_studio-shopify-app-opportunity-finder",
                "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/signalflow_studio~shopify-app-opportunity-finder/run-sync": {
            "post": {
                "operationId": "run-sync-signalflow_studio-shopify-app-opportunity-finder",
                "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": {
                    "searchQueries": {
                        "title": "Search queries",
                        "type": "array",
                        "description": "Shopify App Store search queries. These control what data is collected. If empty and no direct app URLs are provided, the Actor derives queries from Analysis goal and Market.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "appUrls": {
                        "title": "Direct app URLs",
                        "type": "array",
                        "description": "Optional Shopify App Store app URLs to analyze directly. Direct URLs take priority over generated search queries.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxApps": {
                        "title": "Max apps",
                        "minimum": 1,
                        "maximum": 50,
                        "type": "integer",
                        "description": "Maximum Shopify apps to analyze. Default is 20; hard-capped at 50.",
                        "default": 20
                    },
                    "includeReviews": {
                        "title": "Include reviews",
                        "type": "boolean",
                        "description": "Fetch public merchant reviews as evidence. Reviews improve opportunity quality but can increase runtime.",
                        "default": true
                    },
                    "reviewRatings": {
                        "title": "Review ratings",
                        "type": "array",
                        "description": "Review ratings to fetch. Low ratings usually contain the strongest product-gap signals.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "1",
                                "2",
                                "3",
                                "4",
                                "5"
                            ],
                            "enumTitles": [
                                "1 star",
                                "2 stars",
                                "3 stars",
                                "4 stars",
                                "5 stars"
                            ]
                        },
                        "default": [
                            "1",
                            "2",
                            "3"
                        ]
                    },
                    "analysisGoal": {
                        "title": "Analysis goal",
                        "type": "string",
                        "description": "Goal for the report and optional BYOK AI analysis. It can help generate search queries when Search queries are empty, but explicit search queries and app URLs always control data collection."
                    },
                    "market": {
                        "title": "Market or niche",
                        "type": "string",
                        "description": "Market context used for query planning and opportunity framing."
                    },
                    "maxOpportunities": {
                        "title": "Max opportunities",
                        "minimum": 1,
                        "maximum": 25,
                        "type": "integer",
                        "description": "Maximum ranked opportunities to output.",
                        "default": 10
                    },
                    "minScore": {
                        "title": "Minimum opportunity score",
                        "minimum": 0,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Only output opportunities at or above this score.",
                        "default": 35
                    },
                    "aiProvider": {
                        "title": "AI provider",
                        "enum": [
                            "none",
                            "deepseek",
                            "openai",
                            "openrouter",
                            "anthropic",
                            "gemini",
                            "custom_openai_compatible"
                        ],
                        "type": "string",
                        "description": "Optional BYOK AI provider. Rules-based analysis always runs first and does not require an AI key.",
                        "default": "none"
                    },
                    "aiMode": {
                        "title": "AI mode",
                        "enum": [
                            "off",
                            "polish",
                            "cluster",
                            "full"
                        ],
                        "type": "string",
                        "description": "polish improves report wording, cluster improves opportunity framing, full does both. AI never creates opportunities without existing evidence.",
                        "default": "off"
                    },
                    "aiApiKey": {
                        "title": "AI API key",
                        "type": "string",
                        "description": "User-provided BYOK key. Model API costs are billed by the selected AI provider to the key owner."
                    },
                    "aiModel": {
                        "title": "AI model",
                        "type": "string",
                        "description": "Model name for the selected provider, for example deepseek-chat, gpt-4.1-mini, openai/gpt-4.1-mini, claude-3-5-haiku-latest, or gemini-2.0-flash."
                    },
                    "aiBaseUrl": {
                        "title": "AI base URL",
                        "type": "string",
                        "description": "Optional API base URL. Leave empty to use the selected provider default."
                    },
                    "maxAiInputChars": {
                        "title": "Max AI input characters",
                        "minimum": 1000,
                        "maximum": 100000,
                        "type": "integer",
                        "description": "Maximum characters sent to the AI provider. This limits call size but is not an exact billing cap.",
                        "default": 30000
                    },
                    "maxAiOutputTokens": {
                        "title": "Max AI output tokens",
                        "minimum": 500,
                        "maximum": 4000,
                        "type": "integer",
                        "description": "Maximum AI output tokens. This limits call size but is not an exact billing cap.",
                        "default": 1600
                    },
                    "maxReviewsPerApp": {
                        "title": "Max reviews per app",
                        "minimum": 0,
                        "maximum": 30,
                        "type": "integer",
                        "description": "Maximum public reviews to fetch per app. Default is 8; hard-capped at 30.",
                        "default": 8
                    },
                    "maxTotalReviews": {
                        "title": "Max total reviews",
                        "minimum": 0,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Maximum reviews to analyze across all apps. Default is 120; hard-capped at 500.",
                        "default": 120
                    },
                    "includeRawReviews": {
                        "title": "Include raw reviews",
                        "type": "boolean",
                        "description": "Include raw extracted review rows in the Dataset item.",
                        "default": false
                    },
                    "outputFormat": {
                        "title": "Output format",
                        "enum": [
                            "markdown",
                            "json"
                        ],
                        "type": "string",
                        "description": "Primary human-readable report format.",
                        "default": "markdown"
                    },
                    "proxyType": {
                        "title": "Proxy type",
                        "enum": [
                            "none",
                            "auto",
                            "residential"
                        ],
                        "type": "string",
                        "description": "Use none for direct public HTTP requests, or auto to allow Apify proxy in cloud when needed.",
                        "default": "none"
                    },
                    "debug": {
                        "title": "Debug",
                        "type": "boolean",
                        "description": "Include fetch errors and debug counters in output.",
                        "default": false
                    },
                    "businessQuestion": {
                        "title": "Legacy business question",
                        "type": "string",
                        "description": "Deprecated compatibility field. Use Analysis goal instead."
                    }
                }
            },
            "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
                                    }
                                }
                            },
                            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
