# Pinterest Scraper & Monitor - Pins, Boards, Trends (`thirdwatch/pinterest-scraper`) Actor

Scrape and monitor public Pinterest pins from search, user feeds, boards, and pin URLs. Get images, products, videos, and engagement via fast HTTP.

- **URL**: https://apify.com/thirdwatch/pinterest-scraper.md
- **Developed by:** [Thirdwatch](https://apify.com/thirdwatch) (community)
- **Categories:** Social media
- **Features:** Limited permissions
- **Stats:** 473 total users, 83 monthly users, 99.9% runs succeeded, 2 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.20 / 1,000 results

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

## Pinterest Scraper & Monitor

> **Thirdwatch portfolio:** 8,800+ users across 140+ public Actors, 2M+ records delivered, >95% run success. [Explore all Thirdwatch Actors](https://apify.com/thirdwatch).

### What you get

Scrape public Pinterest search results, pins from user feeds, boards, and individual pins. Collect full-resolution images, destination links, creator and board data, product and video metadata, and the engagement counts Pinterest publishes for each source. Turn on monitoring to emit only new pins or engagement changes on scheduled runs.

The Actor reads Pinterest's public web resources directly. It does not require a Pinterest login or browser-based access.

### Why use this Pinterest scraper?

- **Four sources in one Actor:** keywords, usernames, board URLs, and pin URLs.
- **Incremental monitoring:** schedule a Task and receive only newly discovered pins or changed public engagement metrics.
- **Commercial fields:** distinguish the canonical `pin_url` from the pin's `outbound_url`, and identify product, price, currency, availability, video, and Story Pin metadata when Pinterest exposes it.
- **Research context:** every row includes its input source, result position, creator, board, image dimensions, and scrape timestamp.
- **Low operating cost:** efficient, login-free collection keeps per-result pricing low, with further discounts at higher usage tiers.

### Quick start

Search for visual trends:

```json
{
  "searchQueries": ["home office ideas", "summer fashion trends"],
  "maxResults": 100,
  "includeDetails": true
}
```

Monitor a board for new pins:

```json
{
  "boardUrls": ["https://www.pinterest.com/pinterest/official-news/"],
  "maxResults": 100,
  "monitorMode": "new-pins",
  "monitorStoreName": "official-news-watch"
}
```

Run the same input on a schedule. The first run establishes a baseline and emits the current pins; later runs emit only pins that were not in that monitor's history.

### Input

Provide at least one source. Sources may be combined, and `maxResults` is the total cap across the run, shared evenly between sources. In a normal run, rows a short or unreadable source does not use go to sources with more pins. In a monitor, each source keeps a fixed share so its watch window stays the same between runs.

| Field | Type | Description |
|---|---|---|
| `searchQueries` | string\[] | Pinterest keyword searches. |
| `usernames` | string\[] | Public Pinterest usernames, with or without `@`, or profile links. |
| `boardUrls` | string\[] | Public Pinterest board links on any country domain, with or without `https://`, or `pin.it` share links. |
| `pinUrls` | string\[] | Pinterest pin links on any country domain, title-style links such as `/pin/my-title--123456/`, `pin.it` share links, or numeric pin IDs. |
| `maxResults` | integer | Total pins to collect, shared between sources, from 1 to 10,000. Default: 10. |
| `includeDetails` | boolean | Looks up each pin that has a numeric ID for its full public fields, one extra request per pin. See [Fields by source](#fields-by-source). Detailed runs support up to 500 results. |
| `monitorMode` | string | `off`, `new-pins`, or `engagement-changes`. |
| `monitorStoreName` | string | Optional stable identity for a scheduled watch. Reuse it on every run. |

`engagement-changes` automatically enables detailed lookups and compares the counts Pinterest publishes for each source.

If one source cannot be read, the run keeps the rows from the others, leaves that source's history unchanged, and names it in the run's `OUTPUT` record and status message. A run fails only when no source could be read, and a monitor then keeps its state exactly as it was. A source Pinterest answers with no pins counts as a success.

Each run stops shortly before its time limit, keeps the rows collected so far, and reports what it did not finish.

#### Fields by source

| Source | Saves | Reactions | Repins | Comments and shares | SEO fields |
|---|---|---|---|---|---|
| Username feeds | Yes | When shown | With `includeDetails` | With `includeDetails` | Yes |
| Direct numeric pin links | Yes | When shown | Yes | Yes | Yes |
| Boards | Yes | When shown | Yes | No | No |
| Search | No | When shown | No | No | No |

Pinterest identifies search and board pins with a long ID containing letters instead of a number, and does not publish individual lookups for them. `includeDetails` adds nothing to those rows, and their `pin_url` cannot be used as a `pinUrls` input. Links to them still open on Pinterest.

### Output

One dataset row represents one current pin or one monitoring event.

```json
{
  "pin_id": "123456789",
  "title": "Modern home office setup",
  "description": "A compact workspace with natural light",
  "pin_url": "https://www.pinterest.com/pin/123456789/",
  "outbound_url": "https://example.com/workspace-guide",
  "image_url": "https://i.pinimg.com/originals/...jpg",
  "image_width": 1200,
  "image_height": 1800,
  "pinner_username": "designstudio",
  "pinner_followers": 18400,
  "board_name": "Small Office Ideas",
  "board_pin_count": 342,
  "saves_count": 91,
  "reaction_count": 14,
  "repin_count": 37,
  "comment_count": 3,
  "share_count": 5,
  "is_product": false,
  "is_video": false,
  "source_type": "search",
  "source_value": "home office ideas",
  "position": 1,
  "change_type": "engagement-change",
  "changed_fields": ["saves_count", "repin_count"],
  "scraped_at": "2026-07-20T08:00:00+00:00"
}
```

Important URL semantics:

- `pin_url` is always the canonical Pinterest pin page.
- `outbound_url`, `url`, and `link` are the external destination attached to the pin. `url` and `link` remain compatibility aliases for existing integrations.

Fields can be absent when Pinterest does not publish them for a pin. `likes_count` remains a backward-compatible numeric alias and defaults to `0`; use nullable `saves_count` when distinguishing unavailable data from an observed zero. Pinterest's public payload describes this metric as saves, not likes.

#### Run summary

Every run also saves an `OUTPUT` record with `rowsReturned`, `pinsRead`, `sources` (each input with its status and pin count), and `skippedSources` (each input that was not fully read, and why).

### Monitoring behavior

| Mode | First run | Later scheduled runs |
|---|---|---|
| `off` | Current snapshot | Current snapshot |
| `new-pins` | Current pins marked `new` | Only pin IDs first seen by this monitor |
| `engagement-changes` | Current pins marked `new` | New pins plus changes in the counts published for that source |

Monitoring history is stored in a dedicated Apify key-value store and capped at 20,000 pin IDs per watch. An evicted pin can be classified as new if it later reappears. State is written only after dataset events are published, providing at-least-once delivery if a run is interrupted. Avoid overlapping runs with the same monitor name; schedule the next run after the previous one can finish.

### Use cases

- Track competitor boards and content cadence.
- Discover rising visual, fashion, home, food, wedding, and product trends.
- Monitor engagement movement for campaign and creator reporting.
- Build product-research, moodboard, or creative-brief datasets.
- Find destination domains and product pins in a niche.
- Feed Pinterest research into Sheets, webhooks, Make, Zapier, or your data warehouse.

### Limitations

- Only data visible through Pinterest's public, logged-out web surfaces is returned. Private boards and account-only data are unavailable.
- Pinterest may omit engagement, product, price, video, or Story Pin fields for individual pins.
- User feeds can include pins a user saved; they are not guaranteed to include only original creations.
- Deleted pins and removals are not emitted as events. Monitoring detects additions and available engagement changes.
- Pinterest CDN URLs can change. Download assets you need to retain long term in accordance with applicable rights and terms.

### FAQ

#### Do I need a Pinterest account or API key?

No. The Actor works with public Pinterest pages and resources.

#### Can I monitor several boards independently?

Yes. Create one saved Task per watch and give each a distinct `monitorStoreName`. Schedule the Tasks at the cadence you need.

#### Why is an engagement count null?

Pinterest does not expose every metric on every pin. The Actor returns a value only when the public payload supplies it and does not turn a temporary omission into a false zero.

#### Does detailed mode use a browser?

No. It performs one additional request for each pin with a numeric ID, so it is richer but slower than the default snapshot on username feeds.

#### Is this an official Pinterest API?

No. This is an independent scraper for publicly accessible web data and is not affiliated with Pinterest.

### Related Actors

- [Instagram Scraper - Posts, Profiles & Engagement](https://apify.com/thirdwatch/instagram-scraper) — Thirdwatch
- [TikTok Scraper - Videos, Creators & Trends](https://apify.com/thirdwatch/tiktok-scraper) — Thirdwatch

Last verified: 2026-07-20

Explore more production scrapers at [thirdwatch.dev](https://thirdwatch.dev).

# Actor input Schema

## `searchQueries` (type: `array`):

List of search terms to find pins for. Examples: 'minimalist bedroom', 'web design inspiration', 'healthy recipes'.

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

List of Pinterest usernames or profile links to scrape pins from. Example: 'pinterest', '@interiordesign', 'https://www.pinterest.com/pinterest/'.

## `boardUrls` (type: `array`):

List of Pinterest board links to scrape pins from, on any country domain. Example: 'https://www.pinterest.com/username/board-name/'. Share links from pin.it also work.

## `pinUrls` (type: `array`):

List of specific Pinterest pins to scrape: pin links on any country domain, title-style links, pin.it share links, or numeric pin IDs. Example: 'https://www.pinterest.com/pin/123456789/'.

## `includeDetails` (type: `boolean`):

Look up each pin that has a numeric ID for its public engagement counts, video, Story Pin, product, hashtag, and SEO fields. This covers username feeds and direct pin links; search and board rows keep the fields their feed provides. Adds a little time per pin and supports up to 500 results.

## `monitorMode` (type: `string`):

Off returns the current snapshot. New pins emits only pins first seen by this watch. Engagement changes emits new pins plus changes in the public counts Pinterest publishes for each source: reactions on search results, saves, repins and reactions on boards, and all counts on username feeds and direct pin links.

## `monitorStoreName` (type: `string`):

Stable name for this watch. Reuse the same name on scheduled runs. If omitted, the Actor derives one from the watched inputs.

## `maxResults` (type: `integer`):

Maximum total number of pins to scrape across all inputs, shared between them.

## Actor input object example

```json
{
  "searchQueries": [
    "minimalist kitchen design"
  ],
  "usernames": [],
  "boardUrls": [],
  "pinUrls": [],
  "includeDetails": false,
  "monitorMode": "off",
  "maxResults": 10
}
```

# 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 = {
    "searchQueries": [
        "minimalist kitchen design"
    ],
    "maxResults": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("thirdwatch/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 = {
    "searchQueries": ["minimalist kitchen design"],
    "maxResults": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("thirdwatch/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 '{
  "searchQueries": [
    "minimalist kitchen design"
  ],
  "maxResults": 10
}' |
apify call thirdwatch/pinterest-scraper --silent --output-dataset

```

## MCP server setup

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