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

Scrape Pinterest pins from keyword search, boards, sections, profiles and pin URLs: images in all sizes, video, outbound link, saves, comments, product price, board and pinner data.

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

## Pricing

$2.50 / 1,000 pin, board or profiles

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 — Pins, Boards & Profiles

Scrape Pinterest pins from **keyword search**, **boards**, **board sections**, **profiles** and **pin URLs** into a clean dataset: title, description, image URLs in every size, video URL, outbound link and domain, saves, repins, comments, reactions, created date, board name and URL, pinner username, name and follower count, and rich-pin product data (price, currency, in stock) when the pin has it. Board and profile URLs also give one metadata item each: followers, pin and board counts, description, website, owner.

No login, no cookies, no browser: the Actor reads the same public JSON Pinterest's own web app loads for logged-out visitors, about 25 pins per request. Download the results as JSON, CSV or Excel, or pull them through the API into your own app, Google Sheets or an LLM pipeline. You pay per item you get.

### What data does Pinterest Scraper extract?

Every pin (`type: "pin"`):

| Field | Description |
|---|---|
| `id`, `url` | Pin id and URL (`https://www.pinterest.com/pin/<id>/`) |
| `title`, `description`, `altText` | Title as shown (falls back to the rich-pin title), the pin description, and the image alt text |
| `link`, `domain` | Outbound link of the pin and its domain (`null` for pins uploaded without a link) |
| `imageUrl`, `imageWidth`, `imageHeight` | Original-size image and its size |
| `images` | Every size Pinterest lists: `{"236x": {url, width, height}, "474x": ..., "736x": ..., "orig": ...}` |
| `dominantColor` | Main color of the image (`#5c5747`) |
| `isVideo`, `videoUrl`, `videoHlsUrl`, `videoDurationSec`, `videoThumbnailUrl` | Video pins: MP4 (with **Fetch full pin details**, or for pin URLs) or the HLS stream (`.m3u8`), duration in seconds, poster image |
| `saveCount`, `repinCount` | Saves and repins as Pinterest counts them. Board, section and profile pins always have them; search pins get them with **Fetch full pin details** |
| `commentCount`, `shareCount` | With **Fetch full pin details** and for pin URLs |
| `reactionCount` | Sum of the pin's reactions |
| `createdAt` | When the pin was created (ISO 8601, UTC) |
| `boardId`, `boardName`, `boardUrl` | The board the pin is saved to |
| `pinnerId`, `pinnerUsername`, `pinnerFullName`, `pinnerUrl`, `pinnerImageUrl`, `pinnerVerified` | Who saved the pin |
| `pinnerFollowerCount` | Follower count of the pinner as shown in search results and pin pages (`null` in board feeds, which do not carry it) |
| `richPinType`, `siteName` | Rich-pin type (`product`, `article`, `recipe`) and the source site name |
| `product` | Product pins: `{name, price, priceValue, currency, availability, inStock, siteName}`, e.g. `"$120.00"`, `120`, `"USD"`, `"in_stock"` |
| `hashtags` | Hashtags of the pin |
| `isPromoted`, `isRepin` | Ad flag (ads are skipped unless you turn them on) and whether the pin is a repin |
| `sourceType`, `source`, `scrapedAt` | Where the pin came from (`search` + the term, `board`, `section`, `profile`, `pin` + the URL) and when |
| `changeType` | Only with **Only new or changed items** on: `new` |
| `detailError` | Only when **Fetch full pin details** is on and that one pin's page could not be loaded (the pin keeps its feed data) |

Boards (`type: "board"`) from board URLs and from `/<user>/_saved/`: `id`, `url`, `name`, `description`, `pinCount`, `sectionlessPinCount`, `followerCount`, `sectionCount`, `collaboratorCount`, `isCollaborative`, `category`, `coverImageUrl`, `createdAt`, `lastModifiedAt`, `ownerId`, `ownerUsername`, `ownerFullName`, `ownerUrl`.

