# Instagram Video Metadata Scraper (`w3crawler/instagram-video-metadata-scraper`) Actor

Read public Instagram video and reel page metadata and explicitly report when transcript data is unavailable.

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

## Pricing

from $2.99 / 1,000 video metadata

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?

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 Video Metadata Scraper

Read **public Instagram reel, video, IGTV, and post pages** in a real Chromium browser and save page-level metadata: canonical URL, title, caption, author, thumbnail, media type, dimensions, duration with a bounded provenance label, observed media references, JSON-LD, and public caption-track text when one exists. Only pages that expose usable public metadata produce dataset rows; blocked or empty pages are counted in the run summary without becoming fake records.

### Get started

1. Open the [Actor Store page](https://apify.com/w3crawler/instagram-video-metadata-scraper) and select **Try for free**, or open the **Input** tab.
2. Add one or more public Instagram `reel`, `reels`, `tv`, or `p` URLs to `videoUrls`; at most 100 are accepted.
3. Set `maxItems` to the number of unique pages you want processed, and leave `proxyConfiguration` disabled for a first direct-browser run.
4. Start the Actor, open the dataset, and export the rows as JSON, CSV, or Excel. Open **Run summary** (`OUTPUT` in the key-value store) to see the target, saved, and diagnostic counts.

### Input

`videoUrls` is required. Every other field is optional and uses the default shown below. Unsupported field names and out-of-range values are rejected before the browser starts.

| Field | Type | Required? | Default | Meaning |
| --- | --- | --- | --- | --- |
| `videoUrls` | string array | Required | Not supplied | Public Instagram video, reel, IGTV, or post URLs; 1–100 HTTPS `instagram.com` URLs with a `reel`, `reels`, `tv`, or `p` path. |
| `maxItems` | integer | Optional | `100` | Maximum number of unique normalized pages processed, 1–100. |
| `requestTimeoutSecs` | integer | Optional | `45` | Per-page browser navigation timeout, 5–60 seconds. |
| `maxRequestRetries` | integer | Optional | `2` | Additional attempts for blocked or transient page responses, 0–3. |
| `requestDelayMs` | integer | Optional | `0` | Delay before each subsequent video page, 0–10,000 ms. |
| `proxyConfiguration` | object | Optional | `{"useApifyProxy":false}` | Optional Apify Proxy settings with `useApifyProxy`, `apifyProxyGroups`, and an optional two-letter `apifyProxyCountry`. Direct browser access is the default. |

The saved run used this input:

```json
{
  "videoUrls": [
    "https://www.instagram.com/instagram/reel/Dc30nJeRKKz/"
  ],
  "maxItems": 1,
  "maxRequestRetries": 0,
  "requestTimeoutSecs": 45,
  "requestDelayMs": 0,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

The Actor navigates to public Instagram pages only. It does not log in, submit credentials, accept session cookies, or download media bytes. Optional `proxyConfiguration` is passed to the browser when supplied.

### Output

The dataset contains one row per unique page that exposed usable public metadata. Values that Instagram did not publish are omitted rather than inferred; failed, blocked, or empty pages are counted in `OUTPUT` and logs, not written as diagnostic dataset rows.

| Field | Type | Availability | Meaning |
| --- | --- | --- | --- |
| `id` | string | Always | Stable deterministic identifier for the normalized video URL. |
| `recordType` | string enum | Always | Record type; always `instagram-video-page-metadata`. |
| `targetType` | string enum | Always | Target entity type; always `video`. |
| `videoUrl` | string | Always | Normalized requested video page URL. |
| `sourceUrl` | string | Always | Public Instagram page used for extraction. |
| `canonicalUrl` | string | Always | Canonical page URL exposed by Instagram, falling back to the requested URL. |
| `url` | string | Always | Normalized video page URL (dataset view alias). |
| `searchUrl` | string | Always | Requested page URL persisted as a compatibility alias. |
| `mediaType` | string enum | Always | Normalized media type: `image`, `video`, or `carousel`; defaults to `video`. |
| `transcriptAvailable` | boolean | Always | Whether readable public caption-track text was observed. |
| `transcriptStatus` | string enum | Always | Public caption-track state: `public_caption_track`, `public_caption_track_exposed`, or `not_available_from_public_page`. |
| `downloadAvailable` | boolean | Always | Whether a public media reference was observed; no bytes are downloaded. |
| `scrapedAt` | string | Always | UTC time the row was emitted. |
| `title` | string | When published | Public video page title, usually the Open Graph title. |
| `pageTitle` | string | When published | Observed HTML or Open Graph page title before title selection. |
| `caption` | string | When published | Public caption or page description. |
| `author` | string | When published | Public author display name. |
| `authorUsername` | string | When published | Public author username. |
| `authorUrl` | string | When published | Public author profile URL. |
| `imageUrl` | string | When published | Public thumbnail or image URL. |
| `videoUrlFromPage` | string | When published | Explicit public video URL observed in the page or player. |
| `mediaUrl` | string | When published | Compatibility alias for an observed video URL. |
| `width` | integer | When published | Observed media width in pixels, at least 1. |
| `height` | integer | When published | Observed media height in pixels, at least 1. |
| `duration` | string | When published | Source duration representation as a string. |
| `durationSeconds` | number | When published | Normalized duration in seconds, at least 0. |
| `durationSource` | string enum | When published | Bounded provenance: `public_video_element`, `public_media_metadata`, `public_embedded_metadata`, `public_json_ld`, `public_media_url_duration_s`, or `public_media_url_efg_duration_s`. Signed media URLs are never used as the provenance label. |
| `uploadDate` | string | When published | Public publication date/time in ISO format. |
| `likeCount` | integer | When published | Public like count when exposed. |
| `commentCount` | integer | When published | Public comment count when exposed. |
| `videoViewCount` | integer | When published | Public video view count when exposed. |
| `mediaReferences` | object array | When published | Bounded public media references, each with `url`, `kind` (`image` or `video`), optional `width`, `height`, `durationSeconds`, `durationSource`, and `source`. |
| `transcript` | string | When published | Text from a public caption track; never inferred from audio. |
| `transcriptSourceUrl` | string | When published | Public caption-track URL that supplied the transcript text. |
| `jsonLd` | object array | When published | Bounded public JSON-LD objects. |
| `structuredData` | object array | When published | Compatibility alias for the same public structured data. |
| `metadata` | object | When published | Small public page metadata subset, currently `openGraphType` when present. |

#### Full JSON output

This is a real saved row from the 2026-10-25 run. The signed CDN URL in the second `mediaReferences` entry is shortened with an ellipsis; every other value is complete.

```json
{
  "id": "instagram-video:df697121c65cd31bbffda568",
  "recordType": "instagram-video-page-metadata",
  "targetType": "video",
  "videoUrl": "https://www.instagram.com/instagram/reel/Dc30nJeRKKz/",
  "sourceUrl": "https://www.instagram.com/instagram/reel/Dc30nJeRKKz/",
  "canonicalUrl": "https://www.instagram.com/instagram/reel/Dc30nJeRKKz/",
  "title": "Instagram on Instagram: \"that’s his spa now 🚰 #InTheMoment Video by @misterbeanito\"",
  "pageTitle": "Instagram on Instagram: \"that’s his spa now 🚰 #InTheMoment Video by @misterbeanito\"",
  "caption": "966K likes, 22K comments - instagram on September 4, 2026: \"that’s his spa now 🚰 #InTheMoment Video by @misterbeanito\".",
  "author": "Instagram",
  "authorUsername": "instagram",
  "authorUrl": "https://www.instagram.com/instagram/",
  "imageUrl": "https://static.cdninstagram.com/rsrc.php/y4/r/QaBlI0OZiks.ico",
  "mediaType": "video",
  "mediaReferences": [
    {
      "url": "https://static.cdninstagram.com/rsrc.php/y4/r/QaBlI0OZiks.ico",
      "kind": "image",
      "source": "public_media_response"
    },
    {
      "url": "https://scontent-iad3-1.cdninstagram.com/v/t51.71878-15/795341832_1575427477361093_319242826385620795_n.jpg?stp=cmp1_dst-jpg_e35_s640x640_tt6&_nc_cat=108&ccb=7-5&_nc_sid=18de74&_nc_ohc=GwEZWrttYssQ7kNvwHLwSkT&_nc_oc=Adp9Co1ba6xG_j3Lrxe-wcu1kO6QDx37gSr3dS1tw65St2HUuPxt1JHq2-D6OrFOMNo&_nc_zt=23&_nc_ht=scontent-iad3-1.cdninstagram.com&_…",
      "kind": "image",
      "source": "open_graph"
    }
  ],
  "transcriptAvailable": false,
  "transcriptStatus": "not_available_from_public_page",
  "metadata": {
    "openGraphType": "article"
  },
  "downloadAvailable": true,
  "scrapedAt": "2026-10-25T20:48:49.478Z",
  "url": "https://www.instagram.com/instagram/reel/Dc30nJeRKKz/",
  "searchUrl": "https://www.instagram.com/instagram/reel/Dc30nJeRKKz/"
}
```

### Run summary

**Run summary** is stored separately from the dataset in the run's key-value store under `OUTPUT`. It records request accounting and does not add diagnostic rows to the dataset.

| Field | Meaning |
| --- | --- |
| `status` | Actor outcome: `SUCCEEDED` or `FAILED`. |
| `runStatus` | Canonical run status; matches `status`. |
| `dataStatus` | Completeness of saved rows: `COMPLETE`, `PARTIAL`, `NO_RESULTS`, or `FAILED`. |
| `requestedTargetCount` | Number of unique normalized URLs requested after applying `maxItems`. |
| `emittedCount` | Normal video metadata rows saved to the dataset. |
| `normalCount` | Normal video metadata rows saved; equals `emittedCount`. |
| `diagnosticCount` | Pages that returned no usable public metadata or were blocked; these are logged and counted but not saved as rows. |
| `failureCount` | Blocked, failed, or incompletely accounted page requests plus run-level failures. |
| `optionalFailureCount` | Optional output-write failures, normally `0`. |
| `transcriptCount` | Saved rows that contained public caption-track text. |
| `maxItems` | Effective page cap applied to the run, 1–100. |
| `completedAt` | Time the summary was written, in ISO UTC. |

| Status | Data status | Meaning |
| --- | --- | --- |
| `SUCCEEDED` | `COMPLETE` | All requested pages produced usable public rows without diagnostics or failures. |
| `SUCCEEDED` | `PARTIAL` | At least one row was saved, but another page was blocked, empty, or failed. Saved rows remain available. |
| `SUCCEEDED` | `NO_RESULTS` | The run completed cleanly but no page exposed usable public metadata. |
| `FAILED` | `FAILED` | A fatal error occurred before any usable row was saved. |

Example `OUTPUT` from the saved run:

```json
{
  "status": "SUCCEEDED",
  "runStatus": "SUCCEEDED",
  "dataStatus": "COMPLETE",
  "requestedTargetCount": 1,
  "emittedCount": 1,
  "normalCount": 1,
  "diagnosticCount": 0,
  "failureCount": 0,
  "optionalFailureCount": 0,
  "transcriptCount": 0,
  "maxItems": 1,
  "completedAt": "2026-10-25T20:48:49.838Z"
}
```

### Coverage and limitations

The Actor reads whatever the public page renders in Chromium. Instagram can serve a login wall, challenge, or empty shell depending on session, region, and rate limits; those outcomes are counted in `OUTPUT` and logs and are not written as metadata rows. Duration is reported only when a public player element, embedded metadata, JSON-LD, or a media URL exposes a value, and the selected `durationSource` records which evidence was used. Signed CDN URLs in `mediaReferences` can expire after the run, and no media bytes are saved.

Caption `transcript` is only the text of a public caption track. The Actor does not run speech-to-text, transcribe audio, or infer transcript content. Counts such as likes and comments are point-in-time values. Private, deleted, age-restricted, or login-gated pages cannot be read, and the page cap limits how many unique URLs are processed per run.

### Usage and support

Cost depends on browser compute time, optional proxy traffic, and the number of pages processed. Start with one URL, inspect the row and `OUTPUT`, then raise `maxItems` and add proxies only if direct access is blocked. See the Actor's Pricing tab for current account rates.

Use the [Actor Issues page](https://apify.com/w3crawler/instagram-video-metadata-scraper/issues) to report a problem. Include the run ID, the input used, and the `OUTPUT` summary; do not include tokens, cookies, or private data. This Actor is not affiliated with Instagram or Meta. Use it only for public data and in accordance with the source's terms, robots guidance, and applicable law. Public pages can contain personal information; use the output only for lawful purposes.

# Actor input Schema

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

Public Instagram video, reel, IGTV, or post URLs.

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

Maximum number of normalized video pages processed.

## `requestTimeoutSecs` (type: `integer`):

Per-page browser navigation timeout.

## `maxRequestRetries` (type: `integer`):

Additional attempts for blocked or transient page responses.

## `requestDelayMs` (type: `integer`):

Optional delay before each subsequent video page.

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

Optional Apify Proxy configuration. Direct browser access is the default.

## Actor input object example

```json
{
  "videoUrls": [
    "https://www.instagram.com/instagram/reel/Dc30nJeRKKz/"
  ],
  "maxItems": 100,
  "requestTimeoutSecs": 45,
  "maxRequestRetries": 2,
  "requestDelayMs": 0,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `runSummary` (type: `string`):

Run status and counters stored by the Actor.

# 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 = {
    "videoUrls": [
        "https://www.instagram.com/instagram/reel/Dc30nJeRKKz/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("w3crawler/instagram-video-metadata-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 = { "videoUrls": ["https://www.instagram.com/instagram/reel/Dc30nJeRKKz/"] }

# Run the Actor and wait for it to finish
run = client.actor("w3crawler/instagram-video-metadata-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 '{
  "videoUrls": [
    "https://www.instagram.com/instagram/reel/Dc30nJeRKKz/"
  ]
}' |
apify call w3crawler/instagram-video-metadata-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,w3crawler/instagram-video-metadata-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/17tUytG1br7lCreha/builds/hKLK9IaOwxM1fRvQ9/openapi.json
