# TikTok Stories Scraper (`lance_api/tiktok-stories-scraper`) Actor

Scrape active public TikTok Stories from up to 200 profiles in one run. Get video and photo media URLs, Story IDs, author data, music, engagement metrics, and clear outcomes for profiles with no active Stories. No TikTok login required.

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

## Pricing

from $4.00 / 1,000 profiles

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

## TikTok Stories Scraper

Collect the **currently active public Stories** of TikTok profiles — video and photo — in one run, as
a clean structured Dataset.

Give it usernames, `@usernames` or full profile URLs. You get one row per Story with media URLs,
engagement, music and author data, plus **one explicit outcome row for every profile that had no
Story**, so a quiet profile never looks like a broken run.

- 🎬 **Video and photo Stories** in the same Dataset, each row labelled with a stable `storyType`.
- ⚡ **Batch collection** — up to 200 distinct profiles per run, validated, normalized and deduplicated.
- ✅ **A clear outcome for every profile** — `success`, `no_active_stories`, `private`, `not_found`,
  `invalid` or `failed`. One profile failing never stops the batch.
- 🔀 **Newest or oldest first**, plus an optional per-profile Story limit — both applied locally, with
  no extra requests.
- 💰 **Predictable, per-profile pricing** — you pay for profiles checked, never for the number of
  Stories a creator happened to post. See [Pricing](#pricing).

TikTok Stories disappear after roughly a day, so a run that returns nothing is a normal answer, not an
error. No TikTok login, cookie or session is ever used.

***

### 📌 At a glance

|                      |                                                                                                 |
| -------------------- | ----------------------------------------------------------------------------------------------- |
| **What it collects** | Active public TikTok Stories (video and photo)                                                  |
| **Input**            | TikTok usernames, `@usernames` or profile URLs                                                  |
| **Output**           | JSON rows in the default Dataset: one per Story, plus one outcome row per profile with no Story |
| **Batch size**       | 1–200 distinct profiles per run                                                                 |
| **Duplicate inputs** | Merged — processed once                                                                         |
| **Login required**   | No                                                                                              |
| **Options**          | Story order (newest/oldest), optional per-profile Story limit                                   |
| **Pricing**          | Per-profile pricing + run-start fee; see [Pricing](#pricing)                                    |
| **Best for**         | Monitoring, campaign verification, creator research, data pipelines                             |

***

### 🎯 What this Actor does

| Capability                   | Detail                                                                                                    |
| ---------------------------- | --------------------------------------------------------------------------------------------------------- |
| Active Story collection      | Reads the Stories a public profile has live right now, before they expire.                                |
| Video Stories                | Returns a playable `videoUrl`, cover, duration and engagement for video Stories.                          |
| Photo Stories                | Returns every image of a photo Story in `media.images`, plus a top-level `imageUrl`.                      |
| Multiple Stories per profile | One row per Story. A profile with five live Stories returns five rows.                                    |
| Batch processing             | Check up to 200 profiles together for a single monitoring snapshot.                                       |
| Input normalization          | `name`, `@name`, profile URL and video URL forms all resolve to the same profile.                         |
| De-duplication               | Equivalent inputs collapse to one profile for cleaner batch results.                                      |
| Explicit outcomes            | Profiles without Stories, private profiles, unknown profiles and rejected inputs each get a labelled row. |
| Fault isolation              | A failing profile is reported as `failed`; the rest of the batch continues.                               |
| Story ordering               | Newest first or oldest first, applied to the list already fetched.                                        |
| Per-profile limit            | Optional cap on how many Story rows a profile returns.                                                    |
| Automation ready             | Plain JSON, stable IDs, one Dataset per run — drops into n8n, Make, Zapier, warehouses and LLM pipelines. |

***

### 🚀 Quick start

1. Open the **Input** tab.
2. Add one or more profiles to **TikTok profile usernames**.
3. Leave the options at their defaults for a first run.
4. Click **Start**.
5. Open the **Dataset** tab to see the Stories.

```json
{
  "usernames": ["tiktok", "@nasa", "https://www.tiktok.com/@netflix"]
}
```

Every accepted profile produces at least one row. A profile with no active Story gets a
`profile_status` row with `status: "no_active_stories"`.

***

### 📦 What you get

One row per delivered Story gives you media links, engagement and creator context for your own
reporting or analysis:

```json
{
  "rowType": "story",
  "profileUsername": "mercadolivre",
  "storyId": "7698748937192279316",
  "storyType": "photo",
  "status": "success",
  "createdAt": "2026-10-20T13:57:57.000Z",
  "imageUrl": "https://<temporary-media-url>",
  "views": 13315,
  "likes": 113,
  "comments": 0,
  "shares": 1,
  "saves": 0,
  "author": {
    "userId": "6926981670042436614",
    "username": "mercadolivre",
    "nickname": "Mercado Livre",
    "verified": true,
    "followers": 5015608
  },
  "media": { "type": "photo", "images": ["https://<temporary-media-url>"] }
}
```

*Illustrative output example; temporary media URLs are placeholders. Field availability varies.*

Three Dataset views are provided:

| View          | Shows                                                                       |
| ------------- | --------------------------------------------------------------------------- |
| **Stories**   | username, Story ID, type, created time, views, likes, comments, media links |
| **Media**     | video, cover and image URLs, plus any expiry stated by the URL              |
| **Analytics** | views, likes, comments, shares, saves, created time, row status             |

***

### 📋 Output reference

#### Story rows (`rowType: "story"`)

| Field               | Type            | Nullable | Meaning                                                                               |
| ------------------- | --------------- | -------- | ------------------------------------------------------------------------------------- |
| `profileUsername`   | string          | no       | Canonical (lowercased) TikTok username the Story belongs to.                          |
| `storyId`           | string          | no       | TikTok Story id. Always a string, never a number.                                     |
| `storyType`         | string          | no       | `video` or `photo`. A Story with at least one image is a photo Story.                 |
| `status`            | string          | no       | `success` for a delivered Story.                                                      |
| `createdAt`         | ISO 8601 string | yes      | When the Story was published.                                                         |
| `videoUrl`          | string          | yes      | Playable video URL. `null` for photo Stories.                                         |
| `imageUrl`          | string          | yes      | First photo image URL. `null` for video Stories.                                      |
| `coverUrl`          | string          | yes      | Cover image URL.                                                                      |
| `caption`           | string          | yes      | Story caption or description when the source provides one.                            |
| `views` / `likes`   | integer         | yes      | Counters exactly as reported.                                                         |
| `comments`          | integer         | yes      | Comment count.                                                                        |
| `shares` / `saves`  | integer         | yes      | Share and save counters.                                                              |
| `url`               | string          | yes      | Story page URL when available.                                                        |
| `mediaUrlExpiresAt` | ISO 8601 string | yes      | Expiry parsed from the media URL, when the URL itself states one.                     |
| `author`            | object          | no       | `userId`, `username`, `nickname`, `avatarUrl`, `verified`, `followers`…               |
| `media`             | object          | no       | `type`, `durationMs`, `coverUrl`, `videoUrl`, `images`, `hasWatermark`, `sizeBytes`   |
| `engagement`        | object          | no       | `views`, `likes`, `comments`, `shares`, `saves`, `downloads`                          |
| `music`             | object          | no       | `id`, `title`, `author`, `album`, `playUrl`, `coverUrl`, `durationMs`, `original`     |
| `commercial`        | object          | no       | `isAd`, `brandedContentType`                                                          |
| `mentions`          | object          | no       | `users`, `hashtags`, `anchors`                                                        |
| `rowType`           | string          | no       | `story`.                                                                              |
| `inputUsername`     | string          | yes      | First submitted reference for this profile, with surrounding whitespace trimmed.      |
| `canonicalKey`      | string          | yes      | `tiktok:<username>:<storyId>` — use with `storyId` to match Stories across snapshots. |
| `scrapedAt`         | ISO 8601 string | no       | When the row was written.                                                             |

**Unknown scalar values are `null`; missing lists are empty arrays.** Nested objects remain present
with nullable fields, so your pipeline can distinguish unknown data from a reported zero. Zero counters
stay `0`; impossible physical values (a zero duration or byte size) are treated as unknown and become
`null`.

TikTok identifiers (`storyId`, `author.userId`) are always strings, so a large id is never rounded by
JavaScript number handling.

Nested scalar fields can be `null`, and mention/image lists can be empty. Durations (`durationMs`)
are in milliseconds; `sizeBytes` is in bytes. Counters are counts, and timestamps use ISO 8601 UTC.
`author.userId` lets you join creator records; `storyId` helps deduplicate repeated snapshots.

#### Profile outcome rows (`rowType: "profile_status"`)

Every accepted profile that delivered no Story gets exactly one row:

```json
{
  "rowType": "profile_status",
  "inputUsername": "@nasa",
  "profileUsername": "nasa",
  "canonicalKey": "tiktok:nasa",
  "status": "no_active_stories",
  "outcome": "no_active_stories",
  "error": null,
  "storiesFound": 0,
  "scrapedAt": "2026-10-21T00:22:27.245Z"
}
```

#### Status values

| `status`            | On row           | Meaning                                                         | Next step                                      |
| ------------------- | ---------------- | --------------------------------------------------------------- | ---------------------------------------------- |
| `success`           | `story`          | Story collected.                                                | Use the returned data.                         |
| `no_active_stories` | `profile_status` | Profile exists, no active public Story right now.               | Check again on your next scheduled run.        |
| `private`           | `profile_status` | Profile is private; no content returned.                        | Use a public profile.                          |
| `not_found`         | `profile_status` | Profile could not be found.                                     | Verify the username.                           |
| `invalid`           | `profile_status` | Input is not a usable TikTok profile reference.                 | Correct the input.                             |
| `failed`            | `profile_status` | Data could not be read or the free allowance blocked the check. | Check `error`; retry temporary failures later. |

See [Pricing](#pricing) for the Profile Check rules for these outcomes.

`error` is `null` unless something actually went wrong, so filter on `status` for business outcomes.

#### Error codes

| Code                        | With status | Meaning                                                   |
| --------------------------- | ----------- | --------------------------------------------------------- |
| `INVALID_INPUT`             | `invalid`   | The value is not a usable TikTok profile reference.       |
| `TEMPORARY_SOURCE_ERROR`    | `failed`    | Data could not be read right now. Retry the run later.    |
| `FREE_USAGE_LIMIT_EXCEEDED` | `failed`    | The included free profile allowance was reached.          |
| `FREE_USAGE_CHECK_FAILED`   | `failed`    | The allowance could not be verified. Retry the run later. |

***

### ⚙️ Input reference

| Field                  | Type            | Required | Default  | Limits               |
| ---------------------- | --------------- | -------- | -------- | -------------------- |
| `usernames`            | array of string | yes      | —        | 1–200 input entries  |
| `sortStories`          | string          | no       | `newest` | `newest` or `oldest` |
| `maxStoriesPerProfile` | integer         | no       | —        | ≥ 1                  |

**Prefill is not a default.** The Input form pre-fills `usernames` with
`https://www.tiktok.com/@tiktok`; API callers must supply their own non-empty array.
Leaving `maxStoriesPerProfile` unset returns all available active Stories.

**What counts as a profile reference.** All of these resolve to the same profile:

```
tiktok
@tiktok
https://www.tiktok.com/@tiktok
https://www.tiktok.com/@tiktok/video/7300000000000000000
```

Values are trimmed and lowercased, non-profile links are rejected, and equivalent forms collapse to
one profile. **Duplicates are processed once**, keeping repeated references out of your results. Rejected values still produce an `invalid` row so nothing disappears silently.

#### About the 200-profile limit

The Input schema accepts 1–200 entries, including duplicates. Within that list, equivalent entries
are merged before processing. The runtime also rejects lists with more than 200 distinct profiles
instead of silently dropping the extra profiles. Keep each submitted list within 200 entries.

***

### Optional features

🔧 Two options change what a run returns. Neither costs an extra Actor charge and neither causes an
additional request to the data source — both work on the Story list that was already collected.

#### 🔀 `sortStories` — newest or oldest first

**What it does** — orders the Stories returned for each profile by creation time.

- `newest` (default): the most recent Story appears first. Best when you want to know what a creator
  posted most recently, or when you combine it with a limit of 1.
- `oldest`: the earliest Story that is still online appears first. Best when you are walking a
  creator's current Story sequence in the order it was published.

Stories without a known creation time are placed after dated ones, keeping their original order.

**Cost** — none. This is a local sort of data already in memory: no extra request, no extra billing.

#### ✂️ `maxStoriesPerProfile` — cap the rows per profile

**What it does** — keeps only the first N Stories of the sorted list. For example
`sortStories: "newest"` with `maxStoriesPerProfile: 1` returns only the latest active Story of each
profile, which is the usual choice for a daily monitoring job.

**Cost** — no extra Actor charge. The full active list is read, then trimmed locally; this does not
reduce the Profile Check charge. It reduces Dataset rows, response size and downstream processing.

Leave it empty to keep every active Story.

***

### 🔄 How it works

1. Your input list is validated, normalized and deduplicated.
2. Each accepted profile is checked for currently active public Stories.
3. Stories are ordered per your `sortStories` choice and trimmed to your `maxStoriesPerProfile` limit,
   locally.
4. One Dataset row per Story is written, and one outcome row per profile that delivered nothing.
5. Results are ready in the Dataset, the API, or any automation you connect.

Private profiles are reported as `private` and never bypassed. Only public data is read.

***

### 💡 Use cases

- **Creator monitoring** — track which creators are posting Stories today, and capture the media URLs.
- **Brand and campaign monitoring** — verify that a sponsored Story went live, and when.
- **Competitive research** — use returned timestamps and counters to compare Story activity and
  engagement across accounts in your own tools.
- **Snapshot archives** — run on a schedule and keep one Dataset per run as a record of what was live.
- **Social data pipelines** — feed a warehouse or dashboard with structured Story records.
- **AI and analytics input** — use the returned captions, hashtags, counters and media URLs as input
  to your own models; the Actor delivers data, it does not run analysis for you.
- **Agency reporting** — collect a client's creator list in one run and use the structured results
  in your campaign reports.

***

### 🤖 Automation and downstream use

The Dataset is plain JSON, so it drops into n8n, Make, Zapier, a database, a dashboard or an LLM
pipeline for further processing. Two practical patterns:

- **Scheduled snapshot.** Run every few hours; each run is its own Dataset you can diff.
- **Latest-only monitor.** Set `sortStories: "newest"` and `maxStoriesPerProfile: 1` to keep the output
  to one row per active creator per run.

***

### 🧑‍💻 API usage

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('lance_api/tiktok-stories-scraper').call({
  usernames: ['tiktok', '@nasa'],
  sortStories: 'newest',
  maxStoriesPerProfile: 1,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();

const stories = items.filter((row) => row.rowType === 'story');
const outcomes = items.filter((row) => row.rowType === 'profile_status');
console.log(`${stories.length} Stories, ${outcomes.length} profiles without a Story`);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run = client.actor("lance_api/tiktok-stories-scraper").call(run_input={
    "usernames": ["tiktok", "@nasa"],
    "sortStories": "newest",
    "maxStoriesPerProfile": 1,
})

items = client.dataset(run["defaultDatasetId"]).list_items().items
stories = [row for row in items if row["rowType"] == "story"]
print(len(stories), "Stories")
```

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/lance_api~tiktok-stories-scraper/runs" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"usernames":["tiktok","@nasa"]}'
```

This starts a run asynchronously. Wait until the run succeeds by checking
`https://api.apify.com/v2/actor-runs/<runId>`, then read the items from
`https://api.apify.com/v2/datasets/<defaultDatasetId>/items` with the same `Authorization` header.

***

### Pricing

TikTok Stories Scraper uses per-profile pricing: a run-start fee plus one **Profile Check** charge
for each unique, chargeable profile checked. You are not charged per Story.

| Charge        |                   Price (USD) |
| ------------- | ----------------------------: |
| Actor start   |                $0.099 per run |
| Profile check | From $4.00 per 1,000 profiles |

Plan-specific rates vary by Apify subscription. See the Actor's **Pricing** tab for the current rate
on your plan.

#### What is charged and what is not

| Situation                               | Profile Check charge |
| --------------------------------------- | -------------------- |
| Valid profile checked, Stories returned | Yes — one unit       |
| Valid profile checked, no active Story  | Yes — one unit       |
| Private profile checked                 | Yes — one unit       |
| Invalid input                           | No                   |
| Profile not found                       | No                   |
| Technical failure                       | No                   |
| Duplicate input in the same run         | No additional charge |

The Actor start fee is separate from these Profile Check rules. A Profile Check is chargeable only
after its Story rows or profile outcome row have been written to the Dataset.

One profile is one billing unit, regardless of how many active Stories it returns. This makes
recurring monitoring easier to budget.

***

### 📎 Good to know

- **Only active public Stories.** Highlights, archived Stories and expired Stories are out of scope.
- **Public access only.** Private content and access restrictions are not bypassed.
- **Data for your own analysis.** Use returned fields in your reporting or AI tools; the Actor does
  not generate summaries, sentiment analysis or creator scores.
- **Stories are short-lived.** No Stories is a normal answer at any given moment.
- **Media URLs are temporary.** They may expire or stop working. The Actor returns URLs, it does not
  host files — save what you need with your own tooling before they expire.
- **Video and photo Stories differ.** A video Story has `videoUrl`; a photo Story has `imageUrl` and
  `media.images`, and no video URL — photo Stories can carry background audio, which is not a video.
- **`storyId` and `userId` are strings.** TikTok identifiers are large; they are never converted to
  numbers, so they stay exact.
- **One failure stays one failure.** A profile that fails is reported as `failed`; the rest of the
  batch continues.

***

### ❓ FAQ

**Can I collect TikTok Stories without logging in?**
Yes. The Actor reads public data only and never asks for a TikTok account, cookie or session.

**Does it work with private accounts?**
Private profiles are reported with `status: "private"`. Their content is not accessible and is not
returned.

**What happens if a profile has no active Stories?**
You get one `profile_status` row with `status: "no_active_stories"` and `storiesFound: 0`. That is a
normal outcome, not an error.

**Am I charged per Story?**
No. Pricing is per unique, chargeable profile checked, not per Story returned. See [Pricing](#pricing).

**Am I charged for a profile with no active Stories?**
Yes. A completed check that finds no active Stories incurs one Profile Check charge.
See [Pricing](#pricing) for the other outcomes and the separate run-start fee.

**Can I download the video or image files?**
The Actor gives you the media URLs in `videoUrl`, `imageUrl` and `media.images`. It does not download
or host the files; fetching them is up to your own pipeline.

**Are duplicate usernames processed twice?**
No. Inputs are normalized and deduplicated, so `tiktok`, `@TikTok` and the profile URL are one
profile, processed once and counted once.

**Can I process multiple profiles in one run?**
Yes, up to 200 distinct profiles per run.

**What happens if I submit more than 200 profiles?**
Keep the input array within 200 entries, as required by the Input schema. The runtime also rejects
more than 200 distinct profiles with a clear message; extra profiles are not silently dropped.

**Why are some fields null?**
Fields the source did not report are `null` instead of a made-up value. That is why a photo Story has
no `videoUrl`. Music fields can be `null` inside the `music` object, and missing lists are empty arrays.

**How long do Story media URLs remain available?**
They are temporary. Some URLs state their own expiry, which is exposed as `mediaUrlExpiresAt`, but
they can stop working sooner.

**What happens if one profile fails?**
A temporary data-source failure produces a `failed` row with `TEMPORARY_SOURCE_ERROR` for that
profile. Other profiles continue. Allowance-related failures have their own codes listed above.

**Can I limit how many Stories come back per profile?**
Yes — set `maxStoriesPerProfile`. Combined with `sortStories: "newest"` and a value of 1, you get only
the latest active Story per profile.

**How does the free allowance work?**
If your account includes a free allowance for this Actor, it is counted per profile, not per Story.
Duplicate inputs and retries within the same run do not consume an additional unit. An exhausted
allowance is reported as `FREE_USAGE_LIMIT_EXCEEDED` for affected profiles.

**Can I schedule it?**
Yes. Create a Task or schedule on the Actor and each run writes its own Dataset you can compare.

***

### 🧠 Summary for AI agents and developers

```json
{
  "actor": "lance_api/tiktok-stories-scraper",
  "platform": "TikTok",
  "collects": "active public TikTok Stories for given profiles",
  "storyTypes": ["video", "photo"],
  "input": {
    "usernames": "array of username | @username | profile URL",
    "sortStories": "newest | oldest, default newest",
    "maxStoriesPerProfile": "integer, optional"
  },
  "output": {
    "datasetRows": ["story", "profile_status"],
    "idsAreStrings": true,
    "missingValues": "unknown scalars are null; missing lists are empty arrays",
    "media": "URLs only; the Actor does not host files"
  },
  "limits": {
    "maxInputEntries": 200,
    "maxProfilesPerRun": 200,
    "duplicatesCharged": false
  },
  "optionalFeatures": {
    "sortStories": "local sort only, no extra request, no extra charge",
    "maxStoriesPerProfile": "local slice only, no extra request, no extra charge"
  },
  "auth": "no TikTok login required; Apify token only for API access",
  "pricing": {
    "unit": "profile",
    "runStartFee": true,
    "chargedPerStory": false,
    "seePricingTabForCurrentRates": true
  }
}
```

***

### ⚖️ Responsible use

Collect only public data you are permitted to collect, and follow applicable law, TikTok's terms and
the privacy and copyright of the people whose content you store. Do not use the output for spam,
harassment or to build profiles of people in ways they would not expect.

***

### 🛠️ Support

Email **lanceapi2026@hotmail.com** or open an issue on the Actor's page and include:

- the run ID,
- the input you submitted (without secrets),
- the status and error code you saw,
- what you expected versus what you got.

Never send your Apify token, API keys, cookies, session data, passwords, authorization headers or
proxy credentials.

# Actor input Schema

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

TikTok profile usernames, @usernames or full TikTok profile URLs. Equivalent forms of the same profile are normalized and processed once. Up to 200 distinct profiles per run.

## `sortStories` (type: `string`):

Order applied to the Stories returned for each profile. Newest first shows the most recent post at the top; oldest first shows the earliest Story that is still online. Applied to the already-fetched Story list, it never requests additional pages.

## `maxStoriesPerProfile` (type: `integer`):

Optional positive limit applied per profile after ordering. Leave empty to return every active Story. It only limits returned rows; it does not reduce requests.

## Actor input object example

```json
{
  "usernames": [
    "https://www.tiktok.com/@tiktok"
  ],
  "sortStories": "newest"
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "usernames": [
        "https://www.tiktok.com/@tiktok"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("lance_api/tiktok-stories-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 = { "usernames": ["https://www.tiktok.com/@tiktok"] }

# Run the Actor and wait for it to finish
run = client.actor("lance_api/tiktok-stories-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 '{
  "usernames": [
    "https://www.tiktok.com/@tiktok"
  ]
}' |
apify call lance_api/tiktok-stories-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lance_api/tiktok-stories-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/5scfYh5IiQuz4tIXd/builds/qndQIFyUThpbdZp6J/openapi.json
