pin-dl
v0.1.0
Published
Pinterest media downloader CLI — TypeScript port of pinterest-dl using Effect.ts
Readme
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-dlQuick 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 --resumeCommands
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 chromiumExample:
pin-dl login -o cookies.json --headful --wait 20
# On success, prints the next step:
# Use: pin-dl scrape <url> -o ./output --cookies cookies.jsonscrape
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]Shortcuts: Bare URLs and
getboth dispatch toscrape.similardispatches toscrape --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 |
Examples:
# 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 --videosearch
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]Shortcut: A bare string (no
https://, no subcommand) automatically dispatches tosearch. Multiple unquoted words are joined into a single query.
Accepts the same options as scrape (see table above).
Examples:
# 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.jsondownload
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 |
Examples:
# 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 txtWorkflow: 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.jsonResuming 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 --resumeIf you used --save-urls explicitly, that file takes precedence over the auto-save.
Ctrl+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>.tsif ffmpeg is missing) - Captions: same base name — e.g.
<pin_id>.txtor<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
.mp4using ffmpeg (must be inPATH). - Use
--skip-remuxto save the raw.tssegment file instead. - Use
--reencodeto 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 interruptedThis is useful for inspecting results before downloading, or deferring large downloads.
Building from Source
After cloning the repository, run:
pnpm install
vp run build # outputs to dist/
node dist/index.mjs # run directly