# Pinterest Video Scraper — MP4 Links & Captions (`apt_marble/pinterest-video-scraper`) Actor

Turn Pinterest keywords or pin links into video pins with a direct MP4 file link, streaming link, width, height, length, poster frame and caption track — plus title, creator, destination link and live save, repin, comment and share counts. No Pinterest account needed.

- **URL**: https://apify.com/apt\_marble/pinterest-video-scraper.md
- **Developed by:** [Hamza](https://apify.com/apt_marble) (community)
- **Categories:** Social media, Videos
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.00 / 1,000 video scrapeds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Pinterest Video Scraper — MP4 Links & Captions

Give it a few keywords, a list of pin links, or both, and get back Pinterest's video pins as usable files: a direct `.mp4` link you can open or save, the streaming link, the exact width, height and length, the poster frame, and the caption track where the video has one. Every row also carries the pin's own title, description, destination link, board, creator and its live save, repin, comment and share counts — so the same export works for a content pipeline and for research. No Pinterest account, no login, nothing to install.

### What you can do with it

- **Build a video library from a topic.** Search "diy craft ideas", "coffee recipe" or any phrase and collect every video pin Pinterest publishes for it, each with a ready-to-open file link.
- **Turn a list of pin links into files.** Paste pin addresses you already have and get their videos, dimensions and captions back in one table.
- **Find the format that works.** Filter by length — keep only clips between 15 and 60 seconds, for example — and compare them by saves, repins and comments to see what actually travels.
- **Feed a subtitle or transcription workflow.** Where a video ships with a caption track, its link comes with the row, tagged with its language.
- **Track a creator's or a brand's video output.** Every row names the account that published the video and the account that saved this copy, with follower counts for both.
- **Repurpose with rights in mind.** The destination link and domain travel with each row, so you always know whose video it is and where it points.

### What you get

One row per video. A real, abridged row from a live run:

```json
{
  "type": "video",
  "id": "905364331356325440",
  "url": "https://www.pinterest.com/pin/905364331356325440/",
  "searchQuery": "diy craft ideas",
  "mp4Url": "https://v1.pinimg.com/videos/iht/expMp4/0a/82/d9/0a82d91702cdac8dafeb139be4d410a4_720w.mp4",
  "mp4Quality": "V_720P",
  "hasMp4": true,
  "hlsUrl": "https://v1.pinimg.com/videos/iht/hls/0a/82/d9/0a82d91702cdac8dafeb139be4d410a4.m3u8",
  "width": 1080,
  "height": 1920,
  "aspectRatio": 0.563,
  "durationSeconds": 88.4,
  "thumbnail": "https://i.pinimg.com/videos/thumbnails/originals/0a/82/d9/0a82d91702cdac8dafeb139be4d410a4.0000000.jpg",
  "captionsUrl": null,
  "captionsLanguage": null,
  "hasCaptions": false,
  "title": "Diy this table calendar 2026",
  "altText": null,
  "createdAt": "2026-01-10T11:01:14.000Z",
  "domain": "grify.in",
  "saveCount": 26007,
  "repinCount": 17353,
  "commentCount": 83,
  "shareCount": 1968,
  "creatorUsername": "Gayatriscrafts",
  "pinnerUsername": "Gayatriscrafts",
  "pinnedByCreator": true,
  "isPromoted": false,
  "isStoryPin": false,
  "scrapedAt": "2026-08-04T13:22:41.905Z"
}
```

### Input reference

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `queries` | list of text | `["diy craft ideas"]` | One search phrase per line. Pinterest is searched for video pins matching each phrase. Leave empty if you only want to use pin addresses. |
| `pins` | list of text | `[]` | Optional. One pin per line — a full pin address or a bare numeric pin id. Pins that turn out to have no video are reported and left out. |
| `maxVideos` | number | `100` | Safety cap on how many videos the run returns. Maximum 2,000. |
| `minDurationSeconds` | number | `0` | Skip anything shorter than this. `0` keeps every length. Maximum 3,600. |
| `maxDurationSeconds` | number | `0` | Skip anything longer than this. `0` means no upper limit. Maximum 3,600. |
| `excludePromoted` | true/false | `false` | Videos found through a keyword are flagged when they are paid placements. Turn this on to leave them out entirely. |
| `country` | choice | `us` | The country the run browses from. Pinterest personalises results by country. |

At least one keyword or one pin address is required. If both are given, the pin addresses are handled first and the keywords fill the rest of the allowance.

### Output fields

| Field | Description |
| --- | --- |
| `id`, `url` | The pin's id and its address on Pinterest |
| `mp4Url`, `mp4Quality`, `hasMp4` | Direct video file link, which rendition it is, and whether one exists |
| `hlsUrl`, `videoUrls` | Streaming link, plus every rendition the video was published in |
| `width`, `height`, `aspectRatio` | Pixel dimensions and the shape of the frame |
| `durationSeconds`, `durationMs` | Length of the video |
| `thumbnail`, `imageUrl` | Poster frame and the pin's cover image |
| `captionsUrl`, `captionsLanguage`, `captions`, `hasCaptions` | Caption track link, its language, every language available, and whether any exist |
| `title`, `description`, `altText`, `hashtags` | The pin's own text; `altText` is an automatically generated image description used where the pin has no caption of its own |
| `createdAt`, `createdAtRaw` | When the pin was published |
| `link`, `trackedLink`, `domain` | Where the pin sends people, and that site's domain |
| `saveCount`, `repinCount`, `commentCount`, `shareCount`, `reactionCount`, `reactions` | Engagement at the moment of collection |
| `boardId`, `boardName`, `boardUrl` | The board this copy of the video lives on |
| `pinnerUsername`, `pinnerFullName`, `pinnerFollowerCount` | Who saved this copy |
| `creatorUsername`, `creatorFullName`, `creatorFollowerCount`, `creatorDomain`, `pinnedByCreator` | The account behind the video, and whether it is the same account that saved it |
| `isPromoted`, `promotedBy`, `isRepin` | Whether the pin is a paid placement and which advertiser paid for it — answered for videos found through a keyword, and left empty for a pin address you supplied yourself — plus whether the pin is a re-save |
| `isStoryPin`, `videoSource`, `storyPageVideoCount`, `storyPageVideos` | Whether this is a multi-page idea pin, and the video on every one of its pages |
| `dominantColor` | The video's dominant colour |
| `searchQuery`, `inputUrl`, `position`, `source`, `scrapedAt` | Which keyword or address produced the row, where it ranked within that keyword's own results (empty for a pin address you supplied), and when it was collected |

### Pricing

Pay per event. One event, one price:

| Event | Charged when | Price |
| --- | --- | --- |
| Video scraped | Once for every video that lands in the dataset with its file details attached | **$4.00 per 1,000** |

That is **$0.004 per video**. Pins that turn out to have no video, that fall outside your length window, that are promoted while you asked to exclude promoted pins, or that are private or deleted are never charged — you pay only for rows you actually receive.

**Worked example.** You ask for 250 videos across five keywords, keeping only clips between 15 and 60 seconds. Say 220 of them clear the length filter and come back with full details. The run costs 220 × $0.004 = **$0.88**. A full 2,000-video run, the largest a single run allows, costs **$8.00**. Set `maxVideos` for a hard ceiling on any run.

### Limits & what this actor cannot do

- Pinterest publishes a limited number of public results for any one keyword, so a very broad topic returns what Pinterest makes available rather than an unlimited archive.
- A small number of videos are published in streaming form only. Those arrive with the streaming link, dimensions and length but no direct file; `hasMp4` tells you which ones, so you can filter them out in one step.
- Caption tracks exist only where one was published. Most videos have none, and `hasCaptions` says so rather than the row pretending otherwise.
- Video and caption links are the ones Pinterest itself serves. Pinterest can change or retire them at any time, so treat the links as fresh at the moment of collection and act on them promptly.
- Save, repin, comment and share counts are a snapshot taken when the video was collected and keep changing afterwards.
- Many videos are published with no caption of their own; those arrive with an automatically generated image description instead of a title or body text.
- Results are personalised to the country the run browses from, so the same keyword from a different country can return a different set of videos.
- Promoted pins appear inside Pinterest's own video results, and there can be a lot of them. Videos found through a keyword are flagged as promoted, and one switch removes them. A pin address you paste is looked up on its own, and Pinterest does not say there whether that pin is an ad, so the promoted column is left empty rather than guessed.
- Private profiles, secret boards and deleted pins are not publicly viewable; they are reported as unavailable rather than returned as empty rows.
- Shortened `pin.it` links cannot be read. Open one in a browser once and paste the full address it lands on.
- Speed depends on the size of the job and on Pinterest's own response times; no fixed throughput is promised.
- Pinterest's terms govern automated access, and the videos themselves belong to the people who made them. You are responsible for using the data and the media lawfully, in line with the source site's terms, and for handling any personal data in line with applicable privacy law.

### FAQ

**Do I need a Pinterest account?**
No. Everything collected is what Pinterest shows the public.

**Does it need my login or password?**
No. There is nowhere to enter one, and nothing about you is sent to Pinterest.

**Can I schedule it?**
Yes. Schedule it like any other actor — daily, weekly, or on whatever cadence suits — and each run appends a fresh snapshot.

**Is the data complete?**
It is complete for what Pinterest publishes publicly, and honest about the rest. Every video that has a direct file gets one; the few that are streaming-only say so. Counts are a point-in-time snapshot, and Pinterest itself decides how many results a keyword returns.

**Why do some rows have no MP4 link?**
Pinterest publishes a small share of videos — mostly multi-page idea pins — in a streaming form with no single downloadable file. Those rows still carry the streaming link, dimensions, length, poster frame and captions, and `hasMp4` is `false` so they are easy to separate.

**Can I use the videos I get back?**
The actor gives you the links Pinterest serves publicly. What you may do with someone else's video is a licensing question, not a technical one — check the creator's terms before republishing anything.

# Actor input Schema

## `queries` (type: `array`):

One search phrase per line. Pinterest is searched for video pins matching each phrase, and every match is then opened to collect its playable file. Leave empty if you only want to use the pin addresses below.

## `pins` (type: `array`):

Optional. One Pinterest pin per line — a full pin address or a bare numeric pin id. Pins that turn out to have no video are reported and left out of the results. Shortened pin.it links cannot be read; open one in a browser and paste the full address it lands on.

## `maxVideos` (type: `integer`):

Safety cap on how many videos this run returns. Anything beyond it is left untouched.

## `minDurationSeconds` (type: `integer`):

Skip anything shorter than this many seconds. Leave at 0 to keep every length.

## `maxDurationSeconds` (type: `integer`):

Skip anything longer than this many seconds. Leave at 0 for no upper limit.

## `excludePromoted` (type: `boolean`):

Promoted pins are always flagged in the results. Turn this on to leave them out entirely — Pinterest mixes a lot of them into video results.

## `country` (type: `string`):

The country the run browses from. Pinterest personalises what it publishes by country, so pick the market you care about and keep it the same between runs you want to compare.

## Actor input object example

```json
{
  "queries": [
    "diy craft ideas"
  ],
  "pins": [],
  "maxVideos": 50,
  "minDurationSeconds": 0,
  "maxDurationSeconds": 0,
  "excludePromoted": false,
  "country": "us"
}
```

# Actor output Schema

## `dataset` (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 = {
    "queries": [
        "diy craft ideas"
    ],
    "pins": [],
    "maxVideos": 50,
    "minDurationSeconds": 0,
    "maxDurationSeconds": 0,
    "country": "us"
};

// Run the Actor and wait for it to finish
const run = await client.actor("apt_marble/pinterest-video-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 = {
    "queries": ["diy craft ideas"],
    "pins": [],
    "maxVideos": 50,
    "minDurationSeconds": 0,
    "maxDurationSeconds": 0,
    "country": "us",
}

# Run the Actor and wait for it to finish
run = client.actor("apt_marble/pinterest-video-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 '{
  "queries": [
    "diy craft ideas"
  ],
  "pins": [],
  "maxVideos": 50,
  "minDurationSeconds": 0,
  "maxDurationSeconds": 0,
  "country": "us"
}' |
apify call apt_marble/pinterest-video-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,apt_marble/pinterest-video-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/d8aGygooiBnb5CJcW/builds/8cJOcNilkgyye2I4U/openapi.json
