bsky crosspost watches a Bluesky account and re-publishes each new post (text and media) to your other social platforms. It runs as a lightweight polling loop with per-platform adapters, so you can enable only the targets you need.
| Platform | Role | Library | Auth |
|---|---|---|---|
| 🦋 Bluesky | Source | atproto |
App password |
| ✖️ X (Twitter) | Target | twikit |
Cookies (recommended) or login |
| Target | instagrapi |
Session / login |
- Multi-target fan-out — one Bluesky post → many platforms in a single pass.
- Media-aware — downloads and re-uploads images attached to the source post.
- Resilient state — tracks the last processed post; only advances state when a target succeeds, so nothing is silently dropped.
- Drop-in adapters — each platform is isolated behind a common interface; missing credentials simply skip that target.
- Cookie-based X auth — sidesteps X's Cloudflare-protected login (essential on VPS/datacenter IPs).
git clone https://github.com/eqyv/bsky.git
cd bsky
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txtCopy the example env file and fill in your credentials:
cp .env.example .env| Variable | Required | Description |
|---|---|---|
BSKY_HANDLE |
✅ | Your Bluesky handle (name.bsky.social) |
BSKY_APP_PASSWORD |
✅ | Bluesky app password (not your login password) |
X_AUTH_TOKEN / X_CT0 |
Browser-exported X cookies — preferred auth | |
X_USERNAME / X_EMAIL / X_PASSWORD |
X login fallback (blocked on datacenter IPs) | |
X_TOTP_SECRET |
⬜ | X 2FA base32 secret, if enabled |
IG_USERNAME / IG_PASSWORD |
Instagram credentials | |
POLL_INTERVAL_SECONDS |
⬜ | How often to check Bluesky (default 180) |
▶️ = required only for that target. Enable any subset of X / Instagram.
Getting your X cookies: log into X in a browser → DevTools → Application → Cookies → https://x.com → copy the auth_token and ct0 values into .env. See TROUBLESHOOTING.md for why this is recommended.
python main.pyOn first run the bot seeds its state with your latest existing post, so only posts created after startup are mirrored. Press Ctrl+C to stop.
bsky/
├── adapters/ # Per-platform source & target adapters
│ ├── bluesky_source.py
│ ├── twitter.py / twitter_patch.py
│ └── instagram.py
├── core/ # Detector, orchestrator, state manager
├── utils/ # Logger, media downloader
├── storage/ # Session cookies & state (gitignored)
├── config.py # Env-backed configuration
└── main.py # Entry point & polling loop
X (Twitter) relies on twikit, an unofficial client that occasionally drifts from X's changing internals. Common errors and their fixes are documented in TROUBLESHOOTING.md.
This project uses unofficial clients for X and Instagram. Automating these platforms may violate their Terms of Service and can put your account at risk. Use responsibly, at your own risk, and prefer dedicated/secondary accounts.
If this project saved you time and you'd like to support, donations are welcome, thank you! 🙏
You can send toncoin or tokens in (only) TON network to this address.
UQA1aKaBehiY-TJzDffLFPaZzHYa6nHxZUAl8MKCrJnlnBx-
