X (Twitter) Ruby API SDK & Scraper by Xquik
Watch Framer build a tweet ticker with Xquik, from 6:07.
This Ruby SDK calls the Xquik API.
Use this X (Twitter) scraper Ruby SDK by Xquik to search tweets & posts. Export followers and read profiles as typed results. Public reads need no X (Twitter) developer account.
Xquik is the world's fastest and cheapest X (Twitter) scraper service with the most complete X (Twitter) data. Most other Apify Actors charge before filtering or deduplication. Xquik charges only for delivered, unique, filter-matching results and never pads rows. Xquik is independent and not affiliated with X Corp.
The Xquik REST API read 45 tweets per second on 2026-10-15. That cost $0.15 per 1,000. The fastest of 4 rival Actors read 12.5 per second. The cheapest cost $0.173 per 1,000. Compare each run. Most rival Actors charge before they filter or dedup. Xquik charges only for delivered, unique, filter-matching results.
Install the X (Twitter) API Ruby gem
The SDK requires Ruby 3.2.0 or later.
Add the gem to your Gemfile.
gem "x-twitter-scraper", "~> 0.10.6"Or add it from a terminal.
bundle add x-twitter-scraperScrape tweets with the Ruby X (Twitter) API
require "bundler/setup"
require "x_twitter_scraper"
x_twitter_scraper = XTwitterScraper::Client.new(
api_key: ENV["X_TWITTER_SCRAPER_API_KEY"] # Optional. The client reads this variable.
)
response = x_twitter_scraper.x.tweets.search(q: "from:elonmusk", limit: 10)
puts(response)Next, read the Ruby SDK guide, REST API reference or RubyGems page.
Benchmarks & usage
- 10,000+ downloads of x-twitter-scraper on RubyGems (source)
- 8.6 s p99 REST server read time over 7 days, failures included (source)
- This repo meets the OpenSSF Best Practices passing criteria (source)
Checked on 2026-11-13. See each number with its date & source on xquik.com/benchmarks or as JSON.
Common X (Twitter) tasks
| Task | REST route | Usage |
|---|---|---|
| Search tweets without the X API | GET /x/tweets/search |
Use keyword or advanced operator queries. |
| Read an X (Twitter) profile timeline | GET /x/users/{id}/tweets |
Paginate bounded results. |
| Scrape Twitter followers | GET /x/users/{id}/followers |
Use an extraction for complete datasets. |
| Scrape following accounts | GET /x/users/{id}/following |
Use an extraction for complete datasets. |
| Read a home timeline | GET /x/timeline |
Approve this private read. |
| Export large X (Twitter) datasets | POST /extractions |
Poll status, then download results. |
| Download or upload media | /x/media/* |
Use typed file helpers. |
| Monitor an account | POST /monitors |
Deliver events through HMAC webhooks. |
| Post a tweet or reply | POST /x/tweets |
Confirm the account and payload. |
Usage
Handling errors
The SDK raises an APIError subclass for connection failures and non-2xx responses.
begin
account = x_twitter_scraper.account.retrieve
rescue XTwitterScraper::Errors::APIConnectionError => e
puts("Could not reach the server. Check the connection.")
puts(e.cause) # Underlying net/http exception.
rescue XTwitterScraper::Errors::RateLimitError => e
puts("Rate limited. Retry later.")
rescue XTwitterScraper::Errors::APIStatusError => e
puts("Request failed. Inspect the returned HTTP status.")
puts(e.status)
end| Cause | Error type |
|---|---|
| HTTP 400 | BadRequestError |
| HTTP 401 | AuthenticationError |
| HTTP 403 | PermissionDeniedError |
| HTTP 404 | NotFoundError |
| HTTP 409 | ConflictError |
| HTTP 422 | UnprocessableEntityError |
| HTTP 429 | RateLimitError |
| HTTP >= 500 | InternalServerError |
| Other HTTP error | APIStatusError |
| Timeout | APITimeoutError |
| Network error | APIConnectionError |
Retries
The SDK retries connection errors, timeouts & HTTP 408, 409, 429, and 5xx responses.
It uses exponential backoff with 2 retries by default.
Set max_retries to change or disable retries.
# Change the client default.
x_twitter_scraper = XTwitterScraper::Client.new(
max_retries: 0
)
# Override one request.
x_twitter_scraper.account.retrieve(request_options: {max_retries: 5})Timeouts
Requests time out after 60 seconds. Set timeout to change or disable this limit.
# Change the client default.
x_twitter_scraper = XTwitterScraper::Client.new(
timeout: nil
)
# Override one request.
x_twitter_scraper.account.retrieve(request_options: {timeout: 5})Timeouts raise XTwitterScraper::Errors::APITimeoutError and follow the retry policy.
BaseModel
All parameter and response objects inherit from XTwitterScraper::Internal::Type::BaseModel and support these operations.
- Access known and unknown fields with
obj[:prop]. - Destructure fields with
obj => {prop: prop}or pattern matching. - Compare objects by their field values with
==. - Print classes and instances in a readable format.
- Convert values with
#to_h,#deep_to_h,#to_json, or#to_yaml.
Custom requests
Use extra_query, extra_body, or extra_headers under request_options.
Matching extra_ values override documented parameters.
value = "readme-example"
account =
x_twitter_scraper.account.retrieve(
request_options: {
extra_query: {my_query_parameter: value},
extra_body: {my_body_parameter: value},
extra_headers: {"my-header": value}
}
)
puts(account[:my_undocumented_property])Use request for undocumented endpoints. It keeps authentication and retries.
response = x_twitter_scraper.request(
method: :get,
path: "x/tweets/search",
query: {q: "from:NASA", limit: 1},
headers: {"my-header": "value"}
)
puts(response[:tweets].length)Concurrency & connection pooling
Clients are thread-safe. Fork them only when no HTTP requests are in flight. Each client pools at least 99 HTTP connections by default. Reuse 1 client per application in most cases. Requests wait when every connection is busy. This wait counts toward the request timeout. Other SDK classes do not lock their data.
Sorbet
The gem ships RBI definitions without sorbet-runtime.
Pass request hashes or typed parameter objects.
x_twitter_scraper.x.tweets.search(q: "from:elonmusk", limit: 10)
params = XTwitterScraper::X::TweetSearchParams.new(q: "from:elonmusk", limit: 10)
x_twitter_scraper.x.tweets.search(**params)Enums
Tagged symbols replace T::Enum and remain runtime primitives.
# :en
puts(XTwitterScraper::AccountUpdateLocaleParams::Locale::EN)Sorbet types the constant as T.all(XTwitterScraper::AccountUpdateLocaleParams::Locale, Symbol).
Enum parameters accept constants or literal values.
x_twitter_scraper.account.update_locale(
locale: XTwitterScraper::AccountUpdateLocaleParams::Locale::EN,
# …
)
x_twitter_scraper.account.update_locale(
locale: :en,
# …
)Versioning
This package follows SemVer. Version 0 releases may change APIs.
Changes to non-runtime *.rbi and *.rbs definitions are non-breaking.
Questions
Do I need an X (Twitter) developer account?
No. Public reads need only an Xquik API key. Private reads & account actions need a connected X (Twitter) account.
Is this the official X API?
No. Xquik runs its own REST API. This SDK calls that API, not the official X API.
More Xquik tools
- X (Twitter) scraper API & X (Twitter) MCP server with REST, MCP & Skill setup.
- X (Twitter) API SDKs for TypeScript, Python, Go & Java.
- X (Twitter) API SDKs for Kotlin, C# & PHP.
- Twitter CLI & X CLI for terminal workflows.
- Twitter advanced search operators with tested examples.
- X (Twitter) agent plugins for OpenClaw & Hermes Agent.
- X (Twitter) integrations for n8n, Prefect, Haystack & Paperclip.
- X (Twitter) integrations for Terraform, Convex, Supabase & Strapi.
- X (Twitter) MCP for AI agents, VS Code & Raycast.
- Xquik X API & Twitter scraper.
- X (Twitter) API documentation and its source.
Help & contributing
- Report vulnerabilities through the security policy.
- Ask usage questions through the organization support policy.
- Read the contribution guide.
Xquik is an independent third-party service. Not affiliated with X Corp. "Twitter" and "X" are trademarks of X Corp.