How to Scrape Pinterest in 2026

Learn how to extract dynamic Pinterest data using Python, headless browsers, and automated scraper APIs for fast, scalable results.
11 min read
How to Scrape Pinterest blog image

Extracting data from Pinterest is different from most HTML scraping jobs. Pinterest builds its pin grid entirely in the browser. The page does ship JSON blobs, such as __PWS_DATA__ and __PWS_INITIAL_PROPS__. Those hold app config and routing data, not pins. That means a plain HTTP request returns no pin data at all. You either drive a real browser, or you call Bright Data’s Pinterest Scraper API.

If you decide to follow along, you’ll learn how to collect Pinterest data using the following methods:

  • Extract Pinterest Data With Playwright
  • Extract Pinterest Data With Bright Data’s Pinterest Scraper API

TL;DR: Two Ways to Scrape Pinterest

Playwright Bright Data Scraper API
Setup Install Playwright plus browsers Install Requests, add an API key
Handles blocks You manage user agents and proxies Handled for you
Data returned Title, pin URL, thumbnail Full pin record, user, engagement, hashtags
Scope Pins visible on one search page Crawls the keyword, then scrapes every pin
Breaks when Pinterest changes its markup Managed by Bright Data
Cost Free, plus your own proxy spend 5,000 records a month free, then usage-based

What Can You Extract?

Open Pinterest in your browser and inspect a pin. Each one sits deeply nested inside a div with data-test-id="pinWrapper".

Inspect Pin

Find those objects on the page, and you can extract their data:

  • The title of each pin.
  • The url pointing directly to the pin.
  • The image of the pin from the search results.

Scraping Pinterest With Playwright

Getting Started

There are a lot of great scraping libraries in Python, and we’ll be using Playwright. First, you need to make sure you have Playwright installed. You can view their docs here. Playwright is one of the best headless browsers available.

Install Playwright

pip install playwright

Install Playwright’s Browsers

playwright install

Scraping the Actual Pins

Now, let’s look at how to scrape the actual pins from Pinterest. In the code below, we create two functions, scrape_pins() and main()scrape_pins() opens a browser and extracts data from Pinterest. main() gets used as an entry point for the async runtime.

import asyncio
from playwright.async_api import async_playwright
import json

user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36"


async def scrape_pins(query):
    search_url = f"https://www.pinterest.com/search/pins/?q={query}&rs=typed"
    scraped_data = []

    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page(user_agent=user_agent)
        response = await page.goto(search_url)
        await asyncio.sleep(2)
        try:
            #find the pins on the page
            pins = await page.query_selector_all("div[data-test-id='pinWrapper']")

            #iterate through the pins and extract data
            for pin in pins:
                title_link = await pin.query_selector("a")
                pin_url = await title_link.get_attribute("href")
                title = await title_link.get_attribute("aria-label")
                img = await title_link.query_selector("img")
                img_src = await img.get_attribute("src")

                extracted_data = {
                    "title": title,
                    "url": pin_url,
                    "img": img_src
                }
                #add the data to our results
                scraped_data.append(extracted_data)
        except Exception as e:
            print(f"Failed to scrape pins at {search_url}: {e}")
        finally:
            await browser.close()
    #everything has finished, return our scraped data
    return scraped_data

async def main():
    search_query = "office"
    office_results = await scrape_pins(search_query)

    with open(f"{search_query}-results.json", "w") as file:
        try:
            json.dump(office_results, file, indent=4)
        except Exception as e:
            print(f"Failed to save results: {e}")

if __name__ == "__main__":
    asyncio.run(main())

scrape_pins() performs the following steps during our scrape:

  • Create our url: search_url.
  • Create an array to hold our results, scraped_data.
  • Open a new browser instance.
  • Set a custom user_agent in order to run in headless mode. Without it, Pinterest will block us. Keep this string close to a current Chrome release, because a stale version is easy to flag.
  • We wait two seconds for content to load with asyncio.sleep(2).
  • We find all of the visible pins on the page using this selector: div[data-test-id='pinWrapper'].
  • For each pin, we extract the following data:
    • title: The title of the pin.
    • url: The url leading directly to the pin.
    • img: The image of the pin displayed in the search results.

Here is some sample data from the Playwright scraper above.

