# GoodShort Scraper — Catalog, Views, Followers, Genres & Tags (`signalbench/goodshort-scraper`) Actor

Scrape the GoodShort short-drama catalog: titles, genres & tags, episode counts, exact view and follower counts, synopses and covers. SSR-JSON based (no browser) — fast and cheap.

- **URL**: https://apify.com/signalbench/goodshort-scraper.md
- **Developed by:** [SignalBench](https://apify.com/signalbench) (community)
- **Categories:** Videos, Other
- **Stats:** 4 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## GoodShort Scraper — Catalog, Views, Followers, Genres & Tags

Scrape the **GoodShort** vertical short-drama catalog without the app: **title
metadata, genres and trope tags, episode counts, exact view counts, follower
counts, synopses and covers** — structured, ready for analysis. API-first (reads
the site's own server-rendered JSON, **no browser**), so runs are fast, cheap,
and reliable. Export as **JSON, CSV, Excel, or XML**, or pull straight through
the Apify API into your app, agent, notebook, or spreadsheet.

This is the missing **GoodShort API / GoodShort data** source: the short-drama
category has had essentially zero structured-data coverage, and GoodShort has had
none at all. If you're a studio, licensor, or analyst asking *"what's charting and
what should we greenlight next?"* — this is your dataset.

> **No per-datapoint games, never charged for failures.** Flat **$2 per 1,000
> titles** ($0.002 each), billed only per title actually stored. Empty, invalid,
> and failed pages are never stored and never charged.

### What it scrapes

| Field | Description |
|---|---|
| **id / title / url** | GoodShort title ID, name, and canonical URL |
| **views** | **Exact integer** view count — not a rounded "37.9M" string |
| **viewsDisplay / viewsDisplayParsed** | GoodShort's own on-site display figure, kept separately (see the FAQ — it is *not* a rounding of `views`) |
| **follows** | Follower count (the site's "Followers" number) |
| **episodes** | Number of episodes |
| **genres / tags** | Genre names plus the full trope tag list (Second Chance, Misunderstanding, Cute Kids, …) |
| **description** | Full synopsis |
| **cover** | Cover image URL |
| **studio** | Studio/uploader handle |
| **status** | Completed / ongoing |
| **praiseCount / rating** | Platform-reported engagement signals |
| **releaseDate / lastUpdatedAt** | First-episode publish time and last update, ISO-8601 |
| **sourceSurface** | Which GoodShort surface the title was found on — rail, channel, category, tag, or search |

### Modes

- **Trending** *(default)* — the homepage rails and every curated channel
  (Most Trending, Top in GoodShort, Hot List, Love Stories, Counterattack, Cutie,
  ENG Dubbed Dramas, Popular Now). ~90 editorially-picked titles in ~9 requests.
  This is the mode you want for a trends leaderboard.
- **By category** — scrapes the genres you pick (Romance, Fantasy, Urban,
  Ancient, LGBTQIA+, Thriller, Action, Superpower, Suspense, Sci-Fi, or All).
- **Full catalog** — all 11 genres, then a sweep of GoodShort's tag listings.
  Tag listings overlap the genre catalog by only ~2%, so this is the only mode
  that reaches real scale. Bounded by **Max tags to sweep**.
- **Specific URLs** — scrape exactly the GoodShort URLs you provide (title pages,
  category listings, tag listings, the tag index, or channels).
- **Search by keyword** — resolve a title you already know by name.

#### How many titles can I actually get?

Worth knowing before you run, because it's a property of GoodShort, not of this
Actor: **every browse listing is hard-capped at 96 unique titles**, and the union
of all 11 genres is only ~437 titles. Measured yields:

| Mode | Realistic unique titles |
|---|---|
| Trending | ~90 |
| By category (one genre) | up to 96 — Action, Thriller, Superpower, Suspense and Sci-Fi hold under 10 each |
| By category (all 11) | ~437 |
| Full catalog (with tag sweep) | thousands — scales with **Max tags to sweep** |
| Search | max 3 per keyword (GoodShort's search endpoint is an autocomplete and does not paginate) |

### Input example

```json
{
    "mode": "fullCatalog",
    "maxItems": 1000,
    "maxTagsToCrawl": 50,
    "enrichFromDetailPage": true
}
```

### Output example

```json
{
    "platform": "goodshort",
    "id": "31001113972",
    "title": "Blood and Bones of the Disowned Daughter",
    "url": "https://www.goodshort.com/drama/blood-and-bones-of-the-disowned-daughter-31001113972",
    "views": 12138292,
    "viewsDisplay": "37.9M",
    "viewsDisplayParsed": 37900000,
    "follows": 6255505,
    "episodes": 64,
    "genres": ["Romance"],
    "tags": ["Family", "Heiress", "Regret"],
    "releaseDate": "2025-09-05T12:30:49.000Z",
    "cast": [],
    "cover": "https://acf.goodshort.com/videobook/202509/cover-e98.jpg",
    "description": "Natalie was once the Parson family's cherished daughter…",
    "studio": "GINA",
    "status": "Completed",
    "praiseCount": 307747,
    "language": "ENGLISH",
    "sourceSurface": "category:playlets",
    "scrapedAt": "2026-08-21T21:18:09.310Z"
}
```

Export the dataset as **CSV, Excel, JSON, or XML** from the Apify Console, or
fetch it via the Apify API / SDK.

### Who uses this

- **Vertical-drama studios & producers** — track which tropes and titles are
  charting to inform what to greenlight.
- **Licensors & distributors** — catalog intelligence across the fast-growing
  short-drama market.
- **Market & trend analysts** — engagement signals (views, followers, praise) per
  title, genre, tag, and release date.
- **Competitive researchers** — GoodShort alongside DramaBox and ReelShort, in
  one shared shape.

### How it works

GoodShort is a Vue server-rendered site that ships its entire page state as a
JSON blob inside the HTML. The Actor reads that JSON directly with Crawlee — **no
headless browser** to render or break, which is why runs are fast and cheap. It
scrapes only **public catalog metadata**: no video assets or stream URLs, no user
data, and it never touches GoodShort's payment or account endpoints. Paths
disallowed by GoodShort's robots.txt are skipped, and the live robots.txt is
logged at the start of every run.

If GoodShort ever changes its page structure, set **Extraction mode** to
*JSON-LD + DOM fallback* — a second extraction path that reads schema.org markup
and page selectors instead. It loses tags, follower counts and the exact integer
view count, but keeps the run producing data.

### Use it from n8n, Zapier, Make, MCP, and LangChain

Every Apify Actor is exposed via API and through Apify's integrations:

- **n8n / Zapier / Make** — run on a schedule and pipe title data into sheets,
  dashboards, or alerts.
- **MCP / LangChain** — give an AI agent live short-drama catalog data as a tool.
- **Apify API & SDK** — call it from your backend, then export CSV/JSON.

### FAQ

**Is there a GoodShort API?** Not a public one. This Actor is the practical,
available-today way to get structured GoodShort data.

**How much does it cost?** $0.002 per stored title — **$2 per 1,000**. You're
never charged for failed, empty, or invalid pages. The free Apify plan's $5
monthly credit covers ~2,500 titles.

**Why are `views` and `viewsDisplay` different numbers?** Because GoodShort
reports them differently, and we won't quietly pick one for you. The site's raw
`viewCount` for one title reads `12,138,292` while the figure printed on the page
reads `37.9M` — consistently ~3.1× higher, and it drifts upward between page
loads. `views` is the raw integer and is what you want for ranking; `viewsDisplay`
is what a visitor sees. Both are in every record.

**Why is `cast` always empty?** GoodShort publishes no cast data anywhere — not
in its JSON-LD, not in the page, not in its internal APIs. The field is kept for
schema compatibility with sibling short-drama Actors rather than dropped. The
`studio` field holds GoodShort's uploader handle, which is *not* a cast credit.

**Why is `follows` sometimes null?** GoodShort's homepage and channel payloads
omit the follower count. Leave **Fetch each title's detail page** on and it's
filled in for every record; with it off, rail-sourced titles keep `follows: null`
rather than a misleading `0`.

**How accurate is `releaseDate`?** GoodShort has no true release-date field. This
is the first episode's publish time, which is the closest available proxy — most
titles publish all episodes in one batch.

**Is scraping this legal?** The Actor extracts publicly available catalog
metadata. As always, consult your own counsel for your specific use case.

# Actor input Schema

## `mode` (type: `string`):

What to scrape. **Trending** reads the homepage rails and every curated channel (~90 editorially-picked titles, the cheapest and most useful default). **By category** scrapes the genres you pick — GoodShort caps every genre listing at 96 unique titles. **Full catalog** crawls all 11 genres and then sweeps tag listings, which are almost entirely disjoint from the genre catalog and are the only way past ~437 titles. **Specific URLs** scrapes the GoodShort URLs you provide. **Search** resolves titles by keyword (GoodShort's public search returns at most 3 results per keyword).

## `categories` (type: `array`):

Which genres to scrape. Each yields up to 96 unique titles — GoodShort's own ceiling, not a limit of this Actor. Several genres (Action, Thriller, Superpower, Suspense, Sci-Fi) hold fewer than 10 titles in total.

## `startUrls` (type: `array`):

GoodShort URLs to scrape. Accepts title pages (https://www.goodshort.com/drama/{slug}-{id}), category listings (/dramas/{slug}), tag listings (/tag/{slug}), the tag index (/tags/all) and channels (/channel/{slug}).

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

Keywords to resolve. **Note:** GoodShort's public search endpoint is an autocomplete — it returns a maximum of 3 results per keyword and does not paginate. Use it to resolve a title you already know by name, not for discovery.

## `maxItems` (type: `integer`):

Maximum number of titles to store. This caps your cost — 1 stored title = 1 charge.

## `maxTagsToCrawl` (type: `integer`):

GoodShort exposes 73 pages of ~2,000 tag slugs. Tag listings overlap the genre catalog by only ~2%, so sweeping them is the scale lever — but a full sweep is enormous. Each tag yields up to ~97 titles across 10 pages. Set to 0 to skip tags and crawl genres only.

## `enrichFromDetailPage` (type: `boolean`):

Adds one request per title. Required for **follower counts** on homepage/channel results (the rail payload omits them) and for the first-episode publish date. Turn off for the fastest, cheapest run.

## `language` (type: `string`):

Only English is supported. GoodShort's localisation is not URL-prefix based, so no other language can be requested reliably.

## `extractionMode` (type: `string`):

**Server state** parses the page's embedded JSON — full fidelity, recommended. **JSON-LD + DOM fallback** reads schema.org markup and page selectors instead; use it only if GoodShort changes its page structure. The fallback loses tags, follower counts and the exact integer view count (the DOM only exposes GoodShort's rounded display figure).

## `proxyConfiguration` (type: `object`):

Apify Proxy. GoodShort serves plain HTML with no bot challenge, so the default datacenter proxy is enough; switch to residential if you hit blocks on a large run.

## Actor input object example

```json
{
  "mode": "trending",
  "categories": [
    "all"
  ],
  "startUrls": [],
  "searchQueries": [],
  "maxItems": 200,
  "maxTagsToCrawl": 50,
  "enrichFromDetailPage": true,
  "language": "en",
  "extractionMode": "state",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped titles in JSON.

## `resultsCsv` (type: `string`):

All scraped titles as a CSV export.

## `viewInConsole` (type: `string`):

Open the run and its dataset in the Apify Console.

# 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 = {
    "categories": [
        "all"
    ],
    "startUrls": [],
    "searchQueries": [],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("signalbench/goodshort-scraper").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 = {
    "categories": ["all"],
    "startUrls": [],
    "searchQueries": [],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("signalbench/goodshort-scraper").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 '{
  "categories": [
    "all"
  ],
  "startUrls": [],
  "searchQueries": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call signalbench/goodshort-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/6rhh4CmdL1rrvRKVO/builds/eNSN3bJV3QAho89IG/openapi.json
