# Apify Opportunity Finder – Validate Actor Ideas (`groundworklabs/apify-opportunity-finder`) Actor

Validate Apify actor ideas before you build them. Enter keywords, get GO / MAYBE / NO-GO verdicts scored by demand, saturation, and opportunity. Built for solo builders and creators.

- **URL**: https://apify.com/groundworklabs/apify-opportunity-finder.md
- **Developed by:** [Groundwork Labs](https://apify.com/groundworklabs) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $15.00 / 1,000 results

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Apify Opportunity Finder – Validate Actor Ideas Before You Build

**Know whether an Apify actor idea is worth building — before you write a line of code.**

Enter your scraper ideas as keywords. Get GO / MAYBE / NO-GO verdicts scored by real Apify Store demand, direct competitor count, and data quality. Runs on Apify (no setup) or locally from the terminal.

***

### Run on Apify — no setup required

Open the actor, enter your keywords, click Run. No token, no config, no installation.

**[→ Open in Apify Console](https://console.apify.com/actors/pGkjzefMUyo8GI3Oe)**

You need an Apify account (free tier works). Your API token is provided automatically — you do not enter it anywhere.

***

### Run locally (CLI)

```bash
pip install apify-client rich
export APIFY_TOKEN="your_token_here"   # Settings → Integrations in Apify Console
python apify_opportunity.py
```

You'll be prompted to enter keywords:

```
Enter 3–20 keywords or ideas (comma-separated):
> newsletter scraper, Reddit research scraper, G2 review aggregator, podcast transcript
```

***

### What it does

You enter a comma-separated list of scraper ideas. For each one, the tool runs up to 5 related searches against the Apify Store, deduplicates results by actor ID, classifies each actor as a direct competitor, adjacent actor, or irrelevant result, then scores and returns a verdict.

**Per keyword you get:**

| Field | What it means |
|---|---|
| **Demand score** | How many people use existing actors in this niche (relevant actors only) |
| **Saturation score** | How many *direct* competitors exist — actors that solve the same core problem |
| **Opportunity score** | Weighted blend of demand and saturation |
| **Verdict** | `GO`, `MAYBE`, `NO-GO`, or `VALIDATE` |
| **Direct competitors** | Actors matching both the target platform and the core problem |
| **Data status** | `GOOD`, `LIMITED` (search hit result cap), or `INSUFFICIENT` (no relevant actors found) |

***

### Example output

```
Apify Opportunity Finder v2
Multi-variant search · relevance filtering · GO / MAYBE / NO-GO / VALIDATE

  Niche                       Demand  Saturation  Opportunity   Verdict   Direct competitors  Data status
 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  Instagram visual hook           100      50          75          GO               6            LIMITED
  LinkedIn article scraper        100      30          67         MAYBE            12            LIMITED
  Instagram Reels hook            100      10          64         MAYBE            59            LIMITED
  Substack scraper                  3     100          42         NO-GO             0             GOOD
  newsletter scraper                2     100          41         NO-GO             0             GOOD
  podcast transcript scraper       29      30          29         NO-GO             3             GOOD

──────────────────────────── Score breakdown ─────────────────────────────
  Instagram visual hook scraper: high Apify demand signal, 6 direct
  competitors, but related searches returned limited data.
  → Validate manually before building.

──────────────────────────── What to do next ─────────────────────────────

Build this: "Instagram visual hook scraper"
  High Apify demand signal, 6 direct competitors, search results truncated
  — validate manually.
  → Start with a minimal scraper, publish fast, iterate on user feedback.
```

Verdicts are color-coded in the terminal: 🟢 GO · 🟡 MAYBE · 🔴 NO-GO · 🟣 VALIDATE

***

### Why the simple approach gets saturation wrong

A naive Apify Store search for "Instagram visual hook scraper" returns up to 30 broadly-matching actors — generic Instagram scrapers, Reels downloaders, profile extractors. Treating that full list as "30 competitors" overstates saturation and makes specific niches look crowded when they aren't.

This actor fixes that by classifying each returned result before scoring:

- **Direct competitor** — actor text matches both the target platform and the core problem term from your query
- **Adjacent** — matches the platform or the problem, but not both
- **Irrelevant** — no meaningful match, excluded from all scoring

For `Instagram visual hook scraper`: a generic Instagram profile scraper is *adjacent* (platform match only, no mention of hooks or visual analysis). An actor called "Instagram Reels Hook Analyzer" is *direct*. The demand and saturation scores use only the direct and adjacent actors — not the full returned list.

***

### How it works

#### Multi-variant search

A single keyword phrase often misses relevant actors that use different terminology. For each keyword, up to 5 related search strings are generated and searched:

| Your keyword | Variants searched |
|---|---|
| `Instagram visual hook scraper` | Instagram Reels scraper · Instagram posts scraper · Instagram Stories scraper · Instagram video hook · Instagram first frame |
| `newsletter scraper` | Substack scraper · Beehiiv scraper · newsletter archive extractor · newsletter content extractor |
| `podcast transcript scraper` | podcast transcript scraper · podcast episodes scraper · podcast RSS scraper · podcast captions |

Results across all variants are deduplicated by actor ID before classification.

#### Scoring

**Demand score (0–100)**
Based on 30-day user count across direct + adjacent actors only.

**Saturation score (0–100)** — uses `direct_competitor_count`, not the total returned count:

| Direct competitors | Score |
|---|---|
| 0 | 100 |
| 1–2 | 85 |
| 3–5 | 70 |
| 6–10 | 50 |
| 11–20 | 30 |
| 21+ | 10 |

**Opportunity score (0–100)**
`0.6 × demand + 0.4 × saturation`, with quality adjustments:

- Avg success rate < 85% → +5 (reliability gap worth exploiting)
- Avg success rate > 95% → −5 (market already well-served)
- Data quality INSUFFICIENT → score capped at 40

**Verdict thresholds**

| Verdict | Condition |
|---|---|
| GO | Opportunity ≥ 70 |
| MAYBE | Opportunity 50–69 |
| NO-GO | Opportunity < 50 |
| VALIDATE | No relevant actors found — insufficient data for a confident verdict |

#### Data quality flags

| Status | Confidence | Meaning |
|---|---|---|
| GOOD | HIGH | Clean result, no truncation |
| LIMITED | MEDIUM | A search variant hit the result cap — competition may be understated |
| INSUFFICIENT | LOW | No relevant actors found — VALIDATE verdict, do not treat as automatic GO |

A `VALIDATE` verdict means there is not enough signal to call it a GO. Zero competitors with zero demand could mean a genuine gap — or simply no market. Search the Apify Store manually before building.

***

### Run locally (CLI) — options

```bash
## Export results to CSV or JSON
python apify_opportunity.py --output results.csv
python apify_opportunity.py --output results.json

## Verbose mode — shows variants searched, actor classifications, and scoring reasoning per keyword
python apify_opportunity.py --verbose
```

***

### Output fields (CSV / JSON / Apify dataset)

| Field | Type | Description |
|---|---|---|
| `niche` | string | Your keyword |
| `demand_score` | 0–100 | Apify demand signal from relevant actors |
| `saturation_score` | 0–100 | Based on direct competitor count |
| `opportunity_score` | 0–100 | Weighted blend |
| `verdict` | string | GO / MAYBE / NO-GO / VALIDATE |
| `data_status` | string | GOOD / LIMITED / INSUFFICIENT |
| `confidence` | string | HIGH / MEDIUM / LOW |
| `total_users_30d` | integer | 30-day users across relevant actors |
| `median_users_30d` | integer | Median 30-day users |
| `top_actor_users_30d` | integer | Users held by the dominant relevant actor |
| `top_actor_share` | % | % of total demand held by the top actor |
| `returned_actor_count` | integer | Total unique actors returned across all variants |
| `direct_competitor_count` | integer | Actors matching platform + core problem |
| `adjacent_competitor_count` | integer | Actors partially matching |
| `result_limit_reached` | boolean | True if any variant hit the result cap |
| `avg_success_rate` | 0–100 | Avg run success rate of direct competitors |
| `notes` | string | Truncation warnings, demand concentration |

***

### Costs and limits

Each keyword runs up to 5 search variants, each retrieving up to 30 results from `johnvc/store-actor-intelligence-api`. Based on test runs, cost is roughly **$0.005 per keyword** (~$0.05 for 10 keywords). The Apify free tier covers hundreds of runs.

Configurable limits (Apify input tab or CLI):

- 3–20 keywords per run
- 10–50 actors retrieved per variant (default: 30)

***

### What it's for — and not for

**Use it to:**

- Compare 3–20 scraper ideas before you start building
- Get a data-backed GO / NO-GO on a niche you're unsure about
- Rule out ideas with near-zero demand before wasting build time
- Prioritize a backlog when you have too many ideas

**Not suitable for:**

- Replacing manual Apify Store research before committing to a build
- Forecasting revenue or guaranteeing actor success
- Full-store category scans or historical trend analysis

***

### FAQ

**Do I need to enter my Apify token?**
No. When you run the actor on Apify, your token is set automatically by the platform. You never enter it. The optional `apifyToken` input field only exists for users calling the actor programmatically via the Apify API from outside the Console.

**Does running this use my Apify credits?**
Yes. The actor calls `johnvc/store-actor-intelligence-api` for each search variant. Those calls run on your account and use your credits. Cost is roughly $0.005 per keyword. The Apify free tier ($5/month) covers hundreds of runs.

**Why do I get VALIDATE instead of GO when there are no competitors?**
Zero competitors with zero demand signal means the data is insufficient — not that the opportunity is confirmed. `VALIDATE` means: check the Apify Store manually, find evidence of real user demand, then decide. Building on a VALIDATE verdict without manual research is a risk.

**What does LIMITED data status mean?**
At least one search variant returned the maximum number of results (up to 30 by default). More actors may exist than were retrieved. The verdict is directional — spot-check the Apify Store manually for these keywords before acting on it.

**Can I adjust the scoring thresholds?**
Yes. All thresholds are documented in comments inside `apify_opportunity.py`. The `demand_score()`, `saturation_score()`, `opportunity_score()`, and `verdict()` functions each have inline notes explaining what to change and the effect it has.

**How accurate are the scores?**
They are directional signals, not precise measurements. Demand reflects usage of existing actors — not total addressable market size. A niche with no actors and no demand signal could still be an opportunity if you bring your own audience. Use the verdicts to filter and prioritize, not as guarantees.

**Is this affiliated with Apify?**
No. This is an independent tool. It uses the public Apify API and `johnvc/store-actor-intelligence-api`, but is not affiliated with or endorsed by Apify.

***

### License

MIT — use it, fork it, build on it.

# Actor input Schema

## `keywords` (type: `array`):

List of scraper ideas or niches to validate (3–20 keywords). Each keyword is searched against the Apify Store across multiple related search variants.

## `apifyToken` (type: `string`):

Your Apify API token (Settings → Integrations in the Apify Console). When running on Apify, your token is provided automatically — leave this blank. Only fill this in if you're calling the actor via the API and want to override the default token.

## `maxActorsPerKeyword` (type: `integer`):

Maximum number of Apify Store actors to retrieve per search variant. Each keyword runs 3–5 variants, so total API calls = keywords × variants. Lower values are faster and cheaper; higher values are more thorough.

## Actor input object example

```json
{
  "keywords": [
    "newsletter scraper",
    "Reddit research scraper",
    "G2 review aggregator",
    "podcast transcript scraper"
  ],
  "maxActorsPerKeyword": 30
}
```

# Actor output Schema

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

One row per keyword: verdict, demand score, saturation score, opportunity score, and full diagnostic data.

# 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 = {
    "keywords": [
        "newsletter scraper",
        "Reddit research scraper",
        "G2 review aggregator",
        "podcast transcript scraper"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("groundworklabs/apify-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 = { "keywords": [
        "newsletter scraper",
        "Reddit research scraper",
        "G2 review aggregator",
        "podcast transcript scraper",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("groundworklabs/apify-opportunity-finder").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 '{
  "keywords": [
    "newsletter scraper",
    "Reddit research scraper",
    "G2 review aggregator",
    "podcast transcript scraper"
  ]
}' |
apify call groundworklabs/apify-opportunity-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,groundworklabs/apify-opportunity-finder"
        }
    }
}

```

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/pGkjzefMUyo8GI3Oe/builds/Tqo74sBhxelRJpvlk/openapi.json
