# NetShort Scraper — Catalog, Genres, Episodes, Follows & Likes (`signalbench/netshort-scraper`) Actor

Scrape the NetShort short-drama catalog: series metadata, genres, synopses, episode counts, follow & like counts, release dates, 16 locales. Server-rendered HTML (no browser) — fast and cheap.

- **URL**: https://apify.com/signalbench/netshort-scraper.md
- **Developed by:** [SignalBench](https://apify.com/signalbench) (community)
- **Categories:** Videos, Other
- **Stats:** 1 total users, 0 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

## NetShort Scraper — Catalog, Genres, Episodes, Follows & Likes

Scrape the **NetShort** vertical short-drama catalog without the app: **title
metadata, genre labels, full synopses, episode counts, follow counts, like
counts, release dates and 16-locale availability** — structured, ready for
analysis. Reads the site's own server-rendered payload (**no browser**), so runs
are fast, cheap and reliable. Export as **JSON, CSV, Excel or XML**, or pull it
straight through the Apify API into your app, agent, notebook or spreadsheet.

This is the missing **NetShort API / NetShort data** source. NetShort (NETSTORY
PTE. LTD.) publishes roughly **51,000 English series** and there has been no
structured-data coverage of it at all. If you're a studio, licensor, casting
researcher 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. Delisted,
> invalid and failed pages are never stored, so they are never charged.

### What it scrapes

| Field | Description |
|---|---|
| **id / title** | Series ID (19-digit, kept as a string) and title, with `(Dubbed)` split out into `isDubbed` |
| **description** | Full synopsis — the real one, not the truncated SEO meta text |
| **genres / genreIds / tags** | Label names plus their stable IDs (Contract Lovers, Tragic Love, Werewolf, …) |
| **follows / likes** | Platform-reported follow ("chase") and like counts, parsed to integers, with the verbatim `followsDisplay` / `likesDisplay` strings alongside |
| **episodes** | Number of episodes (plus the full per-episode list, optionally) |
| **releaseDate** | Series release date, ISO-8601 |
| **language / availableLanguages** | This record's locale, and every locale the series ships in — a strong signal of how hard a title is being pushed internationally |
| **libraryId** | Groups dub and locale variants of the same underlying production |
| **cover / url / fullEpisodesUrl** | Cover image and canonical URLs |

### Two fields NetShort does not publish

Read this before you wire the output into a cross-platform comparison:

- **`views` is always `null`.** NetShort exposes **no view count anywhere** on
  its public web catalog — only follows and likes. The field is present so
  records line up with view-carrying platforms, but a synthetic number derived
  from follows would be indistinguishable from real data downstream, so we don't
  invent one. **Rank NetShort titles by `follows`.**
- **`cast` is always `[]`.** NetShort publishes no actor or cast data on the web.

Also worth knowing: freshly published titles appear to carry a **display floor
around 2.0K** follows/likes, so treat the first few days of a title's engagement
numbers as noise rather than signal.

### Modes

- **Full catalog (all genres)** — walks every genre on NetShort. Set **Max
  results** to cap size and cost. Turn on **Exhaustive** to seed from NetShort's
  sitemaps instead, which also reaches titles carrying no genre label.
- **By genre** — scrapes only the genres you list, by name (`Revenge`,
  `Sweet Romance`, `Werewolf`, `Contract Lovers`, …) or by raw label ID.
  Names are resolved live: first against NetShort's genre grid, then against its
  full tag sitemap, so genres missing from the on-site grid still work.
- **Specific URLs** — scrape exactly the URLs you provide. `/episode/`,
  `/full-episodes/`, an `-ep-N` watch URL and `/drama/` listing URLs are all
  accepted and normalized for you.

All three work in any of **16 locales** (`en_US`, `es_ES`, `pt_PT`, `fr_FR`,
`de_DE`, `it_IT`, `tr_TR`, `ar_AE`, `id_ID`, `ms_MY`, `th_TH`, `vi_VN`, `ja_JP`,
`ko_KR`, `zh_CN`, `zh_TW`). Each locale is a separate catalog with its own series
IDs, titles and genre labels.

### Input example

```json
{
    "mode": "byGenre",
    "genres": ["Revenge", "Sweet Romance"],
    "maxItems": 500,
    "language": "en_US"
}
```

### Output example

```json
{
    "platform": "netshort",
    "id": "1808055875428081665",
    "title": "Right Beside Me",
    "url": "https://netshort.com/episode/right-beside-me-1808055875428081665",
    "views": null,
    "follows": 143100,
    "followsDisplay": "143.1K",
    "likes": 27000,
    "likesDisplay": "27.0K",
    "episodes": 68,
    "genres": ["Contract Lovers", "Tragic Love", "Love After Marriage"],
    "genreIds": ["1983832091939561474", "1983832091947950083", "1983832091075534850"],
    "releaseDate": "2024-12-20T12:00:00.000Z",
    "cast": [],
    "description": "Eddie and Jenny grew up together in an orphanage. Years later, fate brought them back as Edison, a wealthy CEO, and Sydney, his wife from a powerful adoptive family...",
    "language": "en_US",
    "availableLanguages": ["en_US", "es_ES", "pt_PT", "fr_FR", "de_DE", "it_IT", "tr_TR", "ar_AE", "id_ID", "ms_MY", "th_TH", "vi_VN", "ja_JP", "ko_KR", "zh_CN", "zh_TW"],
    "libraryId": "1894647721228726273",
    "isDelisted": false,
    "extractionMethod": "flight",
    "scrapedAt": "2026-08-21T18:04:00.000Z"
}
```

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** — see which tropes and titles are
  pulling follows before deciding what to greenlight.
- **Licensors & distributors** — catalog intelligence across a market with
  almost no public data.
- **Localization & international teams** — `availableLanguages` and `libraryId`
  show exactly which titles NetShort is pushing into which markets.
- **Market & trend analysts** — engagement per title, genre and release date.

### How it works

NetShort is a Next.js App Router site that server-renders every page, so a
cookie-less request with no JavaScript already contains the complete series
object. The Actor reads that payload directly with a browser-grade HTTP
fingerprint (via Crawlee) — no headless browser to render or break, which is why
runs are fast and cheap. Genre listings paginate server-side, so pagination is
computed rather than clicked.

It scrapes only **public catalog metadata** — no video assets, no user data, no
account endpoints. It also never touches NetShort's internal JSON API, which the
site's `robots.txt` disallows; the public HTML returns the same data.

Every record carries an `extractionMethod` field. `"flight"` is the full-fidelity
path; `"jsonld"` means the Actor fell back to the page's structured-data block
(title, genres and episode count survive; follow and like counts do not). It is
there so a silent degradation is visible in your data rather than hidden.

### 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 NetShort API?** Not a public one. This Actor is the practical,
available-today way to get structured NetShort data.

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

**Why is `views` null?** NetShort doesn't publish view counts on the web at all.
Use `follows`. See the section above.

**Are the follow and like counts exact?** They're NetShort's own reported
figures, rendered abbreviated (`143.1K`), so the parsed integer carries the
platform's rounding — `143.1K` is somewhere in 143,050–143,149. The verbatim
string is kept in `followsDisplay` / `likesDisplay`.

**Why are `genres` and `tags` identical?** NetShort runs a single label taxonomy
and doesn't distinguish the two. Both fields are populated so records merge
cleanly with platforms that do.

**Is scraping this legal?** The Actor extracts publicly available catalog
metadata and honours NetShort's `robots.txt`. As always, consult your own counsel
for your specific use case.

### Development

```bash
npm install
npm test          # builds, then runs the extraction tests against saved page fixtures
npm run start:dev # local run; put input in storage/key_value_stores/default/INPUT.json
```

# Actor input Schema

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

What to scrape. **Full catalog** walks every genre on NetShort. **By genre** scrapes only the genres you list. **Specific URLs** scrapes exactly the NetShort URLs you provide.

## `genres` (type: `array`):

Genre names as shown on NetShort (e.g. `Revenge`, `Sweet Romance`, `Werewolf`, `Historical`), or raw label IDs. Resolved live against netshort.com/drama/all-plots, so a name that no longer exists is reported with the current list. NetShort ships several distinct labels under one display name (there are two `Revenge` labels); a name scrapes all of them and results are deduplicated by series ID.

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

NetShort `/episode/`, `/full-episodes/` or `/drama/` URLs. An `-ep-N` watch URL is collapsed to its series page automatically.

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

Maximum number of titles to store. This caps your cost — 1 stored title = 1 charge. The English catalog is roughly 51,000 titles.

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

Which localized NetShort catalog to walk. Each locale is a separate set of series records with its own IDs, titles and genre labels.

## `includeEpisodeList` (type: `boolean`):

Add the full per-episode array (episode ID, number, locked flag, thumbnail). Large — a typical title has 50–90 episodes.

## `includeDelisted` (type: `boolean`):

Keep series NetShort has marked as delisted. Off by default — delisted titles are skipped and never charged.

## `exhaustive` (type: `boolean`):

In **Full catalog** mode, seed from NetShort's sitemaps instead of the genre index. Slower and heavier, but reaches titles that carry no genre label. Leave off unless you need true catalog completeness.

## `maxConcurrency` (type: `integer`):

Parallel requests. Raise for speed, lower if NetShort starts rate-limiting.

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

Apify Proxy. NetShort is fronted by Cloudflare; if you see 403/429 responses, switch to **Residential**.

## Actor input object example

```json
{
  "mode": "fullCatalog",
  "genres": [
    "Revenge",
    "Sweet Romance"
  ],
  "startUrls": [],
  "maxItems": 100,
  "language": "en_US",
  "includeEpisodeList": false,
  "includeDelisted": false,
  "exhaustive": false,
  "maxConcurrency": 10,
  "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 = {
    "genres": [
        "Revenge",
        "Sweet Romance"
    ],
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("signalbench/netshort-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 = {
    "genres": [
        "Revenge",
        "Sweet Romance",
    ],
    "startUrls": [],
    "proxyConfiguration": { "useApifyProxy": True },
}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,signalbench/netshort-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/DQpLJtadnUF6KHb7G/builds/gaATVWkLmDMvPE1zx/openapi.json
