# Pinterest Scraper | Profiles, Boards & Pins (`hridayrungta/pinterest-scraper`) Actor

Extracts Pinterest pins from any public profile, board, or single pin url/id - images at every resolution, video streams when present, description, dominant color, creator. No login, no browser, no proxy. Incremental mode returns only pins new since your last run.

- **URL**: https://apify.com/hridayrungta/pinterest-scraper.md
- **Developed by:** [Hriday Rungta](https://apify.com/hridayrungta) (community)
- **Categories:** Social media, Automation, E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.70 / 1,000 actor starteds

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

## Pinterest Scraper | Profiles, Boards & Pins

Extracts Pinterest pins from a public profile, a board, or a single pin URL/ID — images at every resolution, video streams when present, description, dominant color, tracking id, creator. No login, no API key, no browser, no proxy.

### What you get

- **Images at every resolution**: `236x`, `474x`, `736x` and the original, for every pin.
- **Video**: HLS (`.m3u8`) and MP4 stream URLs plus a thumbnail and duration, when a pin is a video pin from a profile or board.
- **Title, description, publish date, dominant color, tracking id.**
- **Creator and source**: which profile or board the pin came from, and that account's profile URL.
- **Incremental mode**: track profiles and boards over time — each run after the first only returns pins published since your last run.

### How this works (honestly)

Pinterest server-renders a `<script id="__PWS_INITIAL_PROPS__">` tag on every profile and board page with real pin data (images, video, dominant color, tracking id) baked into the HTML. This Actor fetches that page directly and parses it — no browser needed. It combines that with Pinterest's own legacy RSS feeds (`/username/feed.rss` for a profile, `/username/board-slug.rss` for a board), which are still live and carry the title, description and publish date the HTML embed doesn't. For a single pin, there's no RSS or embedded data anymore, so this Actor instead reads the page's Open Graph meta tags plus Pinterest's public, documented oEmbed endpoint (`pinterest.com/oembed.json`) for the creator's name and profile URL.

**The honest limit**: Pinterest's anonymous profile and board views only ever serve their newest ~25 pins — there is no working anonymous pagination past that. We tested this live: Pinterest's internal `/resource/.../get/` API (the one that powers infinite scroll) now rejects every ad-hoc request with `403 Invalid Resource Request`, even one replayed byte-for-byte from an authenticated browser tab. It only works when Pinterest's own front-end issues it as part of a live page load, which points to a short-lived signature this Actor has no anonymous way to produce. If you need more than ~25 pins from one source, run this Actor against multiple profiles/boards, or use incremental mode to accumulate pins over repeated runs.

**Why there's no keyword search**: for the same reason, Pinterest's search results page renders no pins server-side and has no RSS feed — its only data source is that same blocked internal API. Rather than ship a fragile, easily-broken search mode, this Actor doesn't offer one. Feed it a specific profile, board, or pin instead.

**No video stream URL for single-pin mode**: a standalone pin page no longer embeds the video data anonymously (only the profile/board HTML embed has it), so single-pin rows have every image size but no HLS/MP4 URL.

### Incremental mode

Set `mode: "changes"`. On the first run per profile/board, it seeds from `firstRunSince` (default 30 days). Every run after that only emits pins published since the last run, tracked in a key-value store. Because the anonymous feed itself only ever holds ~25 pins, a source that gains more than ~25 new pins between two runs will only show you the newest ~25 of them — the rest were never billed, but were also never seen. Run more often on high-volume accounts to avoid that gap. A run cut short by `maxItems` still advances the mark safely — no duplicate rows next time, no silent skips either.

### Input at a glance

| Field | Description |
|---|---|
| `profiles` | Pinterest usernames or profile URLs, one per line. |
| `boards` | Board URLs or `username/board-slug`, one per line. |
| `pins` | Pin URLs or bare numeric pin IDs, one per line. |
| `mode` | `"all"` (default) or `"changes"` (incremental, profiles/boards only). |
| `maxItems` | Budget cap on billed pins for this run. |
| `firstRunSince` | How far back the first incremental run looks (e.g. `"30 days"`). |

At least one of `profiles`, `boards`, or `pins` is required.

### Billing (pay-per-event)

| Event | Price |
|---|---|
| Actor started | $0.0017 — charged once per run, regardless of results |
| Pin scraped | $0.0011 per pin |

No proxy surcharge, no separate "with images" tier — every pin you're charged for already includes every image size (and video, when the pin has one).

# Actor input Schema

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

Pinterest profiles, one per line: a bare username ("nasa") or a full profile URL. Returns that profile's latest pins (Pinterest serves roughly the newest 25 anonymously, no further pagination).

## `boards` (type: `array`):

Pinterest boards, one per line: a full board URL ("https://www.pinterest.com/nasa/artemis/") or "username/board-slug". Same ~25-pin anonymous ceiling as profiles.

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

Individual pins, one per line: a full pin URL or a bare numeric pin id. Always fetched fresh - no video stream url for this mode (Pinterest doesn't expose it anonymously for a single pin page).

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

"all": every pin in the profile/board's anonymous feed, every run. "changes": only pins new since your last run, per profile/board. No effect on single pins.

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

Cost cap - you're billed once per pin saved. Each profile/board can only ever contribute its anonymous feed's pins (about 25), so raise this to cover multiple sources, not a single one.

## `firstRunSince` (type: `string`):

A profile/board's first incremental run only takes pins since this date/span - never assumes the whole feed is "new". Default "30 days"; "all" to take everything currently in the anonymous feed.

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

Retries with backoff for network errors and 5xx responses.

## `stateStoreName` (type: `string`):

Name of the key-value store (in YOUR account) that holds the high-water mark per profile/board. Leave blank for the default.

## `stateNamespace` (type: `string`):

Advanced: an explicit namespace for the mark key. Leave blank to namespace by your Apify user id automatically.

## Actor input object example

```json
{
  "profiles": [
    "nasa"
  ],
  "boards": [],
  "pins": [],
  "mode": "all",
  "maxItems": 100,
  "firstRunSince": "30 days",
  "maxRetries": 3,
  "stateStoreName": "",
  "stateNamespace": ""
}
```

# Actor output Schema

## `results` (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 = {
    "profiles": [
        "nasa"
    ],
    "boards": [],
    "pins": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("hridayrungta/pinterest-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": ["nasa"],
    "boards": [],
    "pins": [],
}

# Run the Actor and wait for it to finish
run = client.actor("hridayrungta/pinterest-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": [
    "nasa"
  ],
  "boards": [],
  "pins": []
}' |
apify call hridayrungta/pinterest-scraper --silent --output-dataset

```

## MCP server setup

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