> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xquik.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tweet analytics API for likes, replies & reposts

> Refresh tweet analytics for cached X posts. Retrieve likes, replies, reposts, quotes, bookmarks, views, post text, IDs, tweet count, and snapshot guidance.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="200" id="response-styles-performance-200">
      ```json theme={null}
      {
        "xUsername": "elonmusk",
        "tweetCount": 5,
        "tweets": [
          {
            "id": "1234567890",
            "text": "Excited to share our latest research.",
            "likeCount": 120,
            "retweetCount": 15,
            "replyCount": 8
          }
        ]
      }
      ```
    </Tab>

    <Tab title="401" id="response-styles-performance-401">
      ```json theme={null}
      {
        "error": "unauthenticated",
        "message": "Authentication required. Provide a valid API key or bearer token."
      }
      ```
    </Tab>

    <Tab title="402" id="response-styles-performance-402">
      ```json theme={null}
      {
        "error": "insufficient_credits",
        "message": "Insufficient credits. Top up or subscribe to continue."
      }
      ```
    </Tab>

    <Tab title="404" id="response-styles-performance-404">
      ```json theme={null}
      {
        "error": "not_found",
        "message": "Resource not found."
      }
      ```
    </Tab>

    <Tab title="422" id="response-styles-performance-422">
      ```json theme={null}
      {
        "error": "invalid_input",
        "message": "Invalid input. Check the request body."
      }
      ```
    </Tab>

    <Tab title="429" id="response-styles-performance-429">
      ```json theme={null}
      {
        "error": "rate_limit_exceeded",
        "message": "Too many requests. Try again later.",
        "retryAfter": 60
      }
      ```
    </Tab>
  </Tabs>
</Panel>

<blockquote className="agent-llms-directive">
  For the complete documentation index, see <a href="/llms.txt">llms.txt</a>.
</blockquote>

