Skip to main content

x-migrate

PyPI version CI Python 3.11+ License: MIT

Migrate X (Twitter) lists and follows between accounts.

Extract members from any X list or following page, then follow them or add them to a list on your destination account — with automatic rate-limit recovery, progress tracking, and a Rich TUI.

Requirements

  • Python 3.11+
  • Google Chrome installed

Installation

pip install x-migrate
playwright install chromium
Install from source
git clone https://github.com/tongliuTL/x-migrate
cd x-migrate
pip install -e .
playwright install chromium

Quick Start

Tip: All commands support the short alias xm — use it instead of x-migrate to save typing.

1. Run setup wizard (first time only)

xm setup

Creates ~/.x-migrate/config.toml with your source and destination Chrome profile paths and daily follow limit.

2. Extract members from an X list

xm extract --source list --url "https://x.com/i/lists/YOUR_LIST_ID"

The /members suffix is added automatically if omitted.

Or extract from someone's following list:

xm extract --source following --account "@handle"

3. Follow those members from your destination account

# Follow up to 20 members (default) with an interactive login prompt:
xm follow

# Increase the daily cap:
xm follow --limit 50

# Unattended mode — skips login prompts (requires a saved browser session):
xm follow --auto

# Auto-resume after a rate-limit hit, fully unattended:
xm follow --auto --backoff 2h

# Walk away and let it finish overnight:
xm follow --auto --limit 400 --backoff 3h

# Preview who would be followed without opening a browser:
xm follow --dry-run

4. Add to a list instead of following

xm list-add --list-name "My List Name"

5. Check progress

xm report

Shows migration progress from local data (no browser needed). To cross-check against your live following list:

xm report --verify

Rate Limits

X typically allows ~400 follows per day. x-migrate detects rate limiting automatically and can either stop (default) or sleep and retry:

Behaviour Command
Stop on rate limit, re-run manually next day xm follow
Stop on rate limit, skip login prompt on re-run xm follow --auto
Auto-retry after 2 hours, fully unattended xm follow --auto --backoff 2h

Accepted backoff formats: 2h, 90m, 3600s. Progress is saved after every follow — it is always safe to Ctrl-C mid-run.

The --limit cap is the total for the entire invocation, across all retry sessions.

Configuration

~/.x-migrate/config.toml:

source_profile = "/path/to/source/profile"
dest_profile   = "/path/to/dest/profile"
daily_limit    = 20       # default for --limit when not specified
active_job     = "a1b2c3d4e5f6"   # auto-set by xm extract

Data Storage

All data is stored under ~/.x-migrate/:

Path Contents
config.toml Settings — profiles, daily limit, active job
profile_source/ Chrome profile for source account (saved login session)
profile_dest/ Chrome profile for destination account
progress/ Per-job JSON files tracking follow status per user

Commands

Command Description
xm setup Create or update ~/.x-migrate/config.toml
xm extract Extract members from a list or following page
xm follow Follow extracted members on destination account
xm list-add Add extracted members to a named list
xm report Show local progress; --verify cross-checks live data

All commands also work as x-migrate <command>.

xm follow options

Flag Default Description
--limit N daily_limit from config Maximum follows for this invocation
--auto off Skip login prompts (uses saved browser session)
--backoff DURATION 0 (disabled) Sleep duration after a rate limit before retrying
--dry-run off Print the follow plan without opening a browser

Development

git clone https://github.com/tongliuTL/x-migrate
cd x-migrate
pip install -e ".[dev]"
pytest

See CONTRIBUTING.md for guidelines on submitting changes.

Releasing a new version

  1. Update version in pyproject.toml
  2. Add a ## [X.Y.Z] — YYYY-MM-DD section to CHANGELOG.md
  3. Commit and tag:
    git commit -m "chore: bump version and changelog (vX.Y.Z)"
    git tag vX.Y.Z
    git push && git push --tags
    
  4. GitHub Actions runs tests, builds the wheel, publishes a GitHub Release, and pushes to PyPI automatically.

Pre-releases (e.g. v0.2.0-beta.1) are automatically marked as pre-release on GitHub.

Contributing

Bug reports, feature requests, and pull requests are welcome — see CONTRIBUTING.md.

License

MIT

Metadata

Release files for x-migrate 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for x-migrate 0.2.0
File Size Uploaded
x_migrate-0.2.0.tar.gz 34.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for x-migrate 0.2.0
File Interpreter ABI Platform
x_migrate-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 54.8 kB

Release files / x_migrate-0.2.0.tar.gz

Download URL x_migrate-0.2.0.tar.gz
Size 34.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e474d7f4708cacbaabe2784aec7511813f870082ab8be3c0c55946a4ba00f40c
BLAKE2b-256 checksum
How to use checksums
ff6192deb4140bd57b716b6bf55a3910de0fe7479c6d63185d4f40f6ce52fb2a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 3, 2026.

Transparency log

Release files / x_migrate-0.2.0-py3-none-any.whl

Download URL x_migrate-0.2.0-py3-none-any.whl
Size 20.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3eb33ab02f529e7d6ec37ca3fa96e8a9c92296ee3a91e2a5c364624b3a0ec7ae
BLAKE2b-256 checksum
How to use checksums
651fcb7863c015c5e87b9d9e22f9ec37b2821c2231b9c4d1d77e4ae7838b07b4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 3, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page