Skip to content

Instantly share code, notes, and snippets.

@dctanner
Created July 15, 2025 15:40
Show Gist options
  • Save dctanner/e0e00b32d4df6936a8a19ac7da89a056 to your computer and use it in GitHub Desktop.
Save dctanner/e0e00b32d4df6936a8a19ac7da89a056 to your computer and use it in GitHub Desktop.
Import your Pocket saves into Pinboard
#!/usr/bin/env python3
"""
Pocket to Pinboard Import Script
This script imports bookmarks from a Pocket export CSV file to Pinboard.
To run this script with uv in a single command:
uv run --with pinboard https://gist.githubusercontent.com/dctanner/e0e00b32d4df6936a8a19ac7da89a056/raw/pocket_to_pinboard_standalone.py pocket_export.csv username:api_token
Or download first and run:
curl -O https://gist.githubusercontent.com/dctanner/e0e00b32d4df6936a8a19ac7da89a056/raw/pocket_to_pinboard_standalone.py
uv run --with pinboard pocket_to_pinboard_standalone.py pocket_export.csv username:api_token
Requirements:
- uv (install from https://github.com/astral-sh/uv)
- A Pocket export CSV file (export from https://getpocket.com/export)
- A Pinboard API token (get from https://pinboard.in/settings/password)
Usage:
python pocket_to_pinboard_standalone.py <pocket_csv_file> <pinboard_api_token>
Arguments:
pocket_csv_file Path to the Pocket export CSV file
pinboard_api_token Pinboard API token in username:token format
Example:
python pocket_to_pinboard_standalone.py pocket_export.csv myusername:1234567890ABCDEF
Note: The script respects Pinboard's rate limiting (3 seconds between requests).
"""
import csv
import argparse
import time
from datetime import datetime
import pinboard
def parse_pocket_csv(csv_file):
"""Parse Pocket export CSV and return list of bookmarks."""
bookmarks = []
with open(csv_file, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
# Skip items without URLs
if not row.get('url'):
continue
bookmark = {
'url': row['url'],
'description': row.get('title', ''),
'tags': row.get('tags', '').split(',') if row.get('tags') else [],
'time': datetime.fromtimestamp(int(row.get('time_added', 0))) if row.get('time_added') else None,
'toread': row.get('status') == 'unread'
}
bookmarks.append(bookmark)
return bookmarks
def import_to_pinboard(bookmarks, api_token):
"""Import bookmarks to Pinboard."""
pb = pinboard.Pinboard(api_token)
total = len(bookmarks)
successful = 0
failed = 0
print(f"Starting import of {total} bookmarks...")
for i, bookmark in enumerate(bookmarks, 1):
try:
# Pinboard API has rate limiting (1 request per 3 seconds)
if i > 1:
time.sleep(3)
pb.posts.add(
url=bookmark['url'],
description=bookmark['description'],
tags=' '.join(bookmark['tags']),
dt=bookmark['time'],
toread=bookmark['toread']
)
successful += 1
print(f"[{i}/{total}] Added: {bookmark['description'][:50]}...")
except Exception as e:
failed += 1
print(f"[{i}/{total}] Failed to add {bookmark['url']}: {str(e)}")
print(f"\nImport complete!")
print(f"Successful: {successful}")
print(f"Failed: {failed}")
def main():
parser = argparse.ArgumentParser(description='Import Pocket bookmarks to Pinboard')
parser.add_argument('csv_file', help='Path to Pocket export CSV file')
parser.add_argument('api_token', help='Pinboard API token (username:token format)')
args = parser.parse_args()
# Parse CSV
try:
bookmarks = parse_pocket_csv(args.csv_file)
print(f"Parsed {len(bookmarks)} bookmarks from CSV")
except Exception as e:
print(f"Error reading CSV file: {e}")
return 1
# Import to Pinboard
try:
import_to_pinboard(bookmarks, args.api_token)
except Exception as e:
print(f"Error during import: {e}")
return 1
return 0
if __name__ == '__main__':
exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment