# Instagram Stories Scraper | $2.15/1K Stories + $0.012/Profile (`publicsignallabs/instagram-stories-scraper`) Actor

Capture currently available Instagram Stories for brand, creator and competitor research. Export media links, posting times and content details from selected profiles or known Stories. No Instagram login required.

- **URL**: https://apify.com/publicsignallabs/instagram-stories-scraper.md
- **Developed by:** [Public Signal Labs](https://apify.com/publicsignallabs) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.15 / 1,000 story results

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

## Instagram Stories Scraper | $2.15/1K Stories + $0.012/Profile

**Capture a snapshot of Instagram Stories before they disappear.** Collect currently available Stories to research brand activity, review campaigns or compare what creators and competitors are sharing.

Export available image/video links, posting times and content details in a structured list for analysis. Start with a username, profile link or known Story link; no Instagram login or technical setup required.

### Quick start

```json
{
  "mode": "profiles",
  "profiles": ["instagram", "https://www.instagram.com/natgeo/"],
  "maxItems": 100,
  "enrichProfiles": false,
  "enrichPlaces": false,
  "enrichMedia": false
}
```

For numeric IDs, use `"profiles": ["123456789"]`. IDs are strings; do not pass JSON numbers. Equivalent username references are deduplicated locally; a resolved username and an explicitly supplied ID for the same owner share one tray check.

#### Known-Story mode

```json
{
  "mode": "stories",
  "stories": ["https://www.instagram.com/stories/example/12345678901234567/"],
  "maxItems": 10
}
```

Provide **only `stories`**, not `profiles`, in this mode. Accepted forms are a numeric Story ID, `StoryID_OwnerID`, or a canonical `https://www.instagram.com/stories/username/StoryID/` URL. Owner-qualified references are matched to the returned owner. Only the exact requested Story is selected—even when the lookup includes other Stories. Expired content is not recovered or emitted as active. Known-Story mode is for paying users only.

### Inputs and bounds

| Input | Default / limit | Meaning |
|---|---|---|
| `mode` | `profiles` | `profiles` or distinct `stories` mode. |
| `profiles` | 1–50 references | Usernames, `@username`, profile URLs or numeric ID strings. Profile mode only. |
| `stories` | 1–50 references | Known Story references, as above. Known-Story mode only. |
| `maxItems` | 100; integer 1–1,000 | Total unique saved Story cap for the run, not per profile. |
| `enrichProfiles` | `false` | Optional identity-matched incremental owner profile lookup. |
| `enrichPlaces` | `false` | Optional matching lookup for supplied Instagram location IDs. |
| `enrichMedia` | `false` | Optional matching lookup for supplied `media_id` / `media_pk` references. |

Input is validated before quota admission or extraction. Unknown fields, mixed modes, malformed references, non-boolean enrichment flags and invalid limits are rejected. There is one tray per unique profile, no active-tray pagination or continuation, no arbitrary URL fetching, no fallback route and no uncertain request replay. Runtime request, time, spend and event limits can stop the run with a confirmed partial prefix.

### What each saved row contains

**Enrichment required?** Base Story fields do not require enrichment; optional facts may still be missing. Additional lookup details are stored under `enrichment_results`, not merged back into the base owner, location or media fields. Enable only the kinds you need; already-included matching details may be reused, and extra data is not guaranteed.

| Fields | Contract | Enrichment required? |
|---|---|---|
| `id`, `story_id`, `shortcode`, `url` | Real Story identity. Shortcode is nullable; URL uses `/stories/owner/ID/`, never an invented feed permalink. | No. |
| `content_kind`, `media_type` | `active_story`; `image` or `video`. | No. |
| `owner`, `owner_id`, `owner_username`, `flags`, `source` | Identity-matched owner plus flattened `owner_id` and `owner_username`, supplied privacy/restriction flags, and `source` provenance: `source_input`, `input_index`, `mode`, `source_position` (the Story's 1-based position in the observed tray) and `tray_size` (the observed tray length). Resolution facts already returned are included. | No — optional profile lookup details are separate from these base fields. |
| `published_at`, `fetched_at`, `expires_at` | UTC timestamps. Expiry comes only from a real supplied expiration value, never publication plus 24 hours. | No. |
| `remaining_lifetime_seconds` | Derived at a fixed run observation time only when real expiry is available. Nullable otherwise. Confirmed expired Stories are not saved as active. | No. |
| `images`, `videos`, `width`, `height`, `duration_seconds`, `audio` | Supplied variants, dimensions, duration and supported music/audio metadata. No invented empty lists, zero dimensions or zero duration for absent facts. | No; `enrichMedia` does not fill missing assets of the Story itself. |
| `caption`, `hashtags`, `mentions`, `links`, `link_domains` | Supplied text/entity context, local caption parsing and deduplicated link domains. | No. |
| `location`, `locations`, `sponsors`, `is_paid_partnership` | Supplied supported place and sponsor context; missing facts remain nullable. | No — optional place lookup details are separate. |
| `stickers` | Supported supplied poll, question, quiz, countdown, slider and music fields. Not an exhaustive reconstruction of every interactive sticker. | No. |
| `reshared_media` | Nested referenced media context, selected by `media_id`/`media_pk`, not a generic sticker ID. | No — optional referenced-media lookup details are separate. |
| `enrichment_results`, `enrichment_outcome` | Per-kind results and truthful outcomes. Already-included facts use `included`; incremental matching work uses `succeeded`; unavailable/failed/limited work remains explicit. | No for the outcome containers; disabled kinds have empty result arrays and `not_requested` outcomes. |
| `enrichment_results.profiles[].data` | Available owner profile details, such as biography and follower/following/post counts. Data may be null if the selected lookup is unavailable, failed or limited. | Yes — select `enrichProfiles`; already-included profile details may be reused. |
| `enrichment_results.places[].data` | Available details for places already referenced by the Story, such as address, website, phone or opening hours. Requires a usable location ID. | Yes — select `enrichPlaces`; already-included place details may be reused. |
| `enrichment_results.media[].data` | Available post/Reel details for media referenced by the Story, such as captions, engagement or asset links. Requires a usable referenced media ID; not a lookup of the Story itself. | Yes — select `enrichMedia`; already-included referenced-media details may be reused. |

Temporary CDN asset links can expire and are **not durable downloads**. Highlights, uncaptured expired content, captured-history archives, viewer/reach/impression metrics, OCR, transcripts and binary retention are outside this Actor. Optional facts are not promised for every result.

#### Optional enrichment

Lookups are selected explicitly and cached by operation and entity for the run, including unsuccessful outcomes. Matching facts already returned in resolution, complete owner context, place context or nested media assets are reused rather than looked up again. Repeated references do not repeat a lookup. A missing/failed lookup preserves the base Story and reports the result honestly; it never becomes a fabricated complete profile/place/media record. Unaffordable enrichment is skipped explicitly while affordable base results can still be saved.

### Pricing — USD / Starter

**The headline is not an all-in price.** A matching username resolution costs $0.004 and a profile Story check costs $0.008, including a valid empty check: **$0.012 per initial username check**, plus saved-Story fees and the automatic start event. A numeric profile ID skips resolution and costs $0.008 per valid profile Story check.

| Event | Price | Charged boundary |
|---|---:|---|
| `story-result` — primary | $0.00215 / saved Story ($2.15/1,000) | Unique saved active top-level Story. |
| `profile-resolution` | $0.004 / username | Completed matching resolution actually performed. |
| `story-tray` | $0.008 / tray | Valid completed unforced tray, including a valid empty or duplicate-only tray. |
| `story-lookup` | $0.008 / known Story | Valid matching direct lookup. Result fee is additional. |
| `profile-enrichment` | $0.0055 / profile | Successful incremental matching owner lookup, once per run/entity. |
| `place-enrichment` | $0.004 / place | Successful incremental matching place lookup, once per run/entity. |
| `media-enrichment` | $0.004 / media | Successful incremental matching referenced-media lookup, once per run/entity. |
| `apify-actor-start` | $0.00005 / run at ≤1 GB | Automatic platform start event; not charged again manually. |

No default-dataset-item fee is added to the named Story result event. Unavailable, malformed, mismatched or failed extraction does not earn a successful-work fee. Unperformed work and copied enrichment facts are not billed. A successful resolution followed by an unavailable tray still incurs only the completed resolution fee and the automatic start event.

Known-Story mode has no username-resolution or tray fee: a valid matching direct lookup costs $0.008, plus $0.00215 if its active top-level Story is saved. The automatic start event and any selected incremental enrichment are additional. Already-included matching enrichment facts and repeated references to the same entity do not incur another enrichment fee.

Mixed valid trays retain matching Stories and report a rejected-item count; a completed validated tray still has its work fee. An entirely invalid set is not a successful check and is not presented as a verified empty tray.

Examples without enrichment: one valid empty username check is **$0.01205**; one username with five saved Stories is **$0.02280**; one numeric ID tray with five saved Stories is **$0.01880**. Actual confirmed counts determine the bill, not expected yield or declared tray size.

Dataset persistence and charging are not one atomic transaction. An interrupted mutation can leave saved-but-unconfirmed-charged or charged-but-unconfirmed-delivered work. The summary/audit retains confirmed progress and reconciliation evidence; the Actor does not replay uncertain mutations or promise automatic refunds.

### FREE demo

Nonpaying users receive **five admitted runs per Actor, Apify account and UTC month**. Each admitted run supports one profile, at most five saved Stories, and at most two extraction attempts (username resolution plus one unforced tray; an ID needs only one attempt). No known-Story mode or optional enrichment. `maxItems` is clamped to five after complete input validation. Paying users bypass the demo quota but not bounded workload and spending limits.

The allowance is verified atomically. Missing identity/configuration or a quota outage fails closed. An admitted run consumes its slot even if aborted or empty, and resurrection does not grant another slot or replay extraction. The allowance resets at the next UTC month; unused slots do not carry over. FREE is a bounded demo entitlement, not a guarantee of an active Story or an invoice exemption for every platform configuration.

### Results, outcomes and exports

- **Default dataset:** saved active Stories; export JSON, CSV or Excel in Apify Storage.
- **`OUTPUT`:** schema version 2 summary, source outcomes, confirmed event counts, delivered count and stop reason.
- **`AUDIT`:** extraction attempts/statuses, delivery/billing reconciliation and FREE admission when applicable.

A valid completed empty tray is `empty`; unavailable extraction is `not_available`, not a verified empty account. Other specific outcomes distinguish identity mismatch, invalid Story data, extraction failure, expired-only content and limits. Expected empty/unavailable/limit outcomes end as successful runs with honest records. Mechanical configuration/internal errors fail rather than pretending success.

Availability is not guaranteed, including for profiles marked private or restricted. Returned flags alone do not exclude matching data or skip the selected check. This Actor captures currently available active Stories; it does not recover expired content.

#### Example summary: a valid empty username check

```json
{
  "schemaVersion": 2,
  "status": "SUCCEEDED",
  "stopReason": "empty",
  "deliveredCount": 0,
  "chargedResultCount": 0,
  "chargedResolutionCount": 1,
  "chargedTrayCount": 1,
  "chargedLookupCount": 0,
  "chargedEnrichmentCount": 0,
  "confirmedEventCharges": {
    "profile-resolution": 1,
    "story-tray": 1
  },
  "sources": [
    {
      "inputIndex": 0,
      "sourceInput": "example",
      "outcome": "empty",
      "returnedCount": 0,
      "deliveredCount": 0
    }
  ]
}
```

This illustrative subset omits optional owner facts and runtime outcome/reconciliation metadata. A missing or unavailable profile instead has `not_available`, no successful resolution/tray events, and no saved rows; it is not reported as an empty active tray.

### API and CLI use

Call the Actor through the standard Apify Actor Runs API. Read Story rows from the default dataset and reconciliation metadata from `OUTPUT` and `AUDIT`.

```bash
apify actors call publicsignallabs/instagram-stories-scraper \
  --input '{"mode":"profiles","profiles":["instagram"],"maxItems":100}' \
  --output-dataset
```

The Actor also works with the Apify JavaScript and Python clients, REST API, schedules, webhooks, and platform integrations.

### Responsible use

Collect and use public data only where you have a lawful purpose. Respect privacy, intellectual-property rights, platform rules, anti-spam requirements, and applicable data-protection law. Minimize retained data, secure exports, honor deletion obligations, and do not use unverified contact fields for unlawful or deceptive outreach.

This Actor is unofficial and is not affiliated with or endorsed by Instagram or Meta.

### Support

Use the **Issues** tab on this Actor's Apify page. Include the run ID, input shape with private values removed, expected result, and observed result. Never include API tokens, cookies, credentials, personal contact values, or other private data.

# Actor input Schema

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

Choose profile trays or distinct known-Story lookup. FREE supports profile trays only.

## `profiles` (type: `array`):

1–50 usernames, profile URLs or numeric IDs. Use only in profiles mode and leave this list empty in stories mode.

## `stories` (type: `array`):

1–50 numeric Story IDs, StoryID\_OwnerID identifiers or canonical /stories/username/ID/ URLs. Use only in stories mode and leave this list empty in profiles mode. Paying users only.

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

Run-wide cap. FREE is clamped to five.

## `enrichProfiles` (type: `boolean`):

Incremental owner profile lookup, $0.0055 per successful unique owner. Resolution facts are included without another fee. Paying users only.

## `enrichPlaces` (type: `boolean`):

Incremental supplied location lookup, $0.004 per successful unique place. Paying users only.

## `enrichMedia` (type: `boolean`):

Incremental supplied media\_id/media\_pk reference lookup, $0.004 per successful unique media. Nested references are not extra Story results. Paying users only.

## Actor input object example

```json
{
  "mode": "profiles",
  "profiles": [
    "instagram"
  ],
  "maxItems": 100,
  "enrichProfiles": false,
  "enrichPlaces": false,
  "enrichMedia": false
}
```

# Actor output Schema

## `stories` (type: `string`):

Charged Story rows from the default dataset, ready for preview or export.

## `summary` (type: `string`):

Run status, stop reason, delivered and charged counts, source outcomes, and confirmed event counts.

## `audit` (type: `string`):

Aggregate extraction attempt, delivery and billing reconciliation, and FREE admission metrics.

# 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 = {
    "profiles": [
        "instagram"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("publicsignallabs/instagram-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 = { "profiles": ["instagram"] }

# Run the Actor and wait for it to finish
run = client.actor("publicsignallabs/instagram-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 '{
  "profiles": [
    "instagram"
  ]
}' |
apify call publicsignallabs/instagram-stories-scraper --silent --output-dataset

```

## MCP server setup

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