//pin-dlbyTheAlexLichter

pin-dl

0
0
0
TypeScript

pin-dl

Pinterest media downloader CLI.

✨ Inspired by pinterest-dl.

Requirements

  • Node.js >= 24
  • ffmpeg (optional, required for HLS video remuxing)

Installation

pnpm i -g pin-dl # or npm i -g pin-dl

Quick Start

# Download a board — bare URL, no subcommand needed
pin-dl https://www.pinterest.com/user/board-name/ -o ./output

# Search — bare query, no subcommand needed
pin-dl "dark academia interiors" -o ./refs -n 200
# Words without quotes also work:
pin-dl dark academia interiors -o ./refs -n 200

# Log in for private boards
pin-dl login

# Download a board section
pin-dl https://www.pinterest.com/user/board/ --section "Kitchen Ideas" -o ./kitchen

# Resume an interrupted download
pin-dl download board.json -o ./output --resume

Commands

login

Opens a browser to log in to Pinterest and saves session cookies for use with private boards.

pin-dl login [options]
Option Alias Default Description
--output -o cookies.json Path to save the cookies file
--client chromium Browser engine: chromium | firefox | webkit
--browser-executable Path to a custom browser binary (skips Playwright install check). Also reads pin-dl_BROWSER_EXECUTABLE env var.
--headful false Show the browser window
--incognito false Use an isolated browser context
--wait 10 Seconds to wait after login for cookies to settle
--verbose false Enable verbose output

The browser binary is downloaded automatically on first use if not found (requires confirmation). To install manually:

npx playwright install chromium

undefinedExample:undefined

pin-dl login -o cookies.json --headful --wait 20
# On success, prints the next step:
#   Use: pin-dl scrape <url> -o ./output --cookies cookies.json

scrape

Scrapes images (and optionally videos) from Pinterest board, section, or pin URLs.

pin-dl <url>...          # bare URL shortcut — no subcommand needed
pin-dl get <url>...      # alias for scrape
pin-dl similar <url>     # alias for scrape --related
pin-dl scrape <url>... [options]
pin-dl scrape --file urls.txt [options]

undefinedShortcuts: Bare URLs and get both dispatch to scrape. similar dispatches to scrape --related.

Option Alias Default Description
--output -o Output directory for downloaded files. If omitted, prints JSON to stdout.
--file -f File containing URLs, one per line. Use - for stdin.
--stdin false Read URLs from stdin (alias for --file -)
--cookies -c Path to cookies JSON for private boards
--limit -n 100 Maximum number of items to scrape
--min-res -r Minimum resolution filter, e.g. 512x512 — skips smaller images
--section Board section to scrape by name, e.g. --section "Kitchen Ideas"
--related false For pin URLs: scrape related/similar pins instead
--video false Download video streams if available
--skip-remux false Skip ffmpeg remux; output raw .ts file
--reencode false Force re-encode HLS to MP4 (slower; overrides --skip-remux)
--timeout 10 Request timeout in seconds
--delay 0.2 Delay between requests in seconds
--save-urls Save scraped URLs to a JSON file for later use with pin-dl download
--filename {id} Filename template. Variables: {id}, {alt}, {index}. See below.
--dry-run false Print found URLs to stdout without downloading anything
--skip-existing --resume, --continue false Skip files that already exist in the output directory
--caption none Caption format: txt | json | metadata | none
--ensure-cap false Only include items that have alt text
--cap-from-title false Use image title as caption instead of auto_alt_text
--verbose false Print each downloaded URL
--dump Save raw API request/response pairs to a directory for debugging
--log-file Append all log output to this file

undefinedExamples:undefined

# Bare URL — no subcommand needed
pin-dl https://www.pinterest.com/user/board-name/ -o ./output --limit 200

# Download a specific board section
pin-dl https://www.pinterest.com/user/home-ideas/ --section "Kitchen" -o ./kitchen

# Find similar pins (alias: pin-dl similar <url>)
pin-dl https://www.pinterest.com/pin/123456789/ --related -n 50 -o ./similar

# Batch from a file; read from stdin
pin-dl scrape --file urls.txt -o ./output -c cookies.json
cat urls.txt | pin-dl --stdin -o ./output

# Save scraped URLs for later download (no download yet)
pin-dl https://www.pinterest.com/user/board/ --save-urls board.json

# Filter by minimum resolution
pin-dl scrape <url> -o ./output --min-res 1024x768

# Dry run — inspect URLs without downloading
pin-dl https://www.pinterest.com/user/board/ --dry-run

# Resume after interruption
pin-dl scrape <url> -o ./output --resume

# Download videos
pin-dl scrape <url> -o ./output --video