Profiles (`type: "profile"`) from profile URLs: `id`, `username`, `url`, `fullName`, `about`, `websiteUrl`, `domainUrl`, `domainVerified`, `followerCount`, `followingCount`, `pinCount`, `boardCount`, `videoPinCount`, `monthlyViews` (as shown; Pinterest caps it at 10,000,001 = "10m+"), `imageUrl`, `coverImageUrl`, `isVerified`, `isVerifiedMerchant`, `isPartner`, `createdAt`, `lastPinSavedAt`.

### How to use Pinterest Scraper

1. Type **Search terms** (one per line) and/or paste **Pinterest URLs**:

   | URL | What you get |
   |---|---|
   | `https://www.pinterest.com/bhg/adorable-pets/` | Board item + the board's pins |
   | `https://www.pinterest.com/bhg/<board>/<section>/` | The pins of one board section |
   | `https://www.pinterest.com/bhg/` (or `/_created/`) | Profile item + the user's pins, newest first |
   | `https://www.pinterest.com/bhg/_saved/` | Profile item + one item per board of the user |
   | `https://www.pinterest.com/pin/670473463305409641/`, `https://pin.it/...` | That pin, with full details |
   | `https://www.pinterest.com/search/pins/?q=...`, `/search/videos/?q=...` | Pin or video search |

   Country domains (`pinterest.co.uk`, `de.pinterest.com`, ...) work too.
2. Set **Max results** (total, caps the cost) and, with several sources, **Max pins per search / board / profile**.
3. Turn on **Fetch full pin details** if you need comment counts, MP4 video URLs or save counts for search results (one extra request per pin, same price per result).
4. Click **Start**. Results appear in the **Dataset** tab; export from there or use the API.

### Input example

