# Dzen Scraper: Channel Stats, Articles, Transcripts (`firsthand/dzen-scraper`) Actor

Dzen scraper and dzen.ru API alternative (Yandex Zen): views, likes, comments and subscribers for channels, articles, posts, videos and shorts, read-throughs for articles, full article text and transcripts of videos with Dzen subtitles. No login, no browser, no start fee.

- **URL**: https://apify.com/firsthand/dzen-scraper.md
- **Developed by:** [Firsthand](https://apify.com/firsthand) (community)
- **Categories:** Social media, Videos, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 publications

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

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

## Dzen Scraper: Channel Stats, Articles, Transcripts

Dzen Scraper turns public [Dzen](https://dzen.ru/) (ex Yandex Zen) pages into clean rows: views, likes, comments
and channel subscribers for articles, posts, videos and shorts, read-throughs for articles and posts, plus the full
article text and transcripts of videos that have Dzen's own Russian subtitles. Paste channel links or publication links and export
to JSON, CSV or Excel, or call it as a Dzen API from your code.

No Yandex account, no browser and no proxy are needed: runs are fast and cheap, and there is **no start fee**.

### What you get

- **Channels**: articles, videos and shorts of a channel, newest first, page by page, with the channel name, link
  and subscriber count in each row. Posts are looked up in the latest 200 entries of the channel feed.
- **Engagement**: `views`, `likes`, `comments`, `engagementRate`. Articles and posts also have `viewsTillEnd`
  (read to the end) and `readThroughRate`; Dzen does not show these for videos and shorts.
- **Content**: title, lead text, full article and post text, read time, video duration, cover image, publication
  time. Video description and tags come with **Open every publication** or a direct video link, when the author
  set them.
- **Video transcripts**: the transcript with timestamps for videos that have subtitles on Dzen. `hasSubtitles`
  in every video row tells you which ones do. No speech recognition fees.
- **Familiar fields**: `contentId`, `contentType`, `contentUrl`, `author`, `authorUrl`, `authorSubscribers`,
  `publishedAt`, `engagementRate`, `inputUrl` use the names found in two popular Dzen actors, so moving a pipeline
  takes little work. Some values differ, so check `contentId`, `authorId` and `status` if you switch.

### How to use Dzen Scraper

1. Paste links into **Dzen links**, one per line. Supported:
   - channels: `https://dzen.ru/tass`, `https://dzen.ru/id/5ddebbefc429860a2f8e4c3c`, or just `tass`; a link with
     `?tab=shorts` or `?tab=videos` takes only that type;
   - articles `https://dzen.ru/a/...`, posts `https://dzen.ru/b/...`, videos `https://dzen.ru/video/watch/...`,
     shorts `https://dzen.ru/shorts/...`;
   - old `zen.yandex.ru/...` and mobile `m.dzen.ru/...` links.
2. For channels, choose **What to take from channels** (articles, videos, shorts, posts) and
   **Max publications per channel and type**.
3. Turn on **Add video transcripts** if you need the text of videos, and **Open every publication** if you need
   complete article text, exact publication time and video descriptions from channels.
4. Click **Start** and download the dataset.

### Dzen channel statistics

Channel rows come straight from Dzen's channel feed, 20 publications per request, so a channel with hundreds of
articles is read in seconds. Each row has views, read-throughs, likes and comments as Dzen shows them on the
channel page.

### Dzen video transcript

With **Add video transcripts** on, every video with subtitles gets `transcript` (plain text), `transcriptSegments`
(`start`, `end`, `text`), `transcriptLanguage` and `transcriptSource` (`dzen_auto_subtitles`).

`transcriptStatus` tells what happened: `ok`, `no_subtitles` (no track on Dzen), `empty_subtitles` (the track has no
speech), `subtitles_unavailable` (the download failed), `subtitles_wrong_video` (Dzen returned a track of another
video), `skipped_max_charge` (the run's maximum cost left no room). The transcript is charged only with `ok`; the
video row itself is a normal paid row in every case.

Not every video has subtitles. In a sample of 58 videos from 4 channels on October 31, 2026, 30 had them, and it
depends on the channel: 15 of 15 on one, 1 of 13 on another. Shorts had none (0 of 60), so shorts return
`no_subtitles`. Run the channel without transcripts first and check `hasSubtitles` if you need to know in advance.

### Example output

A video and an article from a real run, long texts shortened here:

```json
[
  {
    "platform": "dzen",
    "contentType": "video",
    "contentId": "6a51d216dc87c335f3ac8f2e",
    "contentUrl": "https://dzen.ru/video/watch/6a51d216dc87c335f3ac8f2e",
    "title": "Закон Бернулли",
    "author": "GetAClass | Физика в опытах",
    "authorId": "5da40fd8bc251465cd7975ed",
    "authorUrl": "https://dzen.ru/getaclass",
    "authorSubscribers": 18854,
    "views": 164381,
    "viewsTillEnd": null,
    "readThroughRate": null,
    "likes": 238,
    "comments": 26,
    "engagementRate": 0.16,
    "publishedAt": "2026-07-11T05:19:30Z",
    "timeToReadSeconds": null,
    "durationSeconds": 347,
    "textPreview": "Закон Бернулли устанавливает зависимость между скоростью стационарного потока жидкости и её давлением. Согласно этому за...",
    "text": null,
    "tags": [
      "физика",
      "наука",
      "принцип бернулли",
      "уравнение непрерывности"
    ],
    "imageUrl": "https://avatars.dzeninfra.ru/get-zen_doc/271828/pub_6a51d216dc87c335f3ac8f2e_6a51d234c5f9831d7439d1ef/smart_crop_516x290",
    "hasSubtitles": true,
    "inputUrl": "https://dzen.ru/video/watch/6a51d216dc87c335f3ac8f2e",
    "transcript": "Что будет, если между двумя шарами, висящими на нитях, направить сильную струю воздуха? Кажется, что струя растолкнет ша...",
    "transcriptSegments": [
      {
        "start": 21.92,
        "end": 23.68,
        "text": "Что будет, если между двумя шарами,"
      },
      {
        "start": 23.7,
        "end": 26.25,
        "text": "висящими на нитях, направить сильную"
      }
    ],
    "transcriptLanguage": "ru",
    "transcriptSource": "dzen_auto_subtitles",
    "transcriptStatus": "ok",
    "status": "ok",
    "scrapedAt": "2026-10-31T07:31:27Z"
  },
  {
    "platform": "dzen",
    "contentType": "article",
    "contentId": "afRiHXixAFfUTmXO",
    "contentUrl": "https://dzen.ru/a/afRiHXixAFfUTmXO",
    "title": "Овощи, которые стоит сажать рядом друг с другом 🍅🌿",
    "author": "Садовый клуб. Вероника Поливкина",
    "authorId": "5ddebbefc429860a2f8e4c3c",
    "authorUrl": "https://dzen.ru/id/5ddebbefc429860a2f8e4c3c",
    "authorSubscribers": 91419,
    "views": 24889,
    "viewsTillEnd": 17157,
    "readThroughRate": 68.93,
    "likes": 316,
    "comments": 3,
    "engagementRate": 1.28,
    "publishedAt": "2026-05-06T05:30:37.272Z",
    "timeToReadSeconds": 81,
    "durationSeconds": null,
    "textPreview": "Грамотное соседство на грядках — это не просто удобство, а настоящий способ повысить урожай, защитить растения от вредит...",
    "text": "Грамотное соседство на грядках — это не просто удобство, а настоящий способ повысить урожай, защитить растения от вредит...",
    "tags": null,
    "imageUrl": "https://avatars.dzeninfra.ru/get-zen-pub-og/271828/pub_69f4621d78b10057d44e65ce_69facb55e7c98d7e5ac29d44/optimize",
    "inputUrl": "https://dzen.ru/a/afRiHXixAFfUTmXO",
    "status": "ok",
    "scrapedAt": "2026-10-31T07:31:21Z"
  }
]
```

### Pricing

Pay per result. There is no start fee, so a run on one link costs one row, while other Dzen actors in Apify Store charge up to $0.06 per run start:

| Event | Price | When |
|---|---|---|
| Publication | $0.0015 per row | each article, post, video or short returned |
| Transcript | $0.003 per video | only when a transcript is returned |

Failed links, deleted publications and links Dzen refused are not charged. A video without subtitles is charged
as a publication, without the transcript fee. Set **Max publications in total** or the run's maximum cost to cap
the spend. If a stopped run is resurrected, it continues and does not charge the same publications again.

### Dzen API for developers

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")  # apify-client 3.x
run = client.actor("firsthand/dzen-scraper").call(run_input={
    "urls": ["https://dzen.ru/tass", "https://dzen.ru/a/afRiHXixAFfUTmXO"],
    "contentTypes": ["articles", "videos"],
    "maxItemsPerChannel": 50,
    "includeTranscripts": True,
})
for row in client.dataset(run.default_dataset_id).iterate_items():
    if row["status"] == "ok":
        print(row["contentType"], row["views"], row["title"])
```

Input names from other Dzen actors are accepted too: `startUrls`, `channelContent`, `fetchArticleText`,
`maxResults`, `proxy`.

### Good to know

- Only public pages are read, the same ones anyone can open without logging in. Personal data is limited to what
  Dzen shows publicly (channel names and public counters). Make sure your use complies with Dzen's terms and with
  data protection law such as GDPR.
- Counters are taken at the time of the run.
- A proxy is optional. It is used only if Dzen does not answer a direct request.
- `publishedAt` of an article read from a channel is the date Dzen created it, which can be earlier than the
  publication time (by up to 2.5 days in our sample). Article links and **Open every publication** give the exact time.
- Post views exist only on the post page, so each post is opened one by one; posts take longer than other types.
- Dzen sometimes reports more read-throughs than views on small publications. The raw counters are kept and
  `readThroughRate` stays empty in that case.
- Dzen shows likes only when there are some: a publication with no likes returns `likes: 0`.
- Every row has `status`. Links that fail come back as rows with `status` and `error` and are not charged:
  `not_found`, `blocked` (Dzen refused), `error`, `not_processed` (the timeout, the maximum cost or **Max publications
  in total** came first). The run's `SUMMARY` record lists inputs, errors and traffic.
- If no link gives a publication, the run ends as failed with the reason.
- Transcripts are Dzen's automatic subtitles: punctuation is automatic, names may be misspelled, and parts of news-style videos can be missing (8% and 36% of spoken words in two news videos we checked against speech recognition; none in a talking-head video).

# Actor input Schema

## `urls` (type: `array`):

Channels (https://dzen.ru/tass, https://dzen.ru/id/..., or just the channel name), articles (dzen.ru/a/...), posts (dzen.ru/b/...), videos (dzen.ru/video/watch/...) and shorts (dzen.ru/shorts/...). A channel link with ?tab=shorts or ?tab=videos takes only that type. Old zen.yandex.ru and m.dzen.ru links work too. One per line.

## `contentTypes` (type: `array`):

For channel links only. Empty means articles, videos and shorts.

## `maxItemsPerChannel` (type: `integer`):

Limit for each channel and each content type, newest first. Empty or 0 means no limit.

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

Charged rows across the whole run. 1000 if empty, 0 means no limit. Links left over come back as not_processed rows, not charged.

## `includeTranscripts` (type: `boolean`):

Videos with subtitles on Dzen get the full transcript with timestamps. About half of videos have them, shorts do not. Charged only when a transcript is returned.

## `includeFullText` (type: `boolean`):

Opens each publication of a channel for the complete article text, the exact publication time and video descriptions. Slower. Direct links always include these.

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

Dzen works without a proxy. If you set one, it is used only when Dzen does not answer a direct request.

## Actor input object example

```json
{
  "urls": [
    "https://dzen.ru/getaclass",
    "https://dzen.ru/a/afRiHXixAFfUTmXO",
    "https://dzen.ru/video/watch/6a51d216dc87c335f3ac8f2e"
  ],
  "contentTypes": [
    "articles",
    "videos"
  ],
  "maxItemsPerChannel": 10,
  "maxItems": 100,
  "includeTranscripts": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

# API

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

## JavaScript example

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

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

// Prepare Actor input
const input = {
    "urls": [
        "https://dzen.ru/getaclass",
        "https://dzen.ru/a/afRiHXixAFfUTmXO",
        "https://dzen.ru/video/watch/6a51d216dc87c335f3ac8f2e"
    ],
    "contentTypes": [
        "articles",
        "videos"
    ],
    "maxItemsPerChannel": 10,
    "maxItems": 100,
    "includeTranscripts": true,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("firsthand/dzen-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 = {
    "urls": [
        "https://dzen.ru/getaclass",
        "https://dzen.ru/a/afRiHXixAFfUTmXO",
        "https://dzen.ru/video/watch/6a51d216dc87c335f3ac8f2e",
    ],
    "contentTypes": [
        "articles",
        "videos",
    ],
    "maxItemsPerChannel": 10,
    "maxItems": 100,
    "includeTranscripts": True,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("firsthand/dzen-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 '{
  "urls": [
    "https://dzen.ru/getaclass",
    "https://dzen.ru/a/afRiHXixAFfUTmXO",
    "https://dzen.ru/video/watch/6a51d216dc87c335f3ac8f2e"
  ],
  "contentTypes": [
    "articles",
    "videos"
  ],
  "maxItemsPerChannel": 10,
  "maxItems": 100,
  "includeTranscripts": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call firsthand/dzen-scraper --silent --output-dataset

```

## MCP server setup

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