[
    {
        "title": "A minimalist office featuring a soothing color palette of whites, greys, and natural wood accents, creating a calm and spacious feel3",
        "url": "/pin/10203536650743650/",
        "img": "https://i.pinimg.com/236x/b3/21/e2/b321e2485da40c0dde2685c3a4fdcb56.jpg"
    },
    {
        "title": "a home office with two desks and an open door that leads to the outside",
        "url": "/pin/261912534574291013/",
        "img": "https://i.pinimg.com/236x/56/f1/29/56f129512885e1b3c9971b16f9445c9a.jpg"
    },
    {
        "title": "home office decor, blakc home office, dark home office, moody home office, small home office",
        "url": "/pin/60094976273327121/",
        "img": "https://i.pinimg.com/236x/ba/75/c9/ba75c9be7e635cce3ee80acdf70d6f9f.jpg"
    },
    {
        "title": "an office with a desk, chair and bookshelf in the middle of it",
        "url": "/pin/599682506666665720/",
        "img": "https://i.pinimg.com/236x/57/66/1d/57661dc80bebda3dfe946c070ee8ed13.jpg"
    },
    {
        "title": "a home office with green walls and plants on the shelves, along with a computer desk",
        "url": "/pin/1147080967585091410/",
        "img": "https://i.pinimg.com/236x/ce/e8/b7/cee8b74151b29605a80e0f61898c249d.jpg"
    },

Scraping Pinterest With the Bright Data Scraper API

With our Pinterest Scraper API, you can completely automate this process. You do not have to worry about headless browsers, selectors, or anything else.

Bright Data Pinterest Scraper

Make sure you’ve got Python Requests installed.

Install Requests

pip install requests

After you’ve set up your API call, you can trigger it from Python. Below, we also have two functions: get_pins() and poll_and_retrieve_snapshot().

  • get_pins(): This function takes a keyword alongside your api_key. It then creates and sends a request to our scraper API. This request triggers a scrape of Pinterest for your desired keyword.
  • poll_and_retrieve_snapshot() takes your api_key and the snapshot_id. It then checks every 10 seconds to see if the snapshot is ready. Once the snapshot is ready, the data is downloaded and we exit the function.
import requests
import json
import time

#function to trigger the scrape
def get_pins(api_key, keyword):
    url = "https://api.brightdata.com/datasets/v3/trigger"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    }
    params = {
        "dataset_id": "gd_lk0sjs4d21kdr7cnlv",
        "include_errors": "true",
        "type": "discover_new",
        "discover_by": "keyword",
    }
    data = [
        {"keyword":keyword},
    ]
    #trigger the scrape
    response = requests.post(url, headers=headers, params=params, json=data)
    #return the snapshot_id
    return response.json()["snapshot_id"]

def poll_and_retrieve_snapshot(api_key, snapshot_id, output_file="snapshot-data.json"):
    #create the snapshot url
    snapshot_url = f"https://api.brightdata.com/datasets/v3/snapshot/{snapshot_id}?format=json"
    headers = {
        "Authorization": f"Bearer {api_key}"
    }

    print(f"Polling snapshot for ID: {snapshot_id}...")

    while True:
        response = requests.get(snapshot_url, headers=headers)

        if response.status_code == 200:
            print("Snapshot is ready. Downloading...")
            snapshot_data = response.json()
            #write the snapshot to a new json file
            with open(output_file, "w", encoding="utf-8") as file:
                json.dump(snapshot_data, file, indent=4)
            print(f"Snapshot saved to {output_file}")
            break
        elif response.status_code == 202:
            print("Snapshot is not ready yet. Retrying in 10 seconds...")
        else:
            print(f"Error: {response.status_code}")
            print(response.text)
            break

        time.sleep(10)


if __name__ == "__main__":

    API_KEY = "YOUR-BRIGHT-DATA-API-KEY"
    KEYWORD = "office"
    
    snapshot_id = get_pins(API_KEY, KEYWORD)
    poll_and_retrieve_snapshot(API_KEY, snapshot_id)

Here is some sample data from the downloaded file. Since our trigger request had "include_errors": "true", the file also included pins with errors. The sample data below includes two error pins as well as two pins with good data.

