Watch Framer build a tweet ticker with Xquik, from 6:07.
This Python SDK calls the Xquik API.
Use this Twitter API Python SDK by Xquik to read tweets as Pydantic models. Sync & async clients share every method. Public reads need no X 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.
The SDK requires Python 3.10 or later.
pip install x_twitter_scraper
Set X_TWITTER_SCRAPER_API_KEY, then run this search.
import os from x_twitter_scraper import XTwitterScraper client = XTwitterScraper( api_key=os.environ.get("X_TWITTER_SCRAPER_API_KEY"), # Optional. The client reads this variable. ) response = client.x.tweets.search( q="from:elonmusk", limit=10, ) for tweet in response.tweets: print(tweet.id, tweet.text)
Next, read the Python SDK guide, API map or REST reference.
- 4,400+ downloads of x-twitter-scraper on PyPI (source)
- 5.8 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-07. See each number with its date & source on xquik.com/benchmarks or as JSON.
Tweepy calls the official X API, which needs a developer account & bearer token.
This SDK reads public X data with an Xquik API key.
This call replaces a Tweepy search_recent_tweets call.
# Tweepy: client.search_recent_tweets(query="from:NASA", max_results=10) response = client.x.tweets.search(q="from:NASA", limit=10)
Code built on snscrape's TwitterSearchScraper maps to 1 SDK call.
The SDK takes the same X search operators & returns typed tweets.
# snscrape: TwitterSearchScraper("from:NASA since:2026-10-01").get_items() response = client.x.tweets.search(q="from:NASA since:2026-10-01", limit=25) for tweet in response.tweets: print(tweet.id, tweet.text)
| Task | REST route | Usage |
|---|---|---|
| Search tweets without the X API | GET /x/tweets/search |
Use keyword or advanced operator queries. |
| Read an X profile timeline | GET /x/users/{id}/tweets |
Pass the cursor to read the next page. |
| 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 |
Connect an X account first. |
| Export large X datasets | POST /extractions |
Poll status, then download results. |
| Run giveaway draws | POST /draws |
Pick winners from post replies. |
| Download or upload media | /x/media/* |
Use typed file helpers. |
| Monitor an account | POST /monitors |
Deliver events through HMAC webhooks. |
| Post or reply | POST /x/tweets |
Confirm the account and payload. |
Use the typed REST SDK in application code. Add https://xquik.com/mcp to MCP clients.
Follow the MCP guide for current authentication support.
Import AsyncXTwitterScraper and await each API call.
import os import asyncio from x_twitter_scraper import AsyncXTwitterScraper client = AsyncXTwitterScraper( api_key=os.environ.get("X_TWITTER_SCRAPER_API_KEY"), # Optional. The client reads this variable. ) async def main() -> None: response = await client.x.tweets.search( q="from:elonmusk", limit=10, ) asyncio.run(main())
Both clients expose the same resources and methods.
The async client uses httpx. Install aiohttp for an alternative backend.
pip install x_twitter_scraper[aiohttp]
Select it with http_client=DefaultAioHttpClient().
import os import asyncio from x_twitter_scraper import DefaultAioHttpClient from x_twitter_scraper import AsyncXTwitterScraper async def main() -> None: async with AsyncXTwitterScraper( api_key=os.environ.get("X_TWITTER_SCRAPER_API_KEY"), # Optional. The client reads this variable. http_client=DefaultAioHttpClient(), ) as client: response = await client.x.tweets.search( q="from:elonmusk", limit=10, ) asyncio.run(main())
Nested request parameters use TypedDicts. Responses use Pydantic models with these helpers.
- Serialize to JSON with
model.to_json(). - Convert to a dictionary with
model.to_dict().
Set python.analysis.typeCheckingMode to basic in VS Code to catch type errors.
Pass uploads as bytes, a PathLike, or (filename, contents, media_type).
import httpx from x_twitter_scraper import XTwitterScraper client = XTwitterScraper() image = httpx.get("https://xquik.com/logo.png").content client.x.media.upload( account="@elonmusk", file=("logo.png", image, "image/png"), idempotency_key="upload-2026-10-15", )
The async client uses the same interface and reads PathLike content asynchronously.
Connection failures raise an APIConnectionError subclass.
Non-2xx responses raise an APIStatusError subclass with status_code and response.
Every SDK error inherits from APIError.
import x_twitter_scraper from x_twitter_scraper import XTwitterScraper client = XTwitterScraper() try: client.x.tweets.search( q="from:elonmusk", limit=10, ) except x_twitter_scraper.APIConnectionError as e: print("Could not reach the server. Check the connection.") print(e.__cause__) # Underlying httpx exception. except x_twitter_scraper.RateLimitError as e: print("Rate limited. Retry later.") except x_twitter_scraper.APIStatusError as e: print("Server returned a non-2xx status.") print(e.status_code) print(e.response)
The SDK uses these error classes.
| Status code | Error type |
|---|---|
| 400 | BadRequestError |
| 401 | AuthenticationError |
| 403 | PermissionDeniedError |
| 404 | NotFoundError |
| 409 | ConflictError |
| 422 | UnprocessableEntityError |
| 429 | RateLimitError |
| >=500 | InternalServerError |
| N/A | APIConnectionError |
The SDK retries connection errors and HTTP 408, 409, 429, and 5xx responses. It uses exponential backoff and attempts 2 retries by default.
Set max_retries to change or disable retries.
Set it on the client, or on 1 request through with_options.
from x_twitter_scraper import XTwitterScraper client = XTwitterScraper( max_retries=0, ) client.with_options(max_retries=5).x.tweets.search( q="from:elonmusk", limit=10, )
Requests time out after 1 minute, and connections after 5 seconds.
Set a float or httpx.Timeout through timeout.
Set it on the client, or on 1 request through with_options.
import httpx from x_twitter_scraper import XTwitterScraper client = XTwitterScraper( timeout=20.0, ) client = XTwitterScraper( timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0), ) client.with_options(timeout=5.0).x.tweets.search( q="from:elonmusk", limit=10, )
Timeouts raise APITimeoutError.
Timed-out requests follow the default retry policy.
The SDK uses Python's logging module.
Set X_TWITTER_SCRAPER_LOG to info to enable logs.
export X_TWITTER_SCRAPER_LOG=infoUse debug for request and response details.
Both missing and explicit null response fields map to None.
Check .model_fields_set to distinguish them.
response = client.x.tweets.search(q="from:NASA", limit=1) tweet = response.tweets[0] if tweet.community_note is None: if "community_note" not in tweet.model_fields_set: print('The response omitted "community_note".') else: print('The response set "community_note" to null.')
Prefix a method with .with_raw_response. to access the raw response.
from x_twitter_scraper import XTwitterScraper client = XTwitterScraper() response = client.x.tweets.with_raw_response.search( q="from:elonmusk", limit=10, ) print(response.headers.get("X-My-Header")) tweet = response.parse() # Parse the regular x.tweets.search() result. print(tweet.has_next_page)
Sync methods return APIResponse.
Async methods return AsyncAPIResponse with awaitable content readers.
The raw-response interface reads the complete body when you make the request.
Use .with_streaming_response and a context manager to read it on demand.
Call .read(), .text(), .json(), an iterator, or .parse().
The async client provides async versions of these methods.
with client.x.tweets.with_streaming_response.search( q="from:elonmusk", limit=10, ) as response: print(response.headers.get("X-My-Header")) for line in response.iter_lines(): print(line)
The context manager always closes the response.
The SDK types every documented endpoint, parameter, and response property. Use its lower-level methods for undocumented API features.
Use client.get, client.post, or another HTTP method for undocumented endpoints.
Client options, including retries, apply to these requests.
import httpx response = client.get( "/x/tweets/search", cast_to=httpx.Response, options={"params": {"q": "from:NASA", "limit": 1}}, ) print(response.headers.get("content-type"))
Pass extra values through extra_query, extra_body, or extra_headers.
Read an extra field through response.unknown_prop.
Use response.model_extra to get every extra field as a dictionary.
Replace the httpx client to configure these options.
- Proxies
- Custom transports
- Other advanced client features
import httpx from x_twitter_scraper import XTwitterScraper, DefaultHttpxClient client = XTwitterScraper( # Or use the `X_TWITTER_SCRAPER_BASE_URL` env var base_url="http://my.test.server.example.com:8083", http_client=DefaultHttpxClient( proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0"), ), )
Use with_options() to replace it for one request.
from x_twitter_scraper import DefaultHttpxClient client.with_options(http_client=DefaultHttpxClient(timeout=30.0)).x.tweets.search( q="from:NASA", limit=10, )
Garbage collection closes the client's HTTP connections.
Call .close() or use a context manager to close them earlier.
from x_twitter_scraper import XTwitterScraper with XTwitterScraper() as client: # Make requests here. ... # The HTTP client is closed.
This package follows SemVer with these exceptions.
- Static type changes that preserve runtime behavior.
- Changes to undocumented internals that stay public.
- Changes unlikely to affect normal use.
Open an issue with questions, bugs or suggestions.
If new features are missing, Python may still load an older package. Check the runtime version.
import x_twitter_scraper print(x_twitter_scraper.__version__)
No. Public reads need only an Xquik API key. Private reads & X account actions need a connected X account.
No. Xquik runs its own REST API. This SDK calls that API, not the official X API.
- X (Twitter) scraper API & Twitter MCP server with REST, MCP & Skill setup.
- Twitter API SDKs for TypeScript, Go, Ruby & Java.
- More Twitter API SDKs for Kotlin, C# & PHP.
- Twitter CLI & X CLI for terminal workflows.
- Twitter advanced search operators with tested examples.
- Twitter agent plugins for OpenClaw & Hermes Agent.
- Twitter integrations for n8n, Prefect, Haystack & Paperclip.
- More Twitter integrations for Terraform, Convex, Supabase & Strapi.
- Twitter MCP for AI agents, VS Code & Raycast.
- Xquik X API & Twitter scraper, Twitter API docs & docs source.
- Report vulnerabilities through the security policy.
- Ask usage questions through the organization support policy.
- Read the contribution guide & governance policy.
- Read the OpenSSF evidence & citation metadata.
Xquik is an independent third-party service. Not affiliated with X Corp. "Twitter" and "X" are trademarks of X Corp.