# SnackVideo Scraper - Profiles, Videos, Hashtags & Trending (`fanndev/snackvideo-scraper`) Actor

Scrape SnackVideo without login: creator profiles with every video and playlist, single videos, hashtag feeds, keyword search, the For You trending feed and playlists. Views, likes, comments, shares, captions, hashtags, music, and download URLs.

- **URL**: https://apify.com/fanndev/snackvideo-scraper.md
- **Developed by:** [Faisal Ahdan naufal](https://apify.com/fanndev) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.30 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## SnackVideo Scraper - Profiles, Videos, Hashtags, Search & Trending

Scrape public data from [SnackVideo](https://www.snackvideo.com) with **no login and no account**. One actor, six modes:

| Mode | Input | What you get |
|---|---|---|
| **Profile** | usernames or profile URLs | Creator stats (followers, following, video count) + **every** video, newest first + their playlists |
| **Video** | video URLs, share links or IDs | Full details for each video |
| **Hashtag** | hashtags | Every video under a hashtag - the most complete way to collect a topic (thousands per hashtag) |
| **Search** | keywords | Videos SnackVideo recommends for the keyword (see note below) |
| **Trending** | nothing | The For You feed for the proxy's country |
| **Playlist** | playlist URLs or IDs | Playlist info + every video in it |

Every video includes views, likes, comments, shares, caption, hashtags, upload time, duration, creator, music, a direct MP4 URL and a cover image.

### Input example

```json
{
  "mode": "profile",
  "usernames": ["https://www.snackvideo.com/@AgathisDammaraa41198"],
  "maxItems": 100,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

### Output example (one video)

```json
{
  "_input": "5256413826759439232",
  "_source": "S1-api-slides",
  "_scrapedAt": "2026-09-24T19:07:33Z",
  "recordType": "VIDEO",
  "id": "5256413826759439232",
  "videoUrl": "https://www.snackvideo.com/@AgathisDammaraa41198/video/5256413826759439232",
  "profileUrl": "https://www.snackvideo.com/@AgathisDammaraa41198",
  "captionText": "KALAU MAU LIHAT laki2 yang SUKSES LIHATLAH DARI isterinya゚##donggggggg",
  "createdAt": "2026-09-21T22:11:04Z",
  "hashtags": ["donggggggg"],
  "durationMs": 24838,
  "playUrl": "https://aws-br-cdn.kwai.net/upic/2026/09/22/06/BMjAy...mp4?tag=...",
  "coverUrl": "https://aws-br-pic.kwai.net/upic/2026/09/22/06/BMjAy...webp",
  "view_count": 16099,
  "like_count": 297,
  "comment_count": 19,
  "forward_count": 266,
  "kwai_id": "AgathisDammaraa41198",
  "user_name": "Agathis Dammara",
  "photo_id_str": "5256413826759439232",
  "... 40 more SnackVideo fields": "music, ext_params, headurls, main_mv_urls, ..."
}
```

`recordType` is `VIDEO`, `PROFILE`, `PLAYLIST` or `ERROR`. An input that can't be scraped (deleted video, unknown user, empty hashtag) produces an `ERROR` row with `_error` = `not_found` / `no_results` / `invalid_input` instead of being dropped silently.

### Good to know

- **Search is a recommendation feed, not an exact search.** SnackVideo returns different videos for the same keyword on every call, and only some of them mention it (it returns videos even for nonsense words). Each search result has `keywordMatched`; switch on **Only keyword matches** to keep just those. For complete, repeatable results on a topic, use **Hashtag** mode.
- **Proxy country = content region.** Trending and Search follow the country of the IP (Indonesia, Pakistan, India, Bangladesh...). Set the proxy country to choose. SnackVideo doesn't block direct requests, so the proxy is about region, not access.
- **Comments are not available.** SnackVideo returns an empty comment list to anyone who isn't logged in, so this actor gives `comment_count` but not comment text.
- **Playlists:** SnackVideo lists up to 20 playlists per creator.
- **Profile video count:** the feed can end a few videos short of `publicVideos` (e.g. 60 of 64); that's all SnackVideo serves.
- `playUrl` and other media URLs are signed and expire after a few days, so download media soon after scraping.
- Use `photo_id_str` / `id` rather than `photo_id`. It is a 64-bit number that spreadsheets and JavaScript round off.

### How it works (technical)

SnackVideo (Kuaishou's international app) is a Nuxt site backed by a JSON API on the same domain (`/rest/o/w/...`). Recon on 2026-09-25 found no WAF (Tengine origin, no Cloudflare/Akamai/DataDome) and no request signing: plain HTTP returns 200. The actor still sends browser-grade TLS (curl\_cffi `chrome124`, rotating to `safari17_0` / `firefox133` / `chrome99_android` on any 403 or challenge page), retries with exponential backoff and jitter, and switches to a new proxy IP on transport errors or HTTP 429.

# Actor input Schema

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

What to scrape. No SnackVideo account or login is used. Each mode reads its own input field below.

## `usernames` (type: `array`):

For mode 'profile'. A handle (AgathisDammaraa41198), @handle, or a profile URL such as https://www.snackvideo.com/@AgathisDammaraa41198.

## `videoUrls` (type: `array`):

For mode 'video'. A video URL (https://www.snackvideo.com/@user/video/5256413826759439232), a share link, or the numeric video ID.

## `hashtags` (type: `array`):

For mode 'hashtag'. With or without '#', or a https://www.snackvideo.com/topic/... URL.

## `searchKeywords` (type: `array`):

For mode 'search'. NOTE: SnackVideo's search is a recommendation feed, not an exact index - results change on every run and only some mention the keyword. Each record carries keywordMatched; switch on 'Only keyword matches' to keep just those. For exhaustive results on a topic use mode 'hashtag'.

## `playlistUrls` (type: `array`):

For mode 'playlist'. https://www.snackvideo.com/@user/playlist/<id> or the numeric playlist ID. Profile mode also outputs a creator's playlists with their URLs.

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

Maximum videos to save for each username, hashtag, keyword, playlist (or for the trending feed).

## `includeVideos` (type: `boolean`):

Profile mode: also save the creator's videos (newest first, up to 'Max videos per input'). Turn off for profile stats only.

## `includePlaylists` (type: `boolean`):

Profile mode: also save the creator's playlists (SnackVideo shows up to 20 per creator).

## `onlyKeywordMatches` (type: `boolean`):

Search mode: keep only videos whose caption contains every word of the keyword.

## `includeStreamManifest` (type: `boolean`):

Keep the raw per-quality stream list (transcode\_manifest\_info). Large and its URLs expire; playUrl already gives a playable MP4.

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

How many inputs are processed in parallel.

## `maxRetries` (type: `integer`):

Retries with exponential backoff, rotating IP and TLS fingerprint, before an input is marked failed.

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

SnackVideo does not block unproxied requests. The proxy country decides WHICH regional content the Trending and Search feeds return (e.g. ID = Indonesia, PK = Pakistan, IN = India).

## Actor input object example

```json
{
  "mode": "profile",
  "usernames": [
    "https://www.snackvideo.com/@AgathisDammaraa41198"
  ],
  "videoUrls": [
    "https://www.snackvideo.com/@AgathisDammaraa41198/video/5256413826759439232"
  ],
  "hashtags": [
    "kucing"
  ],
  "searchKeywords": [
    "kucing lucu"
  ],
  "playlistUrls": [
    "https://www.snackvideo.com/@AgathisDammaraa41198/playlist/164068021363540803"
  ],
  "maxItems": 50,
  "includeVideos": true,
  "includePlaylists": true,
  "onlyKeywordMatches": false,
  "includeStreamManifest": false,
  "maxConcurrency": 3,
  "maxRetries": 6,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Every video, profile, playlist and diagnostic record from this run.

# 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 = {
    "mode": "profile",
    "usernames": [
        "https://www.snackvideo.com/@AgathisDammaraa41198"
    ],
    "videoUrls": [
        "https://www.snackvideo.com/@AgathisDammaraa41198/video/5256413826759439232"
    ],
    "hashtags": [
        "kucing"
    ],
    "searchKeywords": [
        "kucing lucu"
    ],
    "playlistUrls": [
        "https://www.snackvideo.com/@AgathisDammaraa41198/playlist/164068021363540803"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("fanndev/snackvideo-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 = {
    "mode": "profile",
    "usernames": ["https://www.snackvideo.com/@AgathisDammaraa41198"],
    "videoUrls": ["https://www.snackvideo.com/@AgathisDammaraa41198/video/5256413826759439232"],
    "hashtags": ["kucing"],
    "searchKeywords": ["kucing lucu"],
    "playlistUrls": ["https://www.snackvideo.com/@AgathisDammaraa41198/playlist/164068021363540803"],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("fanndev/snackvideo-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 '{
  "mode": "profile",
  "usernames": [
    "https://www.snackvideo.com/@AgathisDammaraa41198"
  ],
  "videoUrls": [
    "https://www.snackvideo.com/@AgathisDammaraa41198/video/5256413826759439232"
  ],
  "hashtags": [
    "kucing"
  ],
  "searchKeywords": [
    "kucing lucu"
  ],
  "playlistUrls": [
    "https://www.snackvideo.com/@AgathisDammaraa41198/playlist/164068021363540803"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call fanndev/snackvideo-scraper --silent --output-dataset

```

## MCP server setup

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