Transfer posts from Mastodon to Bluesky
Project description
Mastodon to Bluesky Transfer Tool
A command-line tool to transfer your posts from Mastodon to Bluesky, preserving media attachments, thread structure, and rich text formatting.
Why This Tool?
As social media platforms evolve, many users find themselves wanting to establish a presence on multiple platforms. This tool helps you migrate your Mastodon content to Bluesky while preserving as much of the original formatting and context as possible. Whether you're cross-posting, migrating, or just backing up your content, this tool automates what would otherwise be a tedious manual process.
Features
- Transfer posts from Mastodon to Bluesky
- Preserve media attachments (up to 4 images per post)
- Convert long posts into proper threads
- Parse and preserve mentions, hashtags, and links
- Handle content warnings
- Incremental transfers (remembers what's been transferred)
- Dry-run mode for testing
- Filter by date range, replies, and boosts
- Interactive mode for selective transfers
- Configuration file and environment variable support
- Automatic retry with exponential backoff
Requirements
- Python 3.11 or higher
- A Mastodon account with an access token
- A Bluesky account with an app password
Installation
Using uv tool (recommended for regular use)
# Install the tool globally
uv tool install mastodon-to-bluesky
# Now use it directly
mastodon-to-bluesky transfer --help
# Update to latest version
uv tool upgrade mastodon-to-bluesky
# Uninstall
uv tool uninstall mastodon-to-bluesky
Using uvx (for one-time use)
# Run without installing
uvx mastodon-to-bluesky transfer --help
# Or use with environment variables set
uvx mastodon-to-bluesky transfer --limit 10
# Run a specific version
uvx mastodon-to-bluesky@1.0.0 transfer --help
Using pip
pip install mastodon-to-bluesky
From source
git clone https://github.com/jonatkinson/mastodon-to-bluesky.git
cd mastodon-to-bluesky
uv pip install -e .
Quick Start
-
Get your Mastodon access token:
- Go to your Mastodon instance settings
- Navigate to Development > New Application
- Give it a name and grant read permissions
- Copy the access token
-
Get your Bluesky app password:
- Go to Settings > App Passwords in Bluesky
- Create a new app password
- Copy the generated password
-
Run the transfer:
uvx mastodon-to-bluesky transfer \
--mastodon-instance https://mastodon.social \
--mastodon-token YOUR_MASTODON_TOKEN \
--bluesky-handle you.bsky.social \
--bluesky-password YOUR_APP_PASSWORD
Configuration
Configuration File
Create ~/.config/mastodon-to-bluesky/config.json:
{
"mastodon_instance": "https://mastodon.social",
"mastodon_token": "your-mastodon-token",
"bluesky_handle": "you.bsky.social",
"bluesky_password": "your-app-password"
}
Environment Variables
export MASTODON_INSTANCE="https://mastodon.social"
export MASTODON_TOKEN="your-mastodon-token"
export BLUESKY_HANDLE="you.bsky.social"
export BLUESKY_PASSWORD="your-app-password"
Usage Examples
Test Connections
Test your Mastodon connection:
uvx mastodon-to-bluesky test-mastodon --limit 5
Test your Bluesky connection:
uvx mastodon-to-bluesky test-bluesky
Transfer Options
Dry run (preview what would be posted):
uvx mastodon-to-bluesky transfer --dry-run --limit 10
Transfer posts from a specific date range:
uvx mastodon-to-bluesky transfer \
--since 2024-01-01 \
--until 2024-12-31
Include replies and boosts:
uvx mastodon-to-bluesky transfer \
--include-replies \
--include-boosts
Interactive mode (select posts one by one):
uvx mastodon-to-bluesky transfer --interactive --limit 20
Retry failed posts:
uvx mastodon-to-bluesky retry-failed
How It Works
- Fetches posts from your Mastodon account via the API
- Converts content from HTML to plain text while preserving formatting
- Downloads media attachments (images only, up to 4 per post)
- Splits long posts into threads (Bluesky has a 300-character limit)
- Parses rich text to create proper mentions, hashtags, and links
- Creates posts on Bluesky with proper threading
- Tracks progress to avoid duplicates in future runs
Features in Detail
Media Handling
- Downloads and re-uploads images (JPEG, PNG, GIF, WebP)
- Preserves alt text from Mastodon
- Supports up to 4 images per post (Bluesky limitation)
- Videos and audio files are skipped with a note
Text Processing
- Converts HTML to plain text
- Preserves paragraph breaks
- Handles mentions (@user.bsky.social format)
- Preserves hashtags and links
- Content warnings become "CW: [warning]" prefix
Thread Creation
- Posts over 300 characters are split into threads
- Each part is numbered (e.g., "[1/3]", "[2/3]", "[3/3]")
- Smart splitting at sentence boundaries
- Maintains readability at split points
State Management
- Tracks transferred post IDs in
.mastodon-to-bluesky-state.json - Stores state in the current directory by default
- Allows incremental transfers
- Prevents duplicate posts
Retry Logic
- Automatic retry for failed posts with exponential backoff
- Categorizes errors (rate limit, network, API errors)
- Configurable retry attempts (default: 3)
- Manual retry command for persistent failures
Limitations
- Post timestamps: Bluesky doesn't support backdating posts. All transferred posts will have the current date/time. The original Mastodon timestamp is appended to each post as "[Originally posted: YYYY-MM-DD HH:MM UTC]"
- Media types: Only supports image media (no video/audio yet)
- Polls: Not supported (Bluesky doesn't have polls)
- Formatting: Some rich text formatting may be simplified
- Quote posts: Converted to regular posts with links
- Post visibility: All posts are public on Bluesky (no granular privacy controls)
Troubleshooting
"Rate limit exceeded"
The tool handles rate limits automatically by waiting. If you see repeated rate limit errors, wait a few minutes before retrying.
"Authentication failed"
- For Mastodon: Check your access token has read permissions
- For Bluesky: Make sure you're using an app password, not your main password
"Failed to parse mention"
Some Mastodon mentions may not have corresponding Bluesky accounts. These are left as plain text.
Media upload failures
- Check file size (Bluesky has limits)
- Ensure the media URL is still accessible
- Try running with fewer posts at a time
"Invalid datetime format" errors
- This is usually due to timezone handling
- The tool now converts all timestamps to current time due to Bluesky limitations
- Original timestamps are preserved in the post text
Development
Setup
# Clone the repository
git clone https://github.com/jonatkinson/mastodon-to-bluesky.git
cd mastodon-to-bluesky
# Install dependencies
uv sync
# Run tests
uv run pytest
# Run with local changes
uv run mastodon-to-bluesky --help
Project Structure
mastodon-to-bluesky/
├── src/mastodon_to_bluesky/
│ ├── __init__.py
│ ├── cli.py # Command-line interface
│ ├── mastodon.py # Mastodon API client
│ ├── bluesky.py # Bluesky API client
│ ├── models.py # Data models
│ └── transfer.py # Transfer logic
├── tests/ # Test files
├── pyproject.toml # Project configuration
└── README.md # This file
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
See CHANGELOG.md for a list of changes in each version.
Acknowledgments
- Thanks to the Mastodon and Bluesky communities
- Built with atproto for Bluesky integration
- Uses BeautifulSoup for HTML parsing
- CLI powered by Click and Rich
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mastodon_to_bluesky-1.0.0.tar.gz.
File metadata
- Download URL: mastodon_to_bluesky-1.0.0.tar.gz
- Upload date:
- Size: 58.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2b58928d61e97106dfd26d916a71a7e9bb2780b1ec299ca2f474f5e0afa86a0e
|
|
| MD5 |
22b855e7867161c45331568e45dc871b
|
|
| BLAKE2b-256 |
1249b73603cd5e1381f2ce925e5430fb332fcaca3672f04da469a6eb98516326
|
Provenance
The following attestation bundles were made for mastodon_to_bluesky-1.0.0.tar.gz:
Publisher:
publish.yml on jonatkinson/mastodon-to-bluesky
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mastodon_to_bluesky-1.0.0.tar.gz -
Subject digest:
2b58928d61e97106dfd26d916a71a7e9bb2780b1ec299ca2f474f5e0afa86a0e - Sigstore transparency entry: 238197436
- Sigstore integration time:
-
Permalink:
jonatkinson/mastodon-to-bluesky@fbfbf0e6ea086bcb6765566a915388edf6c93ebd -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/jonatkinson
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fbfbf0e6ea086bcb6765566a915388edf6c93ebd -
Trigger Event:
push
-
Statement type:
File details
Details for the file mastodon_to_bluesky-1.0.0-py3-none-any.whl.
File metadata
- Download URL: mastodon_to_bluesky-1.0.0-py3-none-any.whl
- Upload date:
- Size: 22.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
901dec4a17a86f172c7dd7d7c46b5eabf8980be86f53da5153bea6240edd98f7
|
|
| MD5 |
e772f3603c06e18d3c36400c1f51c0df
|
|
| BLAKE2b-256 |
812e400c114323583cbc8d053c36f51e2eba0a0533f4b4889e3dd0434900148e
|
Provenance
The following attestation bundles were made for mastodon_to_bluesky-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on jonatkinson/mastodon-to-bluesky
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mastodon_to_bluesky-1.0.0-py3-none-any.whl -
Subject digest:
901dec4a17a86f172c7dd7d7c46b5eabf8980be86f53da5153bea6240edd98f7 - Sigstore transparency entry: 238197439
- Sigstore integration time:
-
Permalink:
jonatkinson/mastodon-to-bluesky@fbfbf0e6ea086bcb6765566a915388edf6c93ebd -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/jonatkinson
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fbfbf0e6ea086bcb6765566a915388edf6c93ebd -
Trigger Event:
push
-
Statement type: