A simple tool which lets you scrape twitter accounts and crosspost them to bluesky accounts! Comes with a CLI and a webapp for managing profiles! Works with images/videos/link embeds/threads.
···11-# Tweets to Bluesky Crossposter
11+# 🐦 Tweets-2-Bsky
2233-A powerful, set-and-forget tool to mirror your Twitter/X account to Bluesky.
33+A powerful tool to crosspost your Tweets to Bluesky automatically. Now supports **multiple accounts**, **custom PDS (hosting) locations**, and a **user-friendly CLI** for easy management.
4455-> **Credits:** This project is powered by [bird](https://github.com/steipete/bird) by [steipete](https://github.com/steipete) for robust Twitter/X data fetching.
55+## ✨ Features
6677-## Why this tool?
77+- **Multi-Account Support**: Sync Twitter A -> Bluesky A, Twitter B -> Bluesky B, or multiple Twitters to one Bluesky.
88+- **Interactive CLI**: Manage all your account mappings and credentials without touching code.
99+- **Custom PDS Support**: Works with `bsky.social` or any independent Bluesky hosting provider.
1010+- **Thread Support**: Maintains your Twitter threads perfectly on Bluesky.
1111+- **Media Support**: Automatically migrates high-quality images and videos.
1212+- **Smart Logic**: Automatically detects languages and expands short links.
1313+- **Safety First**: Includes a `--dry-run` mode to test before you post.
81499-Most crossposters are either paid services or lack key features. This tool is designed for power users who want a perfect mirror:
1515+---
10161111-* **Smart Media Handling:**
1212- * **Videos:** Downloads videos from Twitter and uploads them natively to Bluesky (up to 100MB).
1313- * **Images:** Uploads high-resolution images with the **correct aspect ratio** (no weird cropping).
1414- * **Links:** Automatically removes `t.co` tracking links and expands them to their real destinations.
1515-* **Smart Features:**
1616- * **Language Detection:** Automatically detects the language of your tweet (e.g., English, Japanese) and tags the Bluesky post correctly.
1717- * **Human-like Pacing:** Randomly waits (1-4s) between posts to behave more like a real user and avoid spam detection.
1818- * **Auto-Healing:** Automatically rotates internal Twitter Query IDs if they expire, ensuring the tool keeps working 24/7 without manual intervention.
1919-* **Threads & Replies:**
2020- * **Perfect Threading:** If you write a thread (reply to yourself) on Twitter, it appears as a threaded conversation on Bluesky.
2121- * **Clean Feed:** Automatically filters out your replies to *other* people, keeping your Bluesky timeline focused on your original content.
2222- * **Quotes:** Smartly handles Quote Tweets, embedding the quoted post if available.
2323-* **History Import:**
2424- * Backfill your entire tweet history chronologically (Oldest → Newest).
2525- * Preserves original timestamps on posts.
2626- * Uses human-like pacing to avoid rate limits.
2727-* **Safety:**
2828- * Designed to use **Alt Account Cookies**. You can use a burner account to fetch tweets, protecting your main account from suspension risks.
1717+## 🚀 Quick Start (For Everyone)
29183030-## Setup
3131-3232-### 1. Installation
1919+### 1. Prerequisites
2020+- **Node.js** installed on your computer.
2121+- A Twitter account (preferably an alt/burner for the web cookies).
2222+- A Bluesky account and an **App Password** (Settings -> Privacy & Security -> App Passwords).
33232424+### 2. Installation
2525+Open your terminal and run:
3426```bash
3527git clone https://github.com/j4ckxyz/tweets-2-bsky.git
3628cd tweets-2-bsky
3729npm install
3830```
39314040-### 2. Configuration (`.env`)
3232+### 3. Setup (Using the CLI)
3333+Instead of editing files, use our simple setup command:
3434+```bash
3535+# 1. Set your Twitter cookies (one set of cookies works for all mappings)
3636+npm run cli setup-twitter
41374242-Create a `.env` file in the project folder:
3838+# 2. Add your first account mapping
3939+npm run cli add-mapping
4040+```
4141+*Note: You can find your Twitter `auth_token` and `ct0` in your browser's developer tools under Application -> Cookies.*
43424343+### 4. Run the Sync
4444```bash
4545-# --- Twitter Configuration ---
4646-# 1. Log in to x.com (RECOMMENDED: Use a separate "burner" account!)
4747-# 2. Open Developer Tools (F12) -> Application -> Cookies
4848-# 3. Copy the values for 'auth_token' and 'ct0'
4949-TWITTER_AUTH_TOKEN=d03...
5050-TWITTER_CT0=e1a...
4545+# Build the project
4646+npm run build
51475252-# The username of the account you want to MIRROR (e.g., your main account)
5353-# If left empty, it tries to mirror the account you logged in with (NOT RECOMMENDED).
5454-TWITTER_TARGET_USERNAME=jack
5555-5656-# --- Bluesky Configuration ---
5757-BLUESKY_IDENTIFIER=jack.bsky.social
5858-# Generate an App Password in Bluesky Settings -> Privacy & Security
5959-BLUESKY_PASSWORD=xxxx-xxxx-xxxx-xxxx
6060-6161-# --- Optional ---
6262-CHECK_INTERVAL_MINUTES=5
6363-# BLUESKY_SERVICE_URL=https://bsky.social (Change for custom PDS)
4848+# Start the automatic syncing daemon
4949+npm start
6450```
65516666-**⚠️ Safety Tip:**
6767-Twitter is strict about scraping. **Do not use your main account's cookies.**
6868-1. Create a fresh Twitter account (or use an old alt).
6969-2. Log in with that alt account in your browser.
7070-3. Grab the cookies (`auth_token`, `ct0`) from that alt account.
7171-4. Set `TWITTER_TARGET_USERNAME` to your **main** account's handle (e.g., `elonmusk`).
7272-The tool will use the alt account to "view" your main account's profile and copy the tweets.
5252+---
73537474-### 3. Usage
5454+## 🛠 Advanced Usage
75557676-**Development (with hot reload):**
5656+### Backfilling Old Tweets
5757+If you want to import your historical tweets for a specific account:
7758```bash
7878-npm run dev
5959+# Get the command from the CLI help
6060+npm run cli import-history
6161+6262+# Example: Import the last 10 tweets for a specific user
6363+npm run import -- --username YOUR_TWITTER_HANDLE --limit 10
7964```
80658181-**Production:**
6666+### Testing with Dry Run
6767+See what would be posted without actually posting anything:
8268```bash
8383-npm run build
8484-npm start
6969+npm start -- --dry-run
8570```
86718787-**Import History:**
8888-Migrate your old tweets. This runs once and stops.
7272+### Management Commands
8973```bash
9090-npm run import
7474+npm run cli list # Show all active mappings
7575+npm run cli remove # Remove an account mapping
7676+npm run cli set-interval # Change how often to check for new tweets
9177```
92789393-### 4. Other Commands
9494-9595-| Command | Description |
9696-|---------|-------------|
9797-| `npm run build` | Compile TypeScript to `dist/` |
9898-| `npm run dev` | Run directly with tsx (no build needed) |
9999-| `npm run lint` | Run Biome linter with auto-fix |
100100-| `npm run format` | Format code with Biome |
101101-| `npm run typecheck` | Type-check without emitting |
7979+---
10280103103-## Running on a Server (VPS)
8181+## 📝 Configuration Details
10482105105-To keep this running 24/7 on a Linux server (e.g., Ubuntu):
8383+- **Check Interval**: Default is 5 minutes.
8484+- **Database**: Processed tweets are tracked per-account in the `processed/` folder so you never get duplicates.
8585+- **Service URL**: If you use a custom Bluesky host (like `bsky.network`), you can set it during the `add-mapping` process.
10686107107-1. **Build the project:**
108108- ```bash
109109- npm run build
110110- ```
111111-2. **Install PM2 (Process Manager):**
112112- ```bash
113113- sudo npm install -g pm2
114114- ```
115115-3. **Start the tool:**
116116- ```bash
117117- pm2 start dist/index.js --name "twitter-mirror"
118118- ```
119119-4. **Check logs:**
120120- ```bash
121121- pm2 logs twitter-mirror
122122- ```
123123-5. **Enable startup on reboot:**
124124- ```bash
125125- pm2 startup
126126- pm2 save
127127- ```
8787+## ⚖️ License
8888+MIT
12889129129-## Tech Stack
130130-131131-- **TypeScript** – Full type safety
132132-- **Biome** – Fast linting & formatting
133133-- **tsx** – TypeScript execution for development
9090+---
9191+*Created with ❤️ for the decentralized web.*