Searches Pinterest for a keyword and downloads results.

pin-dl "query"                   # bare query shortcut — no subcommand needed
pin-dl dark academia interiors   # unquoted words are joined into one query
pin-dl search <query>... [options]
pin-dl search --file queries.txt [options]

undefinedShortcut: A bare string (no https://, no subcommand) automatically dispatches to search. Multiple unquoted words are joined into a single query.

Accepts the same options as scrape (see table above).

undefinedExamples:undefined

# Bare query — no subcommand needed
pin-dl "minimalist interior" -o ./output -n 50

# Multiple queries processed sequentially
pin-dl search "cats" "dogs" -o ./output

# Search from a file of queries
pin-dl search --file queries.txt -o ./output --save-urls results.json

download

Downloads media from a previously saved --save-urls file.

pin-dl download <cache.json> [options]

Passing a URL instead of a cache file prints a helpful error pointing to the correct command.

Option Alias Default Description
--output -o filename without extension Output directory
--min-res -r Minimum resolution filter, e.g. 512x512
--filename {id} Filename template. Variables: {id}, {alt}, {index}
--video false Download video streams if available
--skip-remux false Skip ffmpeg remux; output raw .ts file
--reencode false Force re-encode HLS to MP4
--skip-existing --resume, --continue false Skip files that already exist in the output directory
--caption none Caption format: txt | json | metadata | none
--ensure-cap false Only download items that have alt text
--verbose false Print each downloaded file path
--log-file Append all log output to this file

undefinedExamples:undefined

# Download from a saved URL list
pin-dl download board.json -o ./output

# Resume an interrupted download
pin-dl download board.json -o ./output --resume

# Download only captioned items
pin-dl download board.json -o ./output --ensure-cap --caption txt

Workflow: Private Boards

# 1. Log in and save cookies
pin-dl login -o cookies.json

# 2. Scrape a private board using the cookies
pin-dl scrape https://www.pinterest.com/user/private-board/ -o ./output -c cookies.json

Resuming Interrupted Downloads

When you run pin-dl scrape <url> -o <dir>, scraped URLs are automatically saved to <dir>.json alongside the download. If the download is interrupted:

# Option 1: resume from the auto-saved URL list
pin-dl download ./output.json -o ./output --resume

# Option 2: re-run the scrape with --resume (re-fetches URLs, skips existing files)
pin-dl scrape <url> -o ./output --resume

If you used --save-urls explicitly, that file takes precedence over the auto-save.

undefinedCtrl+C hint: pin-dl prints the exact resume command when interrupted.


Output File Naming

By default, files are named by their Pinterest pin ID:

  • Images: <pin_id>.jpg (or .png, etc. based on source)
  • Videos: <pin_id>.mp4 (or <pin_id>.ts if ffmpeg is missing)
  • Captions: same base name — e.g. <pin_id>.txt or <pin_id>.json

Use --filename to customise the naming pattern:

Variable Value
{id} Pinterest pin ID (default)
{alt} Sanitized alt text (spaces → _, special chars stripped). Falls back to {id} if empty.
{index} 1-based position in the batch
# Sequential numbering
pin-dl <url> -o ./output --filename "{index}-{id}"
# → 1-123456.jpg, 2-789012.jpg, ...

# Name by alt text
pin-dl <url> -o ./output --filename "{alt}"
# → dark_moody_aesthetic.jpg, minimalist_desk_setup.jpg, ...

Captions

The --caption option writes metadata alongside each downloaded file:

Mode Output
txt <filename>.txt containing alt text
json <filename>.json containing {src, alt, origin}
metadata Attempts to embed EXIF metadata (shows warning if unsupported)
none No caption files (default)

Use --cap-from-title to prefer the pin title over auto_alt_text.
Use --ensure-cap to skip items that have no caption text.


Videos

Pinterest pins may include HLS (.m3u8) video streams. Pass --video to download them.

  • By default, streams are remuxed to .mp4 using ffmpeg (must be in PATH).
  • Use --skip-remux to save the raw .ts segment file instead.
  • Use --reencode to force a full re-encode to MP4 (slower, maximum compatibility).

Caching / Two-Step Workflow

Save scraped media metadata to a JSON file with --save-urls, then download later:

pin-dl <url> --save-urls board.json            # scrape only, save URLs
pin-dl download board.json -o ./output         # download from saved list
pin-dl download board.json -o ./output --resume  # resume if interrupted

This is useful for inspecting results before downloading, or deferring large downloads.


Building from Source

You need vite-plus installed to use vp globally.

After cloning the repository, run:

vp install
vp run build          # outputs to dist/
node dist/index.mjs   # run directly
[beta]v0.14.0