<Callout icon="coins" color="#5c3327">
  **1 credit per tweet returned** · [All plans](https://xquik.com/#pricing) from \$0.00012/credit
</Callout>

## Refresh tweet engagement for a cached style

Call this endpoint to refresh public engagement counts for cached tweets. Xquik
looks up each stored Tweet ID and returns current cumulative metrics.

Start with [Analyze & Cache Style](/api-reference/styles/analyze). Then pass its
returned `xUsername` as `{id}`. The lookup stays inside the authenticated
Xquik account.

This route contacts X on every request. It does not return saved analytics,
historical deltas, or a precomputed engagement rate.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET https://xquik.com/api/v1/styles/xquik/performance \
    -H "x-api-key: xq_YOUR_KEY_HERE" | jq
  ```

  ```javascript Node.js theme={null}
  const username = "xquik";
  const endpoint = `https://xquik.com/api/v1/styles/${encodeURIComponent(username)}/performance`;
  const response = await fetch(endpoint, {
    method: "GET",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
    },
  });

  const result = await response.json();
  if (!response.ok) {
    throw new Error(`${result.error}: ${result.message}`);
  }
  const snapshot = {
    measuredAt: new Date().toISOString(),
    ...result,
  };
  ```

  ```python Python theme={null}
  from datetime import UTC, datetime
  from urllib.parse import quote

  import requests

  username = "xquik"
  endpoint = (
      "https://xquik.com/api/v1/styles/"
      f"{quote(username, safe='')}/performance"
  )
  response = requests.get(
      endpoint,
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      timeout=30,
  )
  response.raise_for_status()
  result = response.json()
  snapshot = {
      "measuredAt": datetime.now(UTC).isoformat(),
      **result,
  }
  ```

  ```go Go theme={null}
  package main

  import (
      "encoding/json"
      "fmt"
      "net/http"
      "net/url"
      "time"
  )

  func main() {
      username := "xquik"
      endpoint := "https://xquik.com/api/v1/styles/" +
          url.PathEscape(username) + "/performance"
      req, err := http.NewRequest(http.MethodGet, endpoint, nil)
      if err != nil {
          panic(err)
      }
      req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")

      resp, err := http.DefaultClient.Do(req)
      if err != nil {
          panic(err)
      }
      defer resp.Body.Close()

      var result map[string]interface{}
      if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
          panic(err)
      }
      if resp.StatusCode != http.StatusOK {
          panic(fmt.Sprintf("tweet analytics failed: %v", result))
      }
      result["measuredAt"] = time.Now().UTC().Format(time.RFC3339)
      fmt.Println(result)
  }
  ```
</CodeGroup>

## Use an analyzed X username

The path names the value `{id}`. The route reads it as a
lowercase cache key, not a numeric database ID.

Use an analyzed X username whose samples contain live Tweet IDs. A custom style
saved from supplied text contains local sample IDs. Those IDs cannot produce X
tweet analytics.

| Profile source | Performance result |
| - | - |
| Analyzed public X username | Refreshes public metrics for cached Tweet IDs |
| Saved custom style label | Local sample IDs cannot resolve as X Tweets |
| Numeric database ID | Unsupported lookup key |
| Another customer's cache | Inaccessible to this credential |

The route processes at most 100 cached Tweet records. Use
[Get Style](/api-reference/styles/get) to inspect the stored sample count first.

## Read every tweet analytics field

The response returns one row per refreshed Tweet. Each count is cumulative at
request time.

| Field | Meaning | Analytics use |
| - | - | - |
| `id` | Live Tweet ID | Join snapshots without numeric conversion. |
| `text` | Current Tweet text | Store the measured post with its counts. |
| `likeCount` | Likes | Count likes. |
| `replyCount` | Replies | Count replies. |
| `retweetCount` | Reposts without comments | Count reposts without comment. |
| `quoteCount` | Quote posts with comments | Count reposts with comment. |
| `bookmarkCount` | Bookmarks | Count private saves. X reports only the total. |
| `viewCount` | Public view or impression count | Use as exposure, not unique people. |

Reposts and quote posts are separate counts. Do not add quotes into
`retweetCount` twice.

`viewCount` is not a unique-audience field. Repeat exposure can increase the
count. See the [X public metric definitions](https://docs.x.com/x-api/fundamentals/metrics).

## Store tweet analytics snapshots

The response does not provide a measurement timestamp or historical baseline.
Record the client request time beside every successful response.
Keep each Tweet ID, metric row, and measurement time together.

Use this snapshot key:

| Snapshot column | Source |
| - | - |
| Profile key | `xUsername` |
| Tweet key | `tweets[].id` |
| Measurement time | Client UTC timestamp |
| Tweet text | `tweets[].text` |
| Public counts | All 6 count fields |

Do not overwrite an earlier snapshot. Store each request separately. Calculate
deltas only between snapshots for the same Tweet ID.

```json theme={null}
{
  "measuredAt": "2026-08-02T12:00:00.000Z",
  "xUsername": "xquik",
  "tweetId": "1950882898740914261",
  "likeCount": 420,
  "replyCount": 18,
  "retweetCount": 54,
  "quoteCount": 11,
  "bookmarkCount": 87,
  "viewCount": 28000
}
```

## Calculate tweet engagement rates

Xquik returns counts. Your application can derive rates to compare
tweets. Label them as application metrics, not fields returned by Xquik.

Let `views` equal `viewCount`. Use `null` when `views` equals 0.

| Derived metric | Formula | Interpretation |
| - | - | - |
| Public interactions | `likes + replies + reposts + quotes + bookmarks` | Total counted interaction actions |
| Interaction rate | `public interactions / views` | Counted actions per view |
| Conversation rate | `replies / views` | Replies per view |
| Amplification rate | `(reposts + quotes) / views` | Reposts and quotes per view |
| Save rate | `bookmarks / views` | Bookmarks per view |
| Like rate | `likes / views` | Likes per view |

Do not include `viewCount` in the interaction numerator. A view is the
denominator for these derived rates.

Use medians when comparing several tweets. One viral post can distort an
average. Keep raw counts beside every derived rate.

## Compare current and earlier tweet metrics

For 2 snapshots, subtract earlier counts from later counts. Reject negative
deltas until you confirm both snapshots used the same Tweet and field meaning.

| Delta | Formula |
| - | - |
| New likes | `later.likeCount - earlier.likeCount` |
| New replies | `later.replyCount - earlier.replyCount` |
| New reposts | `later.retweetCount - earlier.retweetCount` |
| New quotes | `later.quoteCount - earlier.quoteCount` |
| New bookmarks | `later.bookmarkCount - earlier.bookmarkCount` |
| New views | `later.viewCount - earlier.viewCount` |

Counts can change after publication. Avoid comparing posts measured at
different ages without labeling that difference.

## Separate tweet analytics from account analytics

This route measures only the cached tweets in one style profile. It does not
return follower growth, following changes, profile visits, link clicks,
audience demographics, or an account-wide Twitter analytics report.

You can analyze another public X account after caching its username. The
result covers cached public Tweets only. It does not expose private analytics.

Use [Compare Styles](/api-reference/styles/compare) for 2 writing sample sets.
That route does not fetch live engagement metrics.

## Budget a tweet analytics refresh

Each returned Tweet costs 1 credit. Check `tweetCount` through Get Style before
requesting a refresh. The route can process up to 100 cached Tweets.

Store the returned `tweetCount` with billing reconciliation. It counts metric
rows returned by this request, not the profile's lifetime Tweet total.

## Handle unavailable cached tweets

Every cached ID must still resolve as a live X Tweet. Deleted, protected, or
otherwise unavailable Tweets cannot produce a metric row.

Re-analyze the username when the cache contains stale Tweet IDs. Never replace
an unavailable Tweet ID with another post during snapshot reconciliation.

## Handle tweet analytics errors

| Status | Error | Meaning | Recovery |
| - | - | - | - |
| `200` | None | Current metrics are available | Store counts with a client timestamp. |
| `401` | `unauthenticated` | The credential is missing or invalid | Replace the API key or bearer token. |
| `402` | `insufficient_credits` | The balance cannot cover the request | Top up, then retry. |
| `404` | `style_not_found` | No valid cached profile matches `{id}` | Analyze the username first. |
| `429` | `rate_limit_exceeded` | The request exceeded the rate limit | Wait for `Retry-After`, then retry once. |

The response widget lists every status in the OpenAPI contract.
The route returns no partial-success or asynchronous job responses.

## Path parameters

<ParamField path="id" type="string" required>
  Analyzed X username whose cache contains live Tweet IDs. Xquik lowercases the
  value before an account-scoped lookup. It is not a numeric database ID.
</ParamField>

## Headers

Send `x-api-key` with an Xquik API key. OAuth clients can send a bearer token
through the `Authorization` header instead.

<ParamField header="x-api-key" type="string" required>
  Your Xquik API key. Generate one from the [dashboard](https://xquik.com/dashboard).
</ParamField>

## Response

### 200 OK

<ResponseField name="xUsername" type="string">Lowercase analyzed X username.</ResponseField>
<ResponseField name="tweetCount" type="number">Number of Tweet metric rows returned.</ResponseField>

<ResponseField name="tweets" type="object[]">
  Current Tweet text and public engagement counts.

  <Expandable title="Tweet analytics fields">
    <ResponseField name="id" type="string">Live Tweet ID.</ResponseField>
    <ResponseField name="text" type="string">Current Tweet text.</ResponseField>
    <ResponseField name="bookmarkCount" type="number">Current bookmark count.</ResponseField>
    <ResponseField name="likeCount" type="number">Current like count.</ResponseField>
    <ResponseField name="quoteCount" type="number">Current quote-post count.</ResponseField>
    <ResponseField name="replyCount" type="number">Current reply count.</ResponseField>
    <ResponseField name="retweetCount" type="number">Current repost count, excluding quotes.</ResponseField>
    <ResponseField name="viewCount" type="number">Current public view or impression count.</ResponseField>
  </Expandable>
</ResponseField>

```json theme={null}
{
  "xUsername": "xquik",
  "tweetCount": 1,
  "tweets": [
    {
      "id": "1950882898740914261",
      "text": "Export tweet replies to JSON or CSV.",
      "bookmarkCount": 87,
      "likeCount": 420,
      "quoteCount": 11,
      "replyCount": 18,
      "retweetCount": 54,
      "viewCount": 28000
    }
  ]
}
```

### 401 Unauthenticated

```json theme={null}
{ "error": "unauthenticated", "message": "Missing or invalid API key" }
```

Authentication failed. Replace the missing or invalid credential.

### 402 Insufficient credits

```json theme={null}
{
  "error": "insufficient_credits",
  "message": "Insufficient credits. Top up or subscribe to continue."
}
```

The balance cannot cover the request. Top up through the
[billing page](https://dashboard.xquik.com/en/account?tab=subscription).

### 404 Style not found

```json theme={null}
{ "error": "style_not_found", "message": "No cached style found for this username" }
```

No analyzed profile exists for this username and Xquik account. Analyze it
first.

### 429 Rate limited

```json theme={null}
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Try again later.",
  "retryAfter": 1
}
```

Too many requests. Wait for `Retry-After`, then retry once.

### How do I check tweet analytics through the API?

Analyze an X username, then call this route with its returned `xUsername`.
Store each response with your own UTC measurement timestamp.

### Does this return live Twitter analytics?

Yes. Each request refreshes current public counts for cached Tweet IDs. It
does not return private metrics or historical deltas.

### Can I check Twitter analytics for another account?

Yes, for public Tweets cached by your Xquik account. The response excludes
private account analytics, follower growth, profile visits, and link clicks.

### Is `viewCount` a unique viewer count?

No. Treat it as exposure, not unique people. Repeat views can increase the
count.

### Why does tweet analytics return 404?

The Xquik account has no analyzed profile for that lowercase username. Call
Analyze Style, then retry with the returned `xUsername`.

<Note>
  **Related.** [Get Style](/api-reference/styles/get) inspects cached Tweet IDs.
  [List Styles](/api-reference/styles/list) lists analyzed profiles.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.