Install
Maven Central publication is pending. Build from source until the
com.x_twitter_scraper.api:x-twitter-scraper-java artifact resolves in Maven Central.Authenticate
XTwitterScraperOkHttpClient.fromEnv() reads X_TWITTER_SCRAPER_API_KEY, X_TWITTER_SCRAPER_BEARER_TOKEN, and X_TWITTER_SCRAPER_BASE_URL.
Basic Example
Search tweets and write durable JSON Lines handoff rows:Workflow: Search Tweets to JSON Lines, CSV, or XLSX
Use this workflow when a Java service, Spring Batch job, scheduled worker, or queue consumer needs tweet search results in a durable handoff file for a data lake, CRM enrichment step, analyst CSV export, XLSX workbook, or downstream processor.client.x().tweets().search calls GET /x/tweets/search. Build TweetSearchParams with the same query parameters the REST API accepts: .q(), .limit(), .cursor(), .sinceTime(), .untilTime(), and .queryType().
Request Mapping
.q()
Java builder method
.q() maps to REST q. Use it for an X search query such as from:username, a keyword, hashtag, or boolean operator query..limit()
Java builder method
.limit() maps to REST limit. Use it as a 1 to 200 upper bound for a bounded pull. If page.hasNextPage() is true, keep the same .q(), filters, .queryType(), and .limit() when you continue with page.nextCursor()..cursor()
Java builder method
.cursor() maps to REST cursor. Pass the opaque cursor from page.nextCursor() to request the next page..sinceTime()
Java builder method
.sinceTime() maps to REST sinceTime. Use it as the ISO 8601 lower bound for tweet creation time..untilTime()
Java builder method
.untilTime() maps to REST untilTime. Use it as the ISO 8601 upper bound for tweet creation time..queryType()
Java builder method
.queryType() maps to REST queryType. Use QueryType.LATEST for chronological search or QueryType.TOP for engagement-ranked search.Returned Data & Handoff
client.x().tweets().search returns PaginatedTweets. Use page.tweets() for the tweet list, page.hasNextPage() to decide whether another page exists, and page.nextCursor() as the checkpoint for the next request. For bounded pulls that return fewer tweets than the requested .limit(), pass page.nextCursor() back as .cursor() with the same query, filters, QueryType, and .limit().
Each SearchTweet includes generated accessors such as id(), text(), author(), createdAt(), likeCount(), replyCount(), retweetCount(), quoteCount(), viewCount(), bookmarkCount(), and isNoteTweet() when available. Project page.tweets() into JSON Lines and CSV rows with tweet_id, author_username, engagement counts, page_index, page_cursor, next_cursor, and has_next_page so workers can resume safely or load the same records into XLSX, CRM, warehouse, or agent workflows.
Tweet search costs 1 credit per tweet returned. If remaining credits cannot cover a bounded .limit() request, the API can return fewer tweets; if 0 paid results are affordable, it returns 402 insufficient_credits. The SDK supports withOptions() for retry and request settings. For explicit .limit() pulls, resume with the same query, filters, QueryType, and .limit(); only .cursor() changes.
Workflow: Follower Export to CSV, JSON, or XLSX
Use this workflow when a JVM worker needs an owned follower list for CRM import, warehouse loading, account scoring, analyst CSV, XLSX workbook delivery, or a resumable JSON handoff.client.extractions().estimateCost maps to POST /extractions/estimate, client.extractions().run maps to POST /extractions, client.extractions().retrieve maps to GET /extractions/{id}, and client.extractions().exportResults maps to GET /extractions/{id}/export. For follower exports, follower_explorer requires targetUsername.
client.extractions().run returns the queued 202 Accepted receipt from POST /extractions: REST id, toolType, and status: "running" as Java job.id(), job.toolType(), and job._status(). Store job.id() immediately, then poll client.extractions().retrieve before reading pages or calling client.extractions().exportResults. Credit reservation happens after the job starts. If available credits changed since estimateCost, the run can fetch only the affordable count before export or mark the job failed with insufficient_credits.job.id(), targetUsername, estimate.estimatedResults(), and estimate.source() before polling so a queue retry can resume without rerunning the extraction. client.extractions().retrieve returns results(), hasMore(), and nextCursor(); pass nextCursor() back as after to page through large follower lists. Map exported User ID or row xUserId as the CRM unique key. Use xquik-followers.jsonl for queue replay or warehouse loads, xquik-followers.json for app ingestion, xquik-followers.csv for CRM import, and xquik-followers.xlsx for analyst handoff. Cost: 1 credit per follower extracted or returned. Exports are free after the extraction job exists.
Workflow: Tweet Replies to CSV, JSON, or XLSX
Use this workflow when a Java worker needs every reply to a campaign, support thread, launch post, or incident update as a durable file.reply_extractor requires targetTweetId; estimate first, run the job, poll retrieve, then export the completed job as CSV, JSON, or XLSX.
client.extractions().estimateCost maps to POST /extractions/estimate, client.extractions().run maps to POST /extractions, client.extractions().retrieve maps to GET /extractions/{id}, and client.extractions().exportResults maps to GET /extractions/{id}/export.
Reuse the follower export loop above. Change only the required target, tool type, and output names:
job.id() before polling so a queue retry can resume with client.extractions().retrieve(job.id()) and repeat client.extractions().exportResults(...) after completion. Stream page.results() to Paths.get("xquik-replies.jsonl"). Keep page.nextCursor() as the checkpoint when you stream replies to JSON Lines. Pass it back as after on the next ExtractionRetrieveParams.Builder pageParams.
Keep the same estimate.allowed() credit branch from the follower export workflow before calling run.
Export the completed job with the same helper used above:
ExtractionExportResultsParams.Format.JSON to write Paths.get("xquik-replies.json") and ExtractionExportResultsParams.Format.XLSX to write Paths.get("xquik-replies.xlsx"). Use xquik-replies.jsonl for queue replay or warehouse loads, xquik-replies.json for app ingestion, xquik-replies.csv for CRM import, and xquik-replies.xlsx for analyst handoff.
Workflow: Post Media Tweets and DM Attachments
Use this workflow when a JVM service needs to publish a media tweet, reply with media, or send a direct message with an uploaded local file.client.x().tweets().create maps to POST /x/tweets; pass public media URLs through .addMedia() or .media(). Send up to 4 image URLs or exactly 1 MP4 video URL up to 100 MB, and do not mix video with other media. For replies, set .replyToTweetId() to the parent tweet ID. client.x().media().upload maps to POST /x/media; use media.mediaId() only for the one-item DM .addMediaId() handoff.
client.x().tweets().withRawResponse().create(...) to capture the durable write action. Send a unique Idempotency-Key, store id, request.hash, billing, result, and statusUrl, then poll while terminal is false. Retry only when safeToRetry is true, using a new key.
Keep DM body text in private systems. Shared logs and handoffs should store message_id, optional media_id, account, user_id, and lifecycle status. Leave replyToMessageId unset because the REST endpoint rejects DM reply threading.
Use public media URLs with client.x().tweets().create. Do not pass uploaded media.mediaId() values to tweet creation.
Error Handling
The Java SDK throws unchecked exceptions.400 Bad Request
Throws
BadRequestException.401 Unauthorized
Throws
UnauthorizedException.403 Permission Denied
Throws
PermissionDeniedException.404 Not Found
Throws
NotFoundException.422 Validation Error
Throws
UnprocessableEntityException.429 Rate Limited
Throws
RateLimitException.5xx Server Error
Throws
InternalServerException.XTwitterScraperIoException. All SDK exceptions inherit from XTwitterScraperException.
Pagination
Paginated responses expose generated fields such ashasNextPage. Use the endpoint cursor fields documented in the API reference when requesting additional pages.