gobird is a Twitter/X CLI tool and Go client library.
This project uses X/Twitter's unofficial private web APIs. It is intended for personal, research, and automation use, and upstream changes can break behavior without notice.
This is an unofficial tool. It is not affiliated with, endorsed by, or connected to X Corp (formerly Twitter, Inc.) in any way.
gobird uses reverse-engineered, undocumented private APIs that are not intended for third-party use. Using this tool violates the X/Twitter Terms of Service. By using gobird, you acknowledge and accept the following risks:
- Account suspension or permanent ban. X Corp may suspend or terminate your account at any time for using unofficial API clients.
- Liquidated damages. The X Terms of Service include a liquidated damages clause of $15,000 per million posts accessed through unauthorized means.
- No warranty. This tool is provided as-is with no guarantees of functionality, accuracy, or continued operation. X can change or disable the underlying APIs at any time without notice.
You assume all risk associated with using this tool. The authors and contributors accept no liability for any consequences arising from its use.
gobird is a personal-use CLI tool intended for educational and research purposes only. See DISCLAIMER.md for the full legal text.
- Post tweets and replies with optional media attachments (images, video, GIFs)
- Read single tweets by ID or URL
- Fetch tweet threads and replies
- Search tweets with full-text queries
- Browse the home timeline (algorithmic and chronological)
- Fetch mentions, bookmarks (including bookmark folders), and liked tweets
- List and browse user timelines, followers, and following
- Follow and unfollow accounts
- Fetch owned lists, list memberships, and list timelines
- Browse explore news tabs and trending topics
- Three output modes: colourised human-readable,
--json, and--json-full(with raw API data) - Authentication from CLI flags, environment variables, or browser cookie extraction (Safari, Chrome, Firefox)
- JSON5 config file with environment variable overrides
- Paginated fetching with configurable limits and page caps
- Quoted tweet expansion with configurable depth
- Inspectable query IDs with runtime refresh from the X.com bundle
brew install mudrii/tap/gobirdTo upgrade:
brew upgrade gobirdPrebuilt binaries are published on the GitHub Releases page for supported platforms.
- Download the archive for your platform from
https://github.com/mudrii/gobird/releases - Extract it
- Move
gobirdinto a directory on yourPATH, for example:
tar -xzf gobird_26.05.13_darwin_arm64.tar.gz
install gobird /usr/local/bin/gobird
gobird --versiongo install github.com/mudrii/gobird/cmd/gobird@latestThe binary is installed as gobird.
git clone https://github.com/mudrii/gobird.git
cd gobird
make build
# binary at bin/gobirdgobird works without a config file if you pass credentials with flags, environment variables, or browser extraction. For a persistent setup, create a JSON5 config file at one of these locations:
~/.config/gobird/config.json5./.gobirdrc.json5
Minimal example:
{
authToken: "your-auth-token",
ct0: "your-ct0-token",
defaultBrowser: "safari"
}First-run checks:
gobird --version
gobird check --browser safari
gobird whoamiFor all config keys and browser-specific options, see docs/configuration.md.
If you installed with release binaries, download the new archive for the next release, replace the existing gobird binary, and run:
gobird --versionIf you installed with go install, update with:
go install github.com/mudrii/gobird/cmd/gobird@latest
gobird --versionIf you built from source, update by pulling the latest changes and rebuilding:
git pull --ff-only
make build
./bin/gobird --versiongobird needs two Twitter/X session cookies: auth_token (40 hex characters) and ct0 (32–160 alphanumeric characters). Credentials are resolved in this priority order:
gobird --auth-token <token> --ct0 <ct0> whoamiexport AUTH_TOKEN=abc123... # or TWITTER_AUTH_TOKEN
export CT0=xyz789... # or TWITTER_CT0
gobird whoamigobird can extract cookies directly from a logged-in browser with no manual copy-paste:
# Use the default order: Safari → Chrome → Firefox
gobird whoami
# Pin to a specific browser
gobird --browser chrome whoami
gobird --browser firefox --firefox-profile default-release whoami
gobird --browser safari whoami
# Specify multiple sources with explicit order
gobird --cookie-source chrome --cookie-source safari whoamiSupported browsers: Safari (macOS), Chrome / Chromium, Firefox.
To find your cookies manually: open x.com, open DevTools → Application → Cookies → x.com. Copy the values for auth_token and ct0.
$ gobird read 1867654321098765432
@golang (The Go Programming Language) [Mon Dec 16 14:22:01 +0000 2024]
Download the latest Go release at https://go.dev/dl
replies:142 retweets:893 likes:4201$ gobird tweet "Hello from gobird!"
1867700000000000001$ gobird reply 1867654321098765432 "Great news!"
1867700000000000002$ gobird search "golang generics" -n 5
@GopherAcademy (Gopher Academy) [Tue Dec 17 09:11:22 +0000 2024]
Generics in modern Go: what changed and what didn't
replies:8 retweets:37 likes:204
---
@go_trending (Go Trending) [Tue Dec 17 08:55:01 +0000 2024]
Five patterns for type-safe collections using generics
replies:3 retweets:21 likes:98
---$ gobird home -n 10
$ gobird home --latest -n 20 # chronological (Following tab)$ gobird mentions -n 20$ gobird bookmarks -n 50
$ gobird bookmarks --folder 1234567890123456789$ gobird user-tweets @golang -n 20$ gobird thread 1867654321098765432
$ gobird thread 1867654321098765432 --filter full$ gobird whoami
ID: 783214
Username: @Twitter
Name: Twitter$ gobird follow @golang
followed golang
$ gobird unfollow 13334762
unfollowed 13334762$ gobird trending
$ gobird news --tabs forYou,news$ gobird read 1867654321098765432 --json
{
"id": "1867654321098765432",
"text": "Download the latest Go release at https://go.dev/dl",
"author": { "username": "golang", "name": "The Go Programming Language" },
"likeCount": 4201
}
# Include raw API response
$ gobird search "golang" --json-full | jq '.[0]._raw'package main
import (
"context"
"fmt"
"log"
"github.com/mudrii/gobird/pkg/bird"
)
func main() {
ctx := context.Background()
// Option A: resolve credentials automatically (browser / env / flags)
creds, err := bird.ResolveCredentials(bird.ResolveOptions{})
if err != nil {
log.Fatal(err)
}
client, err := bird.New(creds, nil)
if err != nil {
log.Fatal(err)
}
// Option B: supply tokens directly
// client, err := bird.NewWithTokens("your_auth_token", "your_ct0", nil)
// Search (returns a single page; use GetAllSearchResults for pagination)
page := client.Search(ctx, "golang", &bird.SearchOptions{
Product: "Latest",
FetchOptions: bird.FetchOptions{Limit: 10},
})
if page.Error != nil {
log.Fatal(page.Error)
}
for _, t := range page.Items {
fmt.Printf("@%s: %s\n", t.Author.Username, t.Text)
}
// Fetch a single tweet
tweet, err := client.GetTweet(ctx, "1867654321098765432", nil)
if err != nil {
log.Fatal(err)
}
fmt.Printf("@%s (%d likes): %s\n", tweet.Author.Username, tweet.LikeCount, tweet.Text)
// Post a tweet
id, err := client.Tweet(ctx, "Hello from gobird!")
if err != nil {
log.Fatal(err)
}
fmt.Println("posted:", id)
}Some read methods return a result struct instead of (T, error). Check result.Error and result.Success:
result := client.GetHomeTimeline(ctx, &bird.FetchOptions{Limit: 20})
if result.Error != nil {
log.Fatal(result.Error)
}
for _, t := range result.Items {
fmt.Println(t.Text)
}Methods that follow this pattern: Search, GetAllSearchResults, GetHomeTimeline, GetHomeLatestTimeline, GetBookmarks, GetBookmarkFolderTimeline, GetLikes.
Config is loaded from the following locations:
- When
$BIRD_CONFIGor--configis set: only that file is loaded (replaces default search) - Otherwise, in order (later entries override earlier ones):
~/.config/gobird/config.json5— global./.gobirdrc.json5— project-local
Config files use JSON5 syntax (comments and trailing commas are allowed).
// ~/.config/gobird/config.json5
{
// Credentials (prefer env vars instead of storing tokens in a file)
"authToken": "",
"ct0": "",
// Default browser for cookie extraction: "safari", "chrome", or "firefox"
"defaultBrowser": "chrome",
// Chrome profile name (optional)
"chromeProfile": "Default",
// HTTP request timeout in milliseconds (0 = no timeout)
"timeoutMs": 10000,
// Cookie extraction timeout in milliseconds (0 = no timeout)
"cookieTimeoutMs": 5000,
// Quoted tweet expansion depth (default: 1)
"quoteDepth": 1,
}All config fields can also be set via environment variables (see table below). Environment variables take precedence over file values.
| Command | Description |
|---|---|
tweet <text> |
Post a new tweet |
reply <id-or-url> <text> |
Reply to a tweet |
read <id-or-url> |
Read a single tweet |
replies <id-or-url> |
Fetch replies to a tweet |
thread <id-or-url> |
Fetch a full tweet thread |
search <query> |
Search tweets |
mentions |
Fetch mentions of the authenticated user |
home |
Fetch home timeline (algorithmic) |
bookmarks |
Fetch bookmarks |
unbookmark <id-or-url> |
Remove a tweet from bookmarks |
likes |
Fetch liked tweets |
following |
List accounts the user follows |
followers |
List accounts following the user |
follow <@handle-or-id> |
Follow a user |
unfollow <@handle-or-id> |
Unfollow a user |
user-tweets <@handle> |
Fetch a user's tweet timeline |
lists |
List owned lists (or memberships with --memberships) |
list-timeline <id-or-url> |
Fetch tweets from a list |
news |
Fetch explore news tabs |
trending |
Fetch trending topics |
whoami |
Print the authenticated user |
about <@handle> |
Show account info for a user |
check |
Verify credentials are valid |
query-ids |
Show active GraphQL query IDs |
version |
Print version information |
Pass a tweet ID or URL to gobird without a subcommand to read that tweet directly:
gobird 1867654321098765432All commands accept mutually exclusive output flags:
| Flag | Output |
|---|---|
| (none) | Human-readable, ANSI-coloured |
--plain |
Human-readable, no colour, no emoji |
--json |
Normalised JSON array / object |
--json-full |
Normalised JSON with _raw field containing the raw API response |
Use --no-color to disable ANSI colour while keeping emoji. Use --no-emoji to disable emoji while keeping colour.
gobird includes flags for safer operation:
| Flag | Default | Description |
|---|---|---|
--dry-run |
false |
Preview write operations (tweet, reply, follow, unfollow, unbookmark) without making API calls. The command prints what it would do and exits. |
--rate-limit |
1.0 |
Maximum requests per second. Throttles paginated fetches to avoid triggering X's rate limits. Set to 0 to disable throttling. |
--quiet / -q |
false |
Suppress the startup ToS warning printed to stderr. |
Examples:
# Preview a tweet without posting
gobird tweet "Hello" --dry-run
# Fetch home timeline at 0.5 requests/second
gobird home -n 100 --rate-limit 0.5
# Suppress the startup warning in scripts
gobird whoami --quiet| Variable | Description |
|---|---|
AUTH_TOKEN |
Twitter auth_token cookie (preferred) |
TWITTER_AUTH_TOKEN |
Twitter auth_token cookie (alias) |
CT0 |
Twitter ct0 cookie (preferred) |
TWITTER_CT0 |
Twitter ct0 cookie (alias) |
CHROME_SAFE_STORAGE_PASSWORD |
Optional macOS Chrome keychain password override for browser cookie decryption when Keychain subprocess access is denied |
BIRD_CONFIG |
Explicit path to config file |
BIRD_TIMEOUT_MS |
HTTP request timeout in milliseconds |
BIRD_COOKIE_TIMEOUT_MS |
Browser cookie extraction timeout in milliseconds |
BIRD_QUOTE_DEPTH |
Quoted tweet expansion depth |
- Go 1.26 or later (module currently declares
go 1.26.0and prefers toolchaingo1.26.2) - macOS or Linux
- For browser cookie extraction: Safari, Chrome / Chromium, or Firefox must be installed and logged in to x.com
# Build the binary to bin/gobird
make build
# Run all tests
make test
# Run tests with race detector
make test-race
# Run fmt-check, vet, tests, race-detector, lint, and build (mirrors CI)
make ci
# Run linter (requires golangci-lint)
make lint
# Format source
make fmt
# Generate coverage report (coverage.html)
make coverage
# Remove build artefacts
make cleanInstall golangci-lint:
brew install golangci-lint # macOS
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latestMIT. See LICENSE.
docs/— architecture notes, API correction log, development guide, and agent contextpkg/bird/— public Go library (importable by other projects)internal/client/constants.go— query ID maps and API base URLs