[
    {
        "post_type": null,
        "timestamp": "2026-02-17T15:26:17.248Z",
        "input": {
            "url": "https://www.pinterest.com/pin/jh46IGe2",
            "discovery_input": {
                "keyword": "office"
            }
        },
        "warning": "Bad input. Wrong id!",
        "warning_code": "dead_page",
        "discovery_input": {
            "keyword": "office"
        }
    },
    {
        "post_type": null,
        "timestamp": "2026-02-17T15:26:18.757Z",
        "input": {
            "url": "https://www.pinterest.com/pin/4471026676503806548",
            "discovery_input": {
                "keyword": "office"
            }
        },
        "warning": "Bad input. Page does not exist.",
        "warning_code": "dead_page",
        "discovery_input": {
            "keyword": "office"
        }
    },
    {
        "url": "https://www.pinterest.com/pin/929782285570058239",
        "post_id": "929782285570058239",
        "title": "Essential Tips for Designing a Functional Small Office Space: Maximize Efficiency",
        "content": "17 Smart Tips for Designing a Productive Small Office Space",
        "date_posted": "2026-02-06T15:00:47.000Z",
        "user_name": "wellnesswink",
        "user_url": "https://www.pinterest.com/wellnesswink",
        "user_id": "929782422978147260",
        "followers": 232,
        "likes": 0,
        "categories": [
            "Explore",
            "Home Decor"
        ],
        "attached_files": [
            "https://i.pinimg.com/originals/c8/c0/d5/c8c0d5fb45352e40535db4510049a142.jpg"
        ],
        "image_video_url": "https://i.pinimg.com/originals/c8/c0/d5/c8c0d5fb45352e40535db4510049a142.jpg",
        "video_length": 0,
        "post_type": "image",
        "comments_num": 0,
        "discovery_input": {
            "keyword": "office"
        },
        "timestamp": "2026-02-17T15:26:19.502Z",
        "input": {
            "url": "https://www.pinterest.com/pin/929782285570058239",
            "discovery_input": {
                "keyword": "office"
            }
        }
    },
    {
        "url": "https://www.pinterest.com/pin/889812838892568569",
        "post_id": "889812838892568569",
        "title": "20 Modern Masculine Home Office Design Ideas for Men",
        "content": "Explore 25 chic home office decor ideas that blend style and functionality. Create a workspace you love and boost your productivity effortlessly!",
        "date_posted": "2026-01-27T07:11:38.000Z",
        "user_name": "artfullhouses",
        "user_url": "https://www.pinterest.com/artfullhouses",
        "user_id": "889812976285233957",
        "followers": 10,
        "likes": 0,
        "categories": [
            "Explore",
            "Home Decor"
        ],
        "attached_files": [
            "https://i.pinimg.com/originals/f1/cb/f7/f1cbf7b127db2bef2306ba19ffcc0646.png"
        ],
        "image_video_url": "https://i.pinimg.com/originals/f1/cb/f7/f1cbf7b127db2bef2306ba19ffcc0646.png",
        "video_length": 0,
        "hashtags": [
            "Mens Desk Decor",
            "Chic Home Office Decor",
            "Mens Desk",
            "Home Office Ideas For Men",
            "Office Ideas For Men",
            "Masculine Home Office Ideas",
            "Masculine Home Office",
            "Masculine Home",
            "Chic Home Office"
        ],
        "post_type": "image",
        "comments_num": 0,
        "discovery_input": {
            "keyword": "office"
        },
        "timestamp": "2026-02-17T15:26:20.069Z",
        "input": {
            "url": "https://www.pinterest.com/pin/889812838892568569",
            "discovery_input": {
                "keyword": "office"
            }
        }
    },

The Scraper API collects far more data than our Playwright scraper. Our API crawls Pinterest for your keyword. It then scrapes every individual pin it finds.

Convenience is not our only benefit from this approach. Our Pinterest Scraper API extracts your data at an extremely low cost. Our total results file was almost 45,000 lines long and it only cost $0.97 to generate. Every new account also includes 5,000 free records each month, with no credit card required.

Pinterest Scrape Cost

Hiring someone to build a scraper this good costs several hundred dollars. You would also wait days for your data. With our Scraper API, you get your data within minutes. It costs just a fraction as much.

Conclusion

Extracting data from Pinterest doesn’t have to be difficult. You can build your own scraper with Playwright. You can also use a fully automated solution like our Pinterest Scraper. The right approach depends on your needs.

Bright Data’s Scraper API removes the hassle of headless browsers and proxies. It handles CAPTCHAs for you. You get structured data without the maintenance work.

Faster results – Get data in minutes, not hours.
Cost-efficient – Pay only for what you extract.
No maintenance – Avoid dealing with blocked requests.

Try our How to scrape pinterest and get 5K records/month for free

Frequently Asked Questions

Can you scrape Pinterest without a headless browser?

Not for pin data. Pinterest renders its pin grid in the browser. The HTML does contain JSON blobs such as __PWS_DATA__, but they hold app config and routes. You need a real browser, or a scraper API that runs one for you.

Which selector finds pins on a Pinterest search page?

Each pin sits in a div with the attribute data-test-id=”pinWrapper”. Inside it, the anchor holds the pin URL and the aria-label title. The img tag inside that anchor holds the thumbnail URL.

Why does Pinterest block my headless browser?

Default headless browsers announce themselves through the user agent. Setting a current Chrome user agent avoids the most basic checks. At higher volume you also need rotating proxies to avoid rate limits.

Is scraping Pinterest legal?

Scraping publicly available data is generally permitted in many jurisdictions. Personal data and copyrighted images carry extra obligations under laws such as GDPR. Check Pinterest’s terms and take legal advice for your own use case.

How much does the Pinterest Scraper API cost?

Every new Bright Data account includes 5,000 free records each month. Beyond that you pay per record, and you only pay for successful results. The run in this guide produced almost 45,000 lines for $0.97.

No credit card required
Jake Nulty

Technical Writer

6 years experience

Jacob Nulty is a Detroit-based software developer and technical writer exploring AI and human philosophy, with experience in Python, Rust, and blockchain.

Expertise
Data Structures Python Rust