```json
{
  "searchTerms": ["cottage garden ideas"],
  "startUrls": [
    { "url": "https://www.pinterest.com/bhg/adorable-pets/" },
    { "url": "https://www.pinterest.com/bhg/" }
  ],
  "maxPinsPerSource": 50,
  "maxItems": 200,
  "includeDetails": false,
  "includeBoardAndProfileInfo": true,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

### Output example

A pin from a board (a few `null` fields left out):

```json
{
  "type": "pin",
  "id": "56787645295483271",
  "url": "https://www.pinterest.com/pin/56787645295483271/",
  "title": "Throw a Puppy Picnic for Your Four-Legged Pals This Summer",
  "description": "Show your furry friends some love with a festive outdoor party, complete with homemade dog treats and plenty of playtime. ... #partyfordogs #outdoorpartyideas #dogbirthday #dogpartyideas #bhg",
  "altText": "a basket filled with lots of signs next to a building",
  "link": "https://www.bhg.com/party/puppy-picnic/?utm_source=pinterest.com&utm_medium=social&utm_campaign=bhg_5304692&utm_content=standard_seasonal&utm_term=adorablepets_202106",
  "domain": "bhg.com",
  "imageUrl": "https://i.pinimg.com/originals/b7/27/6b/b7276b5079c927f16572d26cf4b59677.jpg",
  "imageWidth": 1244,
  "imageHeight": 1560,
  "images": {
    "236x": { "url": "https://i.pinimg.com/236x/b7/27/6b/b7276b5079c927f16572d26cf4b59677.jpg", "width": 236, "height": 295 },
    "474x": { "url": "https://i.pinimg.com/474x/b7/27/6b/b7276b5079c927f16572d26cf4b59677.jpg", "width": 474, "height": 594 },
    "736x": { "url": "https://i.pinimg.com/736x/b7/27/6b/b7276b5079c927f16572d26cf4b59677.jpg", "width": 736, "height": 922 },
    "orig": { "url": "https://i.pinimg.com/originals/b7/27/6b/b7276b5079c927f16572d26cf4b59677.jpg", "width": 1244, "height": 1560 }
  },
  "dominantColor": "#726351",
  "isVideo": false,
  "videoUrl": null,
  "saveCount": 3,
  "repinCount": 2,
  "commentCount": null,
  "reactionCount": 0,
  "createdAt": "2021-06-04T00:04:44Z",
  "boardId": "56787713990443348",
  "boardName": "Adorable Pets",
  "boardUrl": "https://www.pinterest.com/bhg/adorable-pets/",
  "pinnerUsername": "bhg",
  "pinnerFullName": "Better Homes and Gardens",
  "pinnerUrl": "https://www.pinterest.com/bhg/",
  "pinnerVerified": true,
  "richPinType": null,
  "product": null,
  "hashtags": ["partyfordogs", "outdoorpartyideas", "dogbirthday", "dogpartyideas", "bhg"],
  "isPromoted": false,
  "sourceType": "board",
  "source": "https://www.pinterest.com/bhg/adorable-pets/",
  "scrapedAt": "2026-10-09T23:42:57Z"
}
```

A product pin with full details (shortened):

```json
{
  "type": "pin",
  "id": "670473463305409641",
  "title": "Nike Dunk Low",
  "link": "https://www.nike.com/t/dunk-low-womens-shoes-ppQwKZ",
  "domain": "nike.com",
  "saveCount": 250,
  "repinCount": 1222,
  "commentCount": 0,
  "shareCount": 21,
  "createdAt": "2024-02-13T23:39:27Z",
  "pinnerUsername": "Juniebu6",
  "pinnerFollowerCount": 89,
  "richPinType": "product",
  "siteName": "Nike.com",
  "product": { "name": "Nike Dunk Low", "price": "$120.00", "priceValue": 120, "currency": "USD", "availability": "in_stock", "inStock": true, "siteName": "Nike.com" }
}
```

A board item:

```json
{
  "type": "board",
  "id": "56787713990443348",
  "url": "https://www.pinterest.com/bhg/adorable-pets/",
  "name": "Adorable Pets",
  "pinCount": 431,
  "followerCount": 3395457,
  "sectionCount": 0,
  "category": "animals",
  "lastModifiedAt": "2024-05-24T22:25:10Z",
  "ownerUsername": "bhg",
  "ownerFullName": "Better Homes and Gardens"
}
```

### How to scrape Pinterest pins by keyword

Put your keywords in **Search terms**, one per line, or paste a Pinterest search URL (`/search/pins/?q=...` for pins, `/search/videos/?q=...` for video pins). The Actor pages through the results the way the site does when you scroll, about 25 pins per request; searches go several hundred pins deep. Promoted pins (ads) are skipped unless you turn on **Include promoted pins**. Search results do not include save or comment counts; turn on **Fetch full pin details** to add them.

### How to scrape a Pinterest board or profile

Paste the board URL (`pinterest.com/<user>/<board>/`) or a section URL to get every pin of the board with saves, repins, outbound link and created date, plus one board item. A profile URL (`pinterest.com/<user>/`) gives the profile item (followers, monthly views, website, pin and board counts) and the user's pins, newest first; `pinterest.com/<user>/_saved/` lists the user's boards instead. Use **Max pins per search / board / profile** to take, say, the 50 newest pins of each.

### Monitor changes on a schedule

Turn on **Only new or changed items** and save the input as a task: each run then outputs only pins that earlier runs of the same task have not returned, for example new pins on a competitor's board or profile, or pins entering the top results of a search. Pins already returned are dropped before any detail request and are not charged, so a daily run where nothing changed costs almost nothing. Each run looks at the first **Max pins per search / board / profile** pins of every source (or **Max results** when that is empty). To schedule it, open the saved task in Apify Console and choose **Schedule**, for example daily at 07:00. New items carry `changeType: "new"`; use **Monitoring key** to keep several schedules on the same input separate.

### Does it work without a Pinterest login?

Yes. It only reads what Pinterest shows logged-out visitors: no account, cookies or session are needed, and nothing behind a login is collected. Pinterest sometimes shows logged-out visitors a shortened board ("see more ideas" after the first page); the Actor detects that and retries the page, so long boards come back complete.

### Can I download Pinterest images and videos?

Every pin has `imageUrl` (original size) and `images` with all sizes Pinterest lists. Video pins have `videoHlsUrl` (an `.m3u8` stream) and, with **Fetch full pin details** or for pin URLs, an MP4 `videoUrl`. The Actor returns the links; it does not download the files.

### How much does it cost to scrape Pinterest?

You pay per saved item (pin, board or profile), plus the small platform usage of the run (paid by you, about 1 request per 25 pins on the default datacenter proxy). Pins already seen in monitoring mode and skipped ads are not charged. **Fetch full pin details** adds one request per pin but no extra charge per result.

### Proxy note

The default Apify datacenter proxy works: Pinterest answers it normally. Responses are 15-300 KB (about 8 KB per pin), so proxy traffic stays small and RESIDENTIAL is not needed.

### Integrations and API

Use the run in Zapier, Make, n8n, Google Sheets, or call it from Python/Node with the Apify client. See the **API** tab for ready-made snippets.

### Is it legal to scrape Pinterest?

The Actor collects only data Pinterest shows publicly to any logged-out visitor: pins, boards and public profiles, including the public usernames and display names of pinners and board owners. It does not log in and does not collect anything private, hidden or behind a login. You are responsible for how you use the data and for complying with Pinterest's terms and applicable law (for example GDPR when you process personal data such as usernames).

### Support

Found a bug or need a field added? Open an issue in the **Issues** tab; it is usually answered within a day.

# Actor input Schema

## `searchTerms` (type: `array`):

Keywords to search on Pinterest, one per line (for example `cottage garden ideas`). Each term returns pins in Pinterest's search order, page after page, up to the limits below.

## `startUrls` (type: `array`):

Board URLs (`pinterest.com/user/board/`), board section URLs (`/user/board/section/`), profile URLs (`pinterest.com/user/` for the user's pins, `/user/_saved/` for the list of the user's boards), pin URLs (`/pin/123.../` or `pin.it/...` short links) and search URLs (`/search/pins/?q=...`, `/search/videos/?q=...`). Country domains such as pinterest.co.uk or de.pinterest.com work too.

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

Stop after this many items (pins, plus board / profile items) are saved in total. Every saved item is one charged result, so this caps the cost.

## `maxPinsPerSource` (type: `integer`):

Optional cap for each search term or URL, so several sources share the total fairly. Leave empty to take pins until Max results is reached. With monitoring on, this is the window each run looks at (the first N pins of every source; Max results is used when empty).

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

Make one extra request per pin for the full pin page data: comment count, share count, saves for search results, MP4 video URL, hashtags, full description and rich-pin product data. Off: search pins come without save/comment counts (board and profile pins still have saves and repins). Same price per result; the run takes longer.

## `includeBoardAndProfileInfo` (type: `boolean`):

For every board or profile URL, also save one item with its metadata (type `board` or `profile`: name, description, followers, pin and board counts, owner, website). Each such item is one charged result.

## `includePromotedPins` (type: `boolean`):

Search results can contain ads. Off (default): promoted pins are skipped and not charged.

## `onlyNewOrChanged` (type: `boolean`):

Remember which pins earlier runs of this input returned and output only pins not seen before (new pins on a board, profile or search). Use with a Schedule; pins already returned are skipped before any detail request and are not charged.

## `monitoringKey` (type: `string`):

Name for this watch, so several schedules on the same search stay separate; defaults to a key derived from the search input

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

Apify datacenter proxy (the default) works: Pinterest's public pages answer it normally. Responses are 15-300 KB (about 8 KB per pin), so proxy traffic stays small. RESIDENTIAL is not needed.

## Actor input object example

```json
{
  "searchTerms": [
    "cottage garden ideas"
  ],
  "startUrls": [
    {
      "url": "https://www.pinterest.com/bhg/adorable-pets/"
    }
  ],
  "maxItems": 100,
  "includeDetails": false,
  "includeBoardAndProfileInfo": true,
  "includePromotedPins": false,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "searchTerms": [
        "cottage garden ideas"
    ],
    "startUrls": [
        {
            "url": "https://www.pinterest.com/bhg/adorable-pets/"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/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 = {
    "searchTerms": ["cottage garden ideas"],
    "startUrls": [{ "url": "https://www.pinterest.com/bhg/adorable-pets/" }],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/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 '{
  "searchTerms": [
    "cottage garden ideas"
  ],
  "startUrls": [
    {
      "url": "https://www.pinterest.com/bhg/adorable-pets/"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call tortuga/pinterest-scraper --silent --output-dataset

```

## MCP server setup

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