Use the Xquik C# SDK for Twitter search, timelines, profiles, and followers. Download media, manage webhooks, and run X automation from .NET.
The typed NuGet package calls the documented Xquik REST API.
It does not call or emulate the official X API.
Use the SDK for asynchronous, typed requests from .NET services.
Reuse the configurable HttpClient for shared transport settings.
Call REST directly when a NuGet dependency does not fit.
Read the C# SDK guide or API guide.
| Task | REST route | Workflow note |
|---|---|---|
| Search tweets | GET /x/tweets/search |
Use keywords or advanced Twitter search operators. |
| Extract profile tweets | GET /x/users/{id}/tweets |
Paginate bounded timeline results. |
| Export followers | GET /x/users/{id}/followers |
Use an extraction for complete datasets. |
| Export following accounts | GET /x/users/{id}/following |
Use an extraction for complete datasets. |
| Read a home timeline | GET /x/timeline |
Approve this private read. |
| Read lists or communities | /x/lists/*, /x/communities/* |
Use the typed nested services. |
| Export large datasets | POST /extractions |
Poll status, then download results. |
| Monitor an account | POST /monitors |
Deliver events through HMAC webhooks. |
| Post or reply | POST /x/tweets |
Confirm the account and payload. |
Requires .NET Standard 2.0 or later.
Install the package from NuGet:
dotnet add package XTwitterScraper --version 0.6.2Verify a GitHub release package before using it:
release_tag=vVERSION
package_version="${release_tag#v}"
gh release download "$release_tag" \
--repo Xquik-dev/x-twitter-scraper-csharp \
--pattern "XTwitterScraper.$package_version.nupkg"
gh attestation verify "XTwitterScraper.$package_version.nupkg" \
--repo Xquik-dev/x-twitter-scraper-csharp \
--signer-workflow Xquik-dev/x-twitter-scraper-csharp/.github/workflows/publish-nuget.yml \
--source-ref "refs/tags/$release_tag" \
--deny-self-hosted-runnersRequire the Xquik-dev repository and expected release workflow.
GitHub verifies the artifact digest, signer identity, and transparency proof.
NuGet.org applies repository signatures to registry packages.
using System;
using XTwitterScraper;
using XTwitterScraper.Models.X.Tweets;
XTwitterScraperClient client = new();
TweetSearchParams parameters = new()
{
Q = "from:elonmusk",
Limit = 10,
};
var paginatedTweets = await client.X.Tweets.Search(parameters);
Console.WriteLine(paginatedTweets);Configure the client using environment variables:
using XTwitterScraper;
// Reads API key, bearer token, and base URL environment variables.
XTwitterScraperClient client = new();Set credentials directly when environment variables do not fit:
using XTwitterScraper;
XTwitterScraperClient client = new()
{
ApiKey = "My API Key",
BearerToken = "My Bearer Token",
};Environment variables and explicit properties can be combined.
| Property | Environment variable | Required | Default value |
|---|---|---|---|
ApiKey |
X_TWITTER_SCRAPER_API_KEY |
false | - |
BearerToken |
X_TWITTER_SCRAPER_BEARER_TOKEN |
false | - |
BaseUrl |
X_TWITTER_SCRAPER_BASE_URL |
true | "https://xquik.com/api/v1" |
Call WithOptions to reuse connections with temporary settings:
using System;
var account = await client
.WithOptions(options =>
options with
{
BaseUrl = "https://example.com",
Timeout = TimeSpan.FromSeconds(42),
}
)
.Account.Retrieve(parameters);
Console.WriteLine(account);The with expression builds the modified options.
WithOptions leaves the original client or service unchanged.
client.X.Tweets.Search accepts TweetSearchParams and returns Task<PaginatedTweets>.
Binary endpoints return HttpResponse instead of parsing the body:
using System;
using XTwitterScraper.Models.Extractions;
ExtractionExportResultsParams parameters = new()
{
ID = "id",
Format = Format.Csv,
};
var response = await client.Extractions.ExportResults(parameters);
Console.WriteLine(response);Use CopyToAsync to save content to any Stream:
using System.IO;
using var response = await client.Extractions.ExportResults(parameters);
using var contentStream = await response.ReadAsStream();
using var fileStream = File.Open(path, FileMode.Create);
await contentStream.CopyToAsync(fileStream); // Accepts any Stream.Typed methods hide headers, status codes, and raw bodies.
Prefix any HTTP call with WithRawResponse to access them:
var response = await client.WithRawResponse.Account.Retrieve();
var statusCode = response.StatusCode;
var headers = response.Headers;Access the raw HttpResponseMessage through RawMessage.
Deserialize non-streaming responses when you need a typed model:
using System;
using XTwitterScraper.Models.Account;
var response = await client.WithRawResponse.Account.Retrieve();
AccountRetrieveResponse deserialized = await response.Deserialize();
Console.WriteLine(deserialized);API errors inherit from XTwitterScraperApiException:
| Status | Exception |
|---|---|
| 400 | XTwitterScraperBadRequestException |
| 401 | XTwitterScraperUnauthorizedException |
| 403 | XTwitterScraperForbiddenException |
| 404 | XTwitterScraperNotFoundException |
| 422 | XTwitterScraperUnprocessableEntityException |
| 429 | XTwitterScraperRateLimitException |
| 5xx | XTwitterScraper5xxException |
| others | XTwitterScraperUnexpectedStatusCodeException |
All 4xx errors inherit from XTwitterScraper4xxException.
Networking errors use XTwitterScraperIOException.
Invalid response data uses XTwitterScraperInvalidDataException.
Every SDK exception inherits from XTwitterScraperException.
The SDK retries these errors twice with exponential backoff:
- Connection errors
- 408 Request Timeout
- 409 Conflict
- 429 Rate Limit
- 5xx server errors
The API may override retry behavior.
Set MaxRetries on the client:
using XTwitterScraper;
XTwitterScraperClient client = new() { MaxRetries = 3 };Override retries for one call with WithOptions:
using System;
var account = await client
.WithOptions(options =>
options with { MaxRetries = 3 }
)
.Account.Retrieve(parameters);
Console.WriteLine(account);Requests time out after 1 minute by default.
Set Timeout on the client:
using System;
using XTwitterScraper;
XTwitterScraperClient client = new() { Timeout = TimeSpan.FromSeconds(42) };Override the timeout for one call with WithOptions:
using System;
var account = await client
.WithOptions(options =>
options with { Timeout = TimeSpan.FromSeconds(42) }
)
.Account.Retrieve(parameters);
Console.WriteLine(account);Route requests through a custom HttpClient:
using System.Net;
using System.Net.Http;
using XTwitterScraper;
var httpClient = new HttpClient
(
new HttpClientHandler
{
Proxy = new WebProxy("https://example.com:8080")
}
);
XTwitterScraperClient client = new() { HttpClient = httpClient };The SDK accepts API fields missing from its generated types.
Pass dictionaries for extra header, query, and body values. Methods without request bodies accept only header and query dictionaries.
using System.Collections.Generic;
using System.Text.Json;
using XTwitterScraper.Models.X.Tweets;
TweetSearchParams parameters = new
(
rawHeaderData: new Dictionary<string, JsonElement>()
{
{ "Custom-Header", JsonSerializer.SerializeToElement(42) }
},
rawQueryData: new Dictionary<string, JsonElement>()
{
{ "custom_query_param", JsonSerializer.SerializeToElement(42) }
}
)
{
// Documented values override matching custom parameters.
Limit = 200
};Access raw values through RawHeaderData, RawQueryData, and RawBodyData.
Use FromRawUnchecked for unsupported values in required parameters:
using System.Collections.Generic;
using System.Text.Json;
using XTwitterScraper.Models.X.Tweets;
var parameters = TweetSearchParams.FromRawUnchecked
(
rawHeaderData: new Dictionary<string, JsonElement>(),
rawQueryData: new Dictionary<string, JsonElement>
{
{
"q",
JsonSerializer.SerializeToElement("custom value")
}
}
);Read undocumented response properties through RawData:
using System.Text.Json;
var response = await client.X.Tweets.Search(parameters);
if (response.RawData.TryGetValue("my_custom_key", out JsonElement value))
{
// Process value.
}RawData contains the complete response as IReadOnlyDictionary<string, JsonElement>.
Unexpected response values throw only when you access their properties.
Call Validate to check the complete response immediately:
var paginatedTweets = await client.X.Tweets.Search(parameters);
paginatedTweets.Validate();Set ResponseValidation to validate every response:
using XTwitterScraper;
XTwitterScraperClient client = new() { ResponseValidation = true };Validate one call with WithOptions:
using System;
var paginatedTweets = await client
.WithOptions(options =>
options with { ResponseValidation = true }
)
.X.Tweets.Search(parameters);
Console.WriteLine(paginatedTweets);Read Contributing, Governance, and Security.
See OpenSSF evidence for verified controls and remaining blockers.
The package follows SemVer. Before v1.0, minor releases may change undocumented internals or behavior unlikely to affect most users.
Review release notes before upgrading between minor versions.
Open an issue for questions, bugs, or suggestions.
Xquik is an independent third-party service. Not affiliated with X Corp. "Twitter" and "X" are trademarks of X Corp.