Opal
opal Twitter & Mastodon → Bluesky
web v0.1.0 -- cli v0.1.0
Back

About Opal

Opal converts your microblog posts from Twitter, Mastodon, Threads, and Nostr to Bluesky while preserving original timestamps.

How it works

  1. 1
    Choose a platform

    Pick Twitter, Mastodon, Threads, or Nostr.

  2. 2
    Authenticate

    Sign in with your AT Protocol identity via OAuth. Nothing is stored.

  3. 3
    Upload your export

    Drop in your archive file — everything is processed locally in your browser.

  4. 4
    Import

    Opal publishes your posts to your PDS with automatic rate-limit handling.

Privacy & data

No tracking
No accounts
No server storage

Opal runs entirely in your browser. Your export files are parsed locally — they are never uploaded to any server run by this project.

The only network requests made are:

  • Your PDS — Opal authenticates directly with your Personal Data Server and publishes records there on your behalf, exactly as any other ATProto client would. If you sign in via OAuth, Opal also creates a record in your repository using the click.croft.toolkit.use lexicon each time you perform an import. This record contains the number of posts imported and a timestamp, helping you track your activity across the croft.click suite.
  • Google Fonts — the layout loads Inter and JetBrains Mono via Google Fonts. If you prefer not to make this request, you can self-host the fonts or use a content-blocking extension.

No cookies, no local storage, no fingerprinting.

Supported platforms

Twitter / X

Import your tweet archive from Twitter's data export file. Supports tweets, retweets, and quote tweets with facets.

Mastodon

Convert your ActivityPub outbox or CSV export from any Mastodon instance. Handles content warnings, media attachments, and poll metadata.

Threads

Bring over your Threads posts from Meta's data export. Supports text posts and media attachments.

Nostr

Convert your Nostr text notes (kind 1 events) to Bluesky posts.

What's converted

  • Posts with original timestamps
  • Links, mentions, and hashtags as facets
  • Media attachments (images)
  • Reply threads (where resolvable)
  • Content warnings (Mastodon)

Not converted: Videos, polls, DMs, bookmarks, and circle-only posts.

OAuth scope

Opal requests minimal permissions to publish posts:

atproto repo:app.bsky.feed.post repo:click.croft.toolkit.use

This allows reading your profile, writing posts to your repository, and logging tool usage. Your Bluesky profile is read directly from your PDS.

CLI / Local usage

Opal also ships as a Node.js command-line tool. This is useful if you prefer to run imports locally, need full control over batch settings, or want to automate things with scripts.

Prerequisites

  • Node.js v18 or later
  • pnpm (recommended) — or npm / yarn

Install & build

# Clone the repository
git clone https://github.com/ewanc26/pkgs.git
cd pkgs/packages/opal

# Install dependencies
pnpm install

# Build
pnpm build

Usage

# Interactive mode
pnpm start

# Import from Twitter archive
pnpm start -i tweets.js -h alice.bsky.social -p xxxx-xxxx-xxxx-xxxx -y

# Import from Mastodon outbox
pnpm start -i outbox.json -m mastodon -h alice.bsky.social -p xxxx-xxxx-xxxx-xxxx -y

# Sync (skip already-imported records)
pnpm start -i tweets.js -m sync -h alice.bsky.social -p xxxx-xxxx-xxxx-xxxx -y

# Preview without publishing
pnpm start -i tweets.js --dry-run

Key flags

FlagDescription
-i <path>Input file or directory
-h <handle>ATProto handle or DID
-p <password>App password (not your main password)
-m <mode>twitter · mastodon · threads · nostr · sync
-ySkip confirmation prompts
--dry-runPreview without writing records
-vVerbose / debug output
-qQuiet mode (warnings & errors only)

Full documentation is available at docs.ewancroft.uk/projects/opal.

Rate limits & PDS safety

ATProto PDS instances enforce rate limits on write operations. Exceeding them can temporarily affect all users on a shared PDS. Opal protects against this by:

  • Reading the ratelimit-* headers from each response
  • Maintaining a 15% headroom buffer before the quota ceiling
  • Automatically adjusting batch size (up to 200 records) in real time
  • Pausing immediately when the abort signal fires if you press Cancel

Licence

Opal is free software released under the GNU Affero General Public License v3.0 (AGPL-3.0-only).

In short: you are free to use, modify, and redistribute this software, but any modified version you run as a network service must also be released under the same licence with its source code made available.

The full licence text is included in the repository.

Credits

Created by

Ewan Croft Author & maintainer

Contributors

Contributions via GitHub are always welcome. The full contributor list is maintained there.

Dependencies