Documentation
¶
Index ¶
- Variables
- func ApplyEnvOverrides()
- func AssignBrowserProfile(acc *Account, idx int)
- func EndpointURL(operation string) (string, error)
- func GenerateCT0() string
- type Account
- func (a *Account) AllowRequest(endpoint string) bool
- func (a *Account) CT0Age() time.Duration
- func (a *Account) Credentials() (authToken, ct0, userAgent string)
- func (a *Account) EndpointAvailableAt(endpoint string) time.Time
- func (a *Account) ID() string
- func (a *Account) IsActive() bool
- func (a *Account) IsEndpointRateLimited(endpoint string) bool
- func (a *Account) MarkEndpointRateLimited(endpoint string, until time.Time)
- func (a *Account) ReactivateAt() time.Time
- func (a *Account) RotateCT0()
- func (a *Account) SetActive(v bool)
- func (a *Account) SetCT0(ct0 string)
- func (a *Account) SetCredentials(authToken, ct0 string)
- func (a *Account) SetReactivateAt(t time.Time)
- func (a *Account) SyncRateLimit(endpoint string, respHdrs map[string]string)
- func (a *Account) UpdateEndpointLimit(endpoint string, limit int)
- type AccountHealth
- type AutoReloginGate
- type AutoReloginGateFunc
- type Client
- func (c *Client) AccountByUsername(username string) *Account
- func (c *Client) CreateTweet(ctx context.Context, acc *Account, text string) (string, error)
- func (c *Client) CreateTweetWithMedia(ctx context.Context, acc *Account, text string, mediaIDs []string) (string, error)
- func (c *Client) GetBookmarks(ctx context.Context, maxCount int) ([]*Tweet, error)
- func (c *Client) GetCommunityTweets(ctx context.Context, communityID string, maxCount int) ([]*Tweet, error)
- func (c *Client) GetDMInbox(ctx context.Context) ([]*DMConversation, error)
- func (c *Client) GetFollowers(ctx context.Context, userID string, maxCount int) ([]*TwitterUser, error)
- func (c *Client) GetFollowing(ctx context.Context, userID string, maxCount int) ([]*TwitterUser, error)
- func (c *Client) GetHomeLatestTimeline(ctx context.Context, count int) ([]*Tweet, error)
- func (c *Client) GetHomeTimeline(ctx context.Context, count int) ([]*Tweet, error)
- func (c *Client) GetListTweets(ctx context.Context, listID string, maxCount int) ([]*Tweet, error)
- func (c *Client) GetRetweeters(ctx context.Context, tweetID string, maxCount int) ([]*TwitterUser, error)
- func (c *Client) GetTweetByID(ctx context.Context, tweetID string) (*Tweet, error)
- func (c *Client) GetUserByScreenName(ctx context.Context, handle string) (*TwitterUser, error)
- func (c *Client) GetUserTweets(ctx context.Context, userID string, count int) ([]*Tweet, error)
- func (c *Client) GetVerifiedFollowers(ctx context.Context, userID string, maxCount int) ([]*TwitterUser, error)
- func (c *Client) HealthReport() []AccountHealth
- func (c *Client) LikeTweet(ctx context.Context, acc *Account, tweetID string) error
- func (c *Client) Pool() *pool.Pool[*Account]
- func (c *Client) PostWithAccount(ctx context.Context, username, text string) (string, error)
- func (c *Client) PostWithMedia(ctx context.Context, username, text string, paths ...string) (string, error)
- func (c *Client) ReplyTweet(ctx context.Context, acc *Account, tweetID, text string) (string, error)
- func (c *Client) Retweet(ctx context.Context, acc *Account, tweetID string) (string, error)
- func (c *Client) SearchTimeline(ctx context.Context, query string, count int) ([]*Tweet, error)
- func (c *Client) SendDM(ctx context.Context, acc *Account, conversationID, text string) (string, error)
- func (c *Client) SetAutoReloginGate(g AutoReloginGate)
- func (c *Client) UnlikeTweet(ctx context.Context, acc *Account, tweetID string) error
- func (c *Client) Unretweet(ctx context.Context, acc *Account, tweetID string) (string, error)
- func (c *Client) UploadMedia(ctx context.Context, acc *Account, data []byte, mediaType string) (string, error)
- func (c *Client) UploadMediaFile(ctx context.Context, acc *Account, path string) (string, error)
- func (c *Client) ValidateAccount(ctx context.Context, acc *Account) error
- type ClientConfig
- type Cursor
- type DMConversation
- type DMMessage
- type Endpoint
- type Tweet
- type TwitterUser
Constants ¶
This section is empty.
Variables ¶
var BearerToken = bearerTokens[0]
BearerToken is the active bearer token (first in list).
var Endpoints = map[string]Endpoint{
"UserByScreenName": {ID: "IGgvgiOx4QZndDHuD3x9TQ", Name: "UserByScreenName", Features: gqlFeatures()},
"UserByRestId": {ID: "VQfQ9wwYdk6j_u2O4vt64Q", Name: "UserByRestId", Features: gqlFeatures()},
"Followers": {ID: "9jsVJ9l2uXUIKslHvJqIhw", Name: "Followers", Features: followersFeatures()},
"Following": {ID: "OLm4oHZBfqWx8jbcEhWoFw", Name: "Following", Features: followersFeatures()},
"UserTweets": {ID: "FOlovQsiHGDls3c0Q_HaSQ", Name: "UserTweets", Features: gqlFeatures()},
"SearchTimeline": {ID: "GcXk9vN_d1jUfHNqLacXQA", Name: "SearchTimeline", Features: gqlFeatures()},
"TweetDetail": {ID: "VWFGPVAGkZMGRKGe3GFFnA", Name: "TweetDetail", Features: gqlFeatures()},
"Retweeters": {ID: "FeoLYPQ-q4bmjGLTZTGs0g", Name: "Retweeters", Features: gqlFeatures()},
"CreateTweet": {ID: "7TKRKCPuAGsmYde0CudbVg", Name: "CreateTweet", Features: gqlFeatures()},
"Bookmarks": {ID: "i8QZ1qqy36ffA3bxfTaf7w", Name: "Bookmarks", Features: gqlFeatures()},
"HomeTimeline": {ID: "HCosKfLNW1AcOo3la3mMgg", Name: "HomeTimeline", Features: gqlFeatures()},
"HomeLatestTimeline": {ID: "zhX91JE87mWvfprhYE97xA", Name: "HomeLatestTimeline", Features: gqlFeatures()},
"ListLatestTweetsTimeline": {ID: "27HKUy8ulrflZ9Tole038g", Name: "ListLatestTweetsTimeline", Features: gqlFeatures()},
"CommunityTweetsTimeline": {ID: "Mvs5UOOEkpXVMDZtUcxR-Q", Name: "CommunityTweetsTimeline", Features: gqlFeatures()},
"BlueVerifiedFollowers": {ID: "OBBd6Dw-4qEYbsu3hGkyxg", Name: "BlueVerifiedFollowers", Features: gqlFeatures()},
"FavoriteTweet": {ID: "lI07N6Otwv1PhnEgXILM7A", Name: "FavoriteTweet", Features: gqlFeatures()},
"UnfavoriteTweet": {ID: "ZYKSe-w7KEslx3JhSIk5LA", Name: "UnfavoriteTweet", Features: gqlFeatures()},
"CreateRetweet": {ID: "mbRO74GrOvSfRcJnlMapnQ", Name: "CreateRetweet", Features: gqlFeatures()},
"DeleteRetweet": {ID: "ZyZigVsNiFO6v1dEks1eWg", Name: "DeleteRetweet", Features: gqlFeatures()},
}
Endpoints maps operation names to their current GraphQL IDs and feature flags.
Functions ¶
func ApplyEnvOverrides ¶
func ApplyEnvOverrides()
ApplyEnvOverrides reads TWITTER_QID_* env vars and overrides queryIds in Endpoints. Called automatically by init(); can also be called manually in tests.
func AssignBrowserProfile ¶
AssignBrowserProfile sets a browser profile based on index.
func EndpointURL ¶
EndpointURL returns the URL for a named operation, or an error if unknown.
func GenerateCT0 ¶
func GenerateCT0() string
GenerateCT0 generates a random 32-byte hex string for use as a ct0 CSRF token.
Types ¶
type Account ¶
type Account struct {
Username string
Password string
AuthToken string
CT0 string
TOTPSecret string
Proxy string
UserAgent string
Profile stealth.BrowserProfile
pool.HealthTracker
// contains filtered or unexported fields
}
Account represents a Twitter account with credentials for the pool.
func ParseAccounts ¶
ParseAccounts parses a comma-separated list of accounts. Format: "user1:pass1,user2:pass2" or "user1:pass1:auth_token:ct0,..." or "user1:pass1:auth_token:ct0:totp_secret,...".
func (*Account) AllowRequest ¶
AllowRequest checks if this account can make a request to the given endpoint.
func (*Account) Credentials ¶
Credentials returns a snapshot of (authToken, ct0, userAgent) under lock.
func (*Account) EndpointAvailableAt ¶
EndpointAvailableAt returns when this account will be available for the given endpoint.
func (*Account) IsEndpointRateLimited ¶
IsEndpointRateLimited returns true if the endpoint is currently blocked.
func (*Account) MarkEndpointRateLimited ¶
MarkEndpointRateLimited marks an endpoint as rate-limited for this account.
func (*Account) ReactivateAt ¶
ReactivateAt implements pool.Identity.
func (*Account) RotateCT0 ¶
func (a *Account) RotateCT0()
RotateCT0 generates a fresh ct0 token and updates the refresh timestamp.
func (*Account) SetCredentials ¶
SetCredentials atomically updates auth_token and ct0.
func (*Account) SetReactivateAt ¶
SetReactivateAt implements pool.Identity.
func (*Account) SyncRateLimit ¶ added in v0.6.6
SyncRateLimit reads the x-rate-limit-limit header from a response and updates this account's per-endpoint cap when the header carries a valid positive value. A no-op when the header is absent or malformed (the prior cap stands). Called on every observed response (200 and 429) so the cap tracks X's real, possibly-shifting per-account budget.
func (*Account) UpdateEndpointLimit ¶ added in v0.6.6
UpdateEndpointLimit sets this account's per-window request cap for the given endpoint, overriding the static default. Driven by the x-rate-limit-limit response header so the limiter self-tunes to X's real per-account-per-endpoint budget. Non-positive limits are ignored by the underlying limiter.
type AccountHealth ¶
AccountHealth describes the health state of a single pool account.
type AutoReloginGate ¶
type AutoReloginGate interface {
Allowed(ctx context.Context, username string) (allowed bool, reason string)
}
AutoReloginGate lets an external controller veto automatic re-login flows. A nil gate is treated as "always allow" — preserves backward compatibility for consumers that don't use go-social.
type AutoReloginGateFunc ¶ added in v0.6.7
AutoReloginGateFunc adapts a plain function to the AutoReloginGate interface.
OPT-OUT: as of v0.6.7 a client that never calls SetAutoReloginGate gets the internal per-account relogin breaker by default (see wireDefaultReloginGate), which stops auto-relogin for an account after reloginBreakerThreshold consecutive failures for reloginBreakerWindow. A consumer that wants the pre-v0.6.7 "always relogin, unlimited" behavior must install an always-allow gate explicitly:
c.SetAutoReloginGate(AutoReloginGateFunc(
func(context.Context, string) (bool, string) { return true, "" }))
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the top-level Twitter scraping client.
func NewClient ¶
func NewClient(cfg ClientConfig) (*Client, error)
NewClient creates a fully-wired Twitter client.
func (*Client) AccountByUsername ¶
AccountByUsername returns the pool account matching the given username (case-insensitive). Returns nil if not found.
func (*Client) CreateTweet ¶
CreateTweet posts a tweet from a specific account. Returns the tweet ID on success.
func (*Client) CreateTweetWithMedia ¶ added in v0.6.0
func (c *Client) CreateTweetWithMedia(ctx context.Context, acc *Account, text string, mediaIDs []string) (string, error)
CreateTweetWithMedia posts a tweet with attached media IDs from a specific account. With no media IDs it is equivalent to CreateTweet. Returns the tweet ID on success.
func (*Client) GetBookmarks ¶ added in v0.6.0
GetBookmarks fetches the authenticated pool account's bookmarked tweets (paginated up to maxCount).
func (*Client) GetCommunityTweets ¶ added in v0.6.0
func (c *Client) GetCommunityTweets(ctx context.Context, communityID string, maxCount int) ([]*Tweet, error)
GetCommunityTweets fetches the latest tweets in a community (paginated up to maxCount).
func (*Client) GetDMInbox ¶ added in v0.6.0
func (c *Client) GetDMInbox(ctx context.Context) ([]*DMConversation, error)
GetDMInbox fetches the authenticated pool account's DM inbox. The inbox is per-account state, so doGET pins a real account from the pool (DMInbox is in requiresAuth — no guest fallback). Returns the conversations, each with its participants and the messages present in the initial inbox state. An empty inbox (0 conversations) is a valid, non-error result.
func (*Client) GetFollowers ¶
func (c *Client) GetFollowers(ctx context.Context, userID string, maxCount int) ([]*TwitterUser, error)
GetFollowers fetches followers for a user (paginated).
func (*Client) GetFollowing ¶
func (c *Client) GetFollowing(ctx context.Context, userID string, maxCount int) ([]*TwitterUser, error)
GetFollowing fetches accounts a user follows (paginated).
func (*Client) GetHomeLatestTimeline ¶ added in v0.6.0
GetHomeLatestTimeline fetches the reverse-chronological "Following" home timeline. POST (pool), mirroring SearchTimeline.
func (*Client) GetHomeTimeline ¶ added in v0.6.0
GetHomeTimeline fetches the algorithmic "For you" home timeline. POST (pool), mirroring SearchTimeline.
func (*Client) GetListTweets ¶ added in v0.6.0
GetListTweets fetches the latest tweets in a list (paginated up to maxCount).
func (*Client) GetRetweeters ¶
func (c *Client) GetRetweeters(ctx context.Context, tweetID string, maxCount int) ([]*TwitterUser, error)
GetRetweeters fetches users who retweeted a tweet (paginated).
func (*Client) GetTweetByID ¶
GetTweetByID fetches a single tweet by its ID.
func (*Client) GetUserByScreenName ¶
GetUserByScreenName fetches a user profile by Twitter handle.
func (*Client) GetUserTweets ¶
GetUserTweets fetches recent tweets for a user.
func (*Client) GetVerifiedFollowers ¶ added in v0.6.0
func (c *Client) GetVerifiedFollowers(ctx context.Context, userID string, maxCount int) ([]*TwitterUser, error)
GetVerifiedFollowers fetches a user's blue-verified followers (paginated up to maxCount). The response shares the followers shape (data.user.result.timeline.timeline), so it reuses the existing fetchUserList helper + parseUserList parser.
func (*Client) HealthReport ¶
func (c *Client) HealthReport() []AccountHealth
HealthReport returns health stats for all accounts in the pool.
func (*Client) LikeTweet ¶ added in v0.6.0
LikeTweet favorites a tweet from a specific account. Returns nil on the "Done" ack, else an error.
func (*Client) PostWithAccount ¶
PostWithAccount posts a tweet from a named account (by username). Returns the tweet ID on success.
func (*Client) PostWithMedia ¶ added in v0.6.0
func (c *Client) PostWithMedia(ctx context.Context, username, text string, paths ...string) (string, error)
PostWithMedia uploads the given files and posts a tweet attaching them, from a named account (by username). Returns the tweet ID on success.
func (*Client) ReplyTweet ¶ added in v0.6.0
func (c *Client) ReplyTweet(ctx context.Context, acc *Account, tweetID, text string) (string, error)
ReplyTweet posts a reply to tweetID from a specific account. Returns the reply tweet ID. It routes through the CreateTweet op (reply.in_reply_to_tweet_id set) and reuses parseCreateTweet for the result.
func (*Client) Retweet ¶ added in v0.6.0
Retweet retweets a tweet from a specific account. Returns the new retweet ID.
func (*Client) SearchTimeline ¶
SearchTimeline searches for tweets matching a query. Uses POST (Twitter migrated this endpoint from GET in March 2026).
func (*Client) SendDM ¶ added in v0.6.0
func (c *Client) SendDM(ctx context.Context, acc *Account, conversationID, text string) (string, error)
SendDM sends a text direct message into an existing conversation from a specific account (account-pinned write, mirroring CreateTweet/engagement mutations). Returns the created message id.
FAIL-CLOSED: a 200 response with no usable message id (empty body, a DM validation failure, or a surfaced API error) returns an error — never a silent "sent". Mirrors parseCreateTweet's empty-result guard. conversationID is a CONVERSATION id (1:1 form "<recipientID>-<selfID>", per twikit), NOT a user id; there is no derive helper — the caller forms it.
func (*Client) SetAutoReloginGate ¶
func (c *Client) SetAutoReloginGate(g AutoReloginGate)
SetAutoReloginGate registers a gate checked before relogin attempts.
func (*Client) UnlikeTweet ¶ added in v0.6.0
UnlikeTweet un-favorites a tweet from a specific account. Returns nil on the "Done" ack, else an error.
func (*Client) Unretweet ¶ added in v0.6.0
Unretweet removes a retweet from a specific account. Returns the source tweet ID. The DeleteRetweet op keys the target by "source_tweet_id" (the ID of the ORIGINAL tweet, not the retweet's own ID) — confirmed live 2026-06-20: sending "tweet_id" yields HTTP 422 GRAPHQL_VALIDATION_FAILED ("source_tweet_id must be defined"). Matches trevorhobenshield/twitter-api-client + dimdenGD/OldTweetDeck.
func (*Client) UploadMedia ¶ added in v0.6.0
func (c *Client) UploadMedia(ctx context.Context, acc *Account, data []byte, mediaType string) (string, error)
UploadMedia uploads raw media bytes via the chunked INIT/APPEND/FINALIZE flow using the given account's authenticated stealth client, and returns the media_id string for use in CreateTweetWithMedia. mediaType is the MIME type (e.g. "image/jpeg", "image/gif", "video/mp4").
func (*Client) UploadMediaFile ¶ added in v0.6.0
UploadMediaFile reads a file from disk, infers its MIME type, and uploads it.
func (*Client) ValidateAccount ¶
ValidateAccount checks that an account's auth_token and ct0 are still valid by calling the authenticated account/settings.json REST endpoint. Returns nil on HTTP 200, an error on 401/403, or a wrapped error on network failure.
type ClientConfig ¶
type ClientConfig struct {
// Accounts is the list of Twitter accounts to use.
Accounts []*Account
// DefaultProxy is the proxy URL for accounts without per-account proxies.
DefaultProxy string
// SessionTTL controls how long saved sessions are considered valid.
SessionTTL time.Duration
// AuthCooldown is the soft-deactivation duration for auth errors.
AuthCooldown time.Duration
// BanCooldown is the soft-deactivation duration for banned/locked accounts.
BanCooldown time.Duration
// NonResponsiveCooldown is the BASE backoff for accounts that trip the
// consecutive-failure threshold against a transiently-broken endpoint. The
// effective cooldown grows per trip (x2, capped at 30m, +/-30% jitter) so a
// flapping upstream self-heals once it recovers instead of latching the pool
// permanently. Default: 5m.
NonResponsiveCooldown time.Duration
// CaptchaSolver is the optional CAPTCHA solver for locked accounts.
CaptchaSolver captcha.Solver
// RateLimit configures per-account per-endpoint rate limiting.
RateLimit ratelimit.Config
// OpenAccountCount is the number of anonymous guest accounts to create at startup.
OpenAccountCount int
// MetricsHook is called on each API request for external metrics collection.
// endpoint is the operation name, success and rateLimited indicate the outcome.
MetricsHook func(endpoint string, success, rateLimited bool)
// SessionDir overrides the default session persistence directory.
// Default: ~/.go-twitter/sessions
SessionDir string
// ProxyBackoffInitial is the initial backoff for proxy failures.
ProxyBackoffInitial time.Duration
// ProxyBackoffMax is the maximum backoff for proxy failures.
ProxyBackoffMax time.Duration
// PoolAlertHook is called when the pool emits alerts (account deactivation, proxy failures, etc.).
// topic is the alert type (e.g. "pool.deactivated"), payload contains details.
PoolAlertHook func(topic string, payload any)
// DisableGuestFallback disables the guest-token fallback path entirely.
// When true, endpoints that would normally fall back to guest mode after
// pool exhaustion will return an error instead. Recommended in production
// where guest tokens from datacenter IPs return persistent 403 errors.
// Default: false (guest fallback enabled for backward compatibility).
DisableGuestFallback bool
// AccountPaceMin is the minimum human-pace delay between consecutive requests
// MADE BY THE SAME ACCOUNT, applied AFTER the pool selects an account and IN
// ADDITION TO the anti-fingerprint jitter. Pacing is keyed by account, not by
// domain: each account self-paces its own request rhythm via an independent
// timestamp, so a low-frequency caller (seed) is never starved by a global
// gate that a high-frequency caller (KOL/VC) holds. It is anti-burst stealth
// spacing UNDER the per-account-per-endpoint rate-limit ceiling, never a
// throughput cap below it.
//
// Together with AccountPaceRandom the realized inter-request spacing for one
// account is [AccountPaceMin, AccountPaceMin+AccountPaceRandom) (variable,
// never below AccountPaceMin). Default: 800ms. Set AccountPaceDisabled to off.
AccountPaceMin time.Duration
// AccountPaceRandom is the random jitter added on top of AccountPaceMin for
// the per-account spacing (see AccountPaceMin). Default: 1.2s.
AccountPaceRandom time.Duration
// AccountPaceDisabled turns off the per-account human pace entirely. When
// true only the anti-fingerprint jitter applies. Default: false (pacing
// enabled with safe defaults).
AccountPaceDisabled bool
}
ClientConfig holds all configuration for the Twitter client.
type DMConversation ¶ added in v0.6.0
DMConversation is a single direct-message conversation from the 1.1 inbox. Participants holds the user IDs in the thread (the inbox shape carries participant IDs, not full user objects). Messages are the messages seen in the inbox_initial_state entries for this conversation.
type DMMessage ¶ added in v0.6.0
type DMMessage struct {
ID string
ConversationID string
SenderID string
Text string
CreatedAt time.Time
}
DMMessage is a single direct message. Fields mirror the 1.1 inbox message_data shape (id, sender_id, text, time as unix millis).
type Tweet ¶
type Tweet struct {
ID string
AuthorID string
AuthorHandle string // @screen_name (from core.user_results)
AuthorName string // display name (from core.user_results)
Text string
CreatedAt time.Time
Views int
Likes int
Retweets int
Quotes int
ReplyCount int
TokenMentions []string // extracted $TICKER patterns, e.g. ["BTC", "ETH"]
}
Tweet represents a single tweet.
func SearchWithSocial ¶
func SearchWithSocial(ctx context.Context, sc *social.Client, query string, limit int) ([]*Tweet, error)
SearchWithSocial acquires accounts from go-social and searches Twitter, retrying with different accounts on failure. go-social rotates accounts on each call, so retries naturally use different credentials.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
gql-sync
command
Command gql-sync auto-extracts Twitter GraphQL queryIDs from x.com's webpack bundles and regenerates queryids_gen.go — the "generated" layer of the endpoints override chain (env > generated > committed).
|
Command gql-sync auto-extracts Twitter GraphQL queryIDs from x.com's webpack bundles and regenerates queryids_gen.go — the "generated" layer of the endpoints override chain (env > generated > committed). |
|
internal
|
|
|
bundle
Package bundle fetches x.com warm pages, reassembles the webpack chunk map (chunkID->name, chunkID->hash), resolves a module name to its abs.twimg.com bundle URL, BFS-follows import() refs, and caches the snapshot to disk with a TTL.
|
Package bundle fetches x.com warm pages, reassembles the webpack chunk map (chunkID->name, chunkID->hash), resolves a module name to its abs.twimg.com bundle URL, BFS-follows import() refs, and caches the snapshot to disk with a TTL. |
|
Package slogsample provides sampling utilities for slog handlers.
|
Package slogsample provides sampling utilities for slog handlers. |
|
Package social provides a thin HTTP client for the go-social account management API.
|
Package social provides a thin HTTP client for the go-social account management API. |