# Zyte API stats API

> ##### TIP
> 
> For the reference documentation of the HTTP API of Zyte API itself,
> see [Zyte API reference documentation](reference.md#zapi-reference).

The [Zyte dashboard](https://app.zyte.com) has a [Stats](https://app.zyte.com/o/stats/usage) page that lets you monitor different
aspects of your Zyte API requests, including cost, response time, or features
used.

Zyte API also offers an HTTP API to query your Zyte API requests.

## Authentication

All requests require [basic authentication](https://datatracker.ietf.org/doc/html/rfc7617#section-2), with your [Zyte dashboard API
key](https://app.zyte.com/o/settings) (not your Zyte API key) as username, and no password. For example, if
your API key is `foo`, you base64-encode `foo:` as `Zm9vOg==` and send
the `Authorization` header with value `Basic Zm9vOg==`.

```none
Authorization: Basic Zm9vOg==
```

![](zyte-api/usage/images/account_settings.png)

## Basic usage

The most basic request only requires an organization ID.

To find your organization ID, open the [Zyte dashboard](https://app.zyte.com) and
copy your organization ID from the browser address bar.
For example, if the URL is `https://app.zyte.com/o/000000`,
`000000` is your organization ID.

```bash
curl \
    --user YOUR_STATS_API_KEY: \
    --compressed \
    https://zyte-api-stats.zyte.com/api/stats?organization_id=000000
```

```json
{
    "page": 1,
    "page_size": 500,
    "results": [
        {
            "billed_traffic_bytes": 0,
            "cost_microusd_avg": "1335.10",
            "cost_microusd_p80": "2040.00",
            "cost_microusd_total": "584773.00",
            "organization_id": 000000,
            "request_count": 438,
            "response_time_sec_avg": "5.49",
            "response_time_sec_p80": "6.40",
            "status_codes": [
                {
                    "code": null,
                    "count": 3
                },
                {
                    "code": 200,
                    "count": 432
                },
                {
                    "code": 404,
                    "count": 3
                }
            ]
        }
    ],
    "total_result_count": 1
}
```

> ##### NOTE
> 
> This endpoint reports costs in US dollars only, through the
> `cost_microusd_*` fields. If your organization is billed in a different
> currency, use the [multicurrency endpoint](#stats-multicurrency)
> instead; `/api/stats` rejects non-USD organizations.

## Multicurrency

The `/api/v1/stats` endpoint works like `/api/stats` but reports costs per
currency. Use it if your organization is billed in a currency other than US
dollars.

It accepts the same parameters as `/api/stats`. In each result, the scalar
`cost_microusd_*` fields are replaced by `cost_micro_*` arrays with one entry
per currency present in your usage. As with `/api/stats`, each result also
includes a [billed_traffic_bytes](#stats-billed-traffic) field.

```bash
curl \
    --user YOUR_STATS_API_KEY: \
    --compressed \
    https://zyte-api-stats.zyte.com/api/v1/stats?organization_id=000000
```

```json
{
    "page": 1,
    "page_size": 500,
    "results": [
        {
            "organization_id": 000000,
            "request_count": 438,
            "billed_traffic_bytes": 0,
            "cost_micro_total": [
                {"currency": "USD", "value": 584773},
                {"currency": "EUR", "value": 538791}
            ],
            "cost_micro_avg": [
                {"currency": "USD", "value": 1335},
                {"currency": "EUR", "value": 1230}
            ],
            "cost_micro_p80": [
                {"currency": "USD", "value": 2040},
                {"currency": "EUR", "value": 1879}
            ],
            "response_time_sec_avg": "5.49",
            "response_time_sec_p80": "6.40",
            "status_codes": [
                {
                    "code": null,
                    "count": 3
                },
                {
                    "code": 200,
                    "count": 432
                },
                {
                    "code": 404,
                    "count": 3
                }
            ]
        }
    ],
    "total_result_count": 1
}
```

Each entry of a `cost_micro_*` array has a `currency` field, a three-letter
[ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code, and a
`value` field. As with the `cost_microusd_*` fields of `/api/stats`, the
value is expressed in micro-units of the currency: divide it by 1,000,000 to get
the amount in the main unit of the currency. For example, a `value` of
`584773` for `USD` is 0.58 USD.

Only the currencies present in your usage during the selected timeframe are
included; a currency you did not use is omitted, not reported as zero.

When domain health information is requested (`include_domain_health=true`), its
monetary fields follow the same per-currency format, named `total_spent_micro_*`
and `my_avg_price_micro_*` (instead of the `*_microusd_*` fields of
`/api/stats`).

## Billed traffic

Both `/api/stats` and the [multicurrency endpoint](#stats-multicurrency)
include a `billed_traffic_bytes` field in each result: the total billed traffic
in bytes over the selected timeframe, and per domain when `groupby_domain=true`.
It is a plain integer total, not broken down by currency.

It is non-zero only for requests that trigger per-GB billing, such as those using
[ipType:residential](https://docs.zyte.com/zyte-api/usage/reference.html#operation/extract/request/ipType)
or extended geolocations; it is `0` otherwise.

## Rate limiting

The stats API has a rate limit of 20 requests per minute. Anything above that
will trigger a 429 response.

## Grafana dashboard

Follow the steps below to replicate the shown [Grafana](https://grafana.com/grafana/) dashboard to visualize data from the stats API.

1. First, install the [Infinity](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) plugin on your Grafana instance.
2. Add the newly installed data source into the [Data Sources](https://grafana.com/docs/plugins/yesoreyeram-infinity-datasource/latest/setup/configuration/) section and configure it to fetch data from [https://zyte-api-stats.zyte.com](https://zyte-api-stats.zyte.com) with [your Stats dashboard API key](#stats-authentication).
   ![](zyte-api/usage/images/infinity_auth.png)![](zyte-api/usage/images/infinity_url.png)
3. [Impot the dashboard](https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/import-dashboards/) from the file [stats_api_demo.json](https://docs.zyte.com/_static/stats_api_demo.json).
4. Paste your organization ID into the “organization_id” field as shown in the screenshot below.
   ![](zyte-api/usage/images/grafana_screenshot.png)

## Google Looker Studio dashboard

Follow the steps below to replicate the shown [Google Looker Studio](https://lookerstudio.google.com/) dashboard to visualize data from the stats API.

1. First, connect to the [Zyte API Stats Connector](https://datastudio.google.com/datasources/create?connectorId=AKfycbyh_6V56h157XDWT97HQZEyc_cQlE7bdL633-9AfUWaOWwTkHJ-UyRTMvmUVzunKm_JYQ&authuser=0).
2. It will ask for the API key - provide your [your Stats dashboard API key](#stats-authentication) (not your Zyte API key).
3. Check all of the “Allow … to be modified in reports.” checkboxes.
4. Paste your organization ID into the “organization_id” parameter.
5. Click the “Connect”, “Allow”, “Create report” and “Create report” buttons.

![](zyte-api/usage/images/lookerstudio_screenshot.png)

## Reference

```yaml
components:
  schemas:
    CurrencyValue:
      description: "A monetary amount in a single currency.\n\nUsed by the multicurrency (`/api/v1/stats`) cost fields, where each cost is reported as a list with one `CurrencyValue` entry per currency present in your usage."
      properties:
        currency:
          description: Three-letter [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code (e.g. `USD`, `EUR`, `GBP`).
          maxLength: 3
          minLength: 3
          type: string
        value:
          description: The amount, in micro-units of `currency` (divide by 1,000,000 to get the amount in the currency's main unit).
          minimum: 0
          type: number
      required:
      - currency
      - value
      type: object
    HTTPError:
      properties:
        detail:
          type: object
        message:
          type: string
      type: object
    StatsResponse:
      properties:
        page:
          minimum: 1
          type: integer
        page_size:
          maximum: 500
          minimum: 1
          type: integer
        results:
          items:
            $ref: '#/components/schemas/StatsResult'
          type: array
        total_result_count:
          minimum: 1
          type: integer
      required:
      - page
      - page_size
      - results
      - total_result_count
      type: object
    StatsResponseV1:
      properties:
        page:
          minimum: 1
          type: integer
        page_size:
          maximum: 500
          minimum: 1
          type: integer
        results:
          items:
            $ref: '#/components/schemas/StatsResultV1'
          type: array
        total_result_count:
          minimum: 0
          type: integer
      required:
      - page
      - page_size
      - results
      - total_result_count
      type: object
    StatsResult:
      properties:
        billed_traffic_bytes:
          description: "Total billed traffic in bytes over the selected timeframe (and per domain when `groupby_domain=true`).\n\nIt is non-zero only for requests that trigger per-GB billing, such as those using\n[`ipType:residential`](/zyte-api/usage/reference.md) or extended geolocations; it is `0` otherwise."
          minimum: 0
          type: integer
        cost_microusd_avg:
          minimum: 0
          type: number
        cost_microusd_p80:
          minimum: 0
          type: number
        cost_microusd_total:
          minimum: 0
          type: number
        day:
          format: date-time
          type: string
        domain:
          maxLength: 256
          minLength: 0
          type: string
        domain_health:
          description: "Domain health information. Returned only when `include_domain_health=true` and `groupby_domain=true`.\n\nIt aims to show detailed stats from your Top 100 most requested domains in the last 7 days. Domains not recently used or not within the Top 100 domains will have a `null` value. These stats are not real-time; they are calculated once every 3 hours."
          nullable: true
          type: object
          properties:
            global_avg_success_rate_24h:
              type: string
            global_avg_success_rate_7d:
              type: string
            my_avg_price_microusd_24h:
              type: string
            my_avg_price_microusd_7d:
              type: string
            my_avg_response_time_24h:
              type: string
            my_avg_response_time_7d:
              type: string
            my_requests_24h:
              type: integer
            my_requests_7d:
              type: integer
            my_success_rate_24h:
              type: string
            my_success_rate_7d:
              type: string
            status:
              type: string
              enum:
              - healthy
              - possible_misconfiguration
              - issue_under_investigation
              - possible_performance_issue
            total_spent_microusd_24h:
              type: string
            total_spent_microusd_7d:
              type: string
            total_successful_requests_24h:
              type: integer
            total_successful_requests_7d:
              type: integer
        hour:
          format: date-time
          type: string
        month:
          format: date-time
          type: string
        organization_id:
          type: integer
        request_count:
          minimum: 1
          type: integer
        response_time_sec_avg:
          minimum: 0
          type: number
        response_time_sec_p80:
          minimum: 0
          type: number
        status_codes:
          items:
            properties:
              code:
                nullable: true
                type: integer
              count:
                minimum: 0
                type: integer
            type: object
          type: array
        year:
          format: date-time
          type: string
      required:
      - billed_traffic_bytes
      - cost_microusd_avg
      - cost_microusd_p80
      - cost_microusd_total
      - organization_id
      - request_count
      - response_time_sec_avg
      - response_time_sec_p80
      type: object
    StatsResultV1:
      properties:
        billed_traffic_bytes:
          description: "Total billed traffic in bytes over the selected timeframe (and per domain when `groupby_domain=true`). It is a plain integer total, not broken down by currency.\n\nIt is non-zero only for requests that trigger per-GB billing, such as those using\n[`ipType:residential`](/zyte-api/usage/reference.md) or extended geolocations; it is `0` otherwise."
          minimum: 0
          type: integer
        cost_micro_avg:
          description: Average cost per request, with one entry per currency.
          items:
            $ref: '#/components/schemas/CurrencyValue'
          type: array
        cost_micro_p80:
          description: 80th percentile cost per request, with one entry per currency.
          items:
            $ref: '#/components/schemas/CurrencyValue'
          type: array
        cost_micro_total:
          description: Total cost, with one entry per currency.
          items:
            $ref: '#/components/schemas/CurrencyValue'
          type: array
        day:
          format: date-time
          type: string
        domain:
          maxLength: 256
          minLength: 0
          type: string
        domain_health:
          description: "Domain health information. Returned only when `include_domain_health=true` and `groupby_domain=true`.\n\nIt aims to show detailed stats from your Top 100 most requested domains in the last 7 days. Domains not recently used or not within the Top 100 domains will have a `null` value. These stats are not real-time; they are calculated once every 3 hours.\n\nMonetary fields (`total_spent_micro_*`, `my_avg_price_micro_*`) are reported as currency arrays, with one entry per currency."
          nullable: true
          type: object
          properties:
            global_avg_success_rate_24h:
              type: string
            global_avg_success_rate_7d:
              type: string
            my_avg_price_micro_24h:
              description: Average price per request in the last 24 hours, with one entry per currency.
              items:
                $ref: '#/components/schemas/CurrencyValue'
              type: array
            my_avg_price_micro_7d:
              description: Average price per request in the last 7 days, with one entry per currency.
              items:
                $ref: '#/components/schemas/CurrencyValue'
              type: array
            my_avg_response_time_24h:
              type: string
            my_avg_response_time_7d:
              type: string
            my_requests_24h:
              type: integer
            my_requests_7d:
              type: integer
            my_success_rate_24h:
              type: string
            my_success_rate_7d:
              type: string
            status:
              type: string
              enum:
              - healthy
              - possible_misconfiguration
              - issue_under_investigation
              - possible_performance_issue
            total_spent_micro_24h:
              description: Total amount spent in the last 24 hours, with one entry per currency.
              items:
                $ref: '#/components/schemas/CurrencyValue'
              type: array
            total_spent_micro_7d:
              description: Total amount spent in the last 7 days, with one entry per currency.
              items:
                $ref: '#/components/schemas/CurrencyValue'
              type: array
            total_successful_requests_24h:
              type: integer
            total_successful_requests_7d:
              type: integer
        hour:
          format: date-time
          type: string
        month:
          format: date-time
          type: string
        organization_id:
          type: integer
        request_count:
          minimum: 1
          type: integer
        response_time_sec_avg:
          minimum: 0
          type: number
        response_time_sec_p80:
          minimum: 0
          type: number
        status_codes:
          items:
            properties:
              code:
                nullable: true
                type: integer
              count:
                minimum: 0
                type: integer
            type: object
          type: array
        year:
          format: date-time
          type: string
      required:
      - billed_traffic_bytes
      - organization_id
      - request_count
      - response_time_sec_avg
      - response_time_sec_p80
      type: object
    ValidationError:
      properties:
        detail:
          properties:
            <location>:
              properties:
                <field_name>:
                  items:
                    type: string
                  type: array
              type: object
          type: object
        message:
          type: string
      type: object
  securitySchemes:
    BasicAuth:
      scheme: basic
      type: http
info:
  title: APIFlask
  version: 0.1.0
openapi: 3.0.3
paths:
  /api/stats:
    get:
      parameters:
      - in: query
        name: organization_id
        required: true
        schema:
          type: integer
      - in: query
        name: page
        required: false
        schema:
          default: 1
          minimum: 1
          type: integer
      - in: query
        name: page_size
        required: false
        schema:
          default: 500
          maximum: 500
          minimum: 1
          type: integer
      - description: "The start date and time in\n[ISO 8601-1](https://en.wikipedia.org/wiki/ISO_8601) format (e.g. `2024-09-10T00:00:00Z`).\n\nIt defaults to 7 days in the past."
        in: query
        name: start_time
        required: false
        schema:
          format: date-time
          type: string
      - description: "The end date and time in\n[ISO 8601-1](https://en.wikipedia.org/wiki/ISO_8601) format (e.g. `2024-09-17T00:00:00Z`).\n\nIt defaults to the current date and time."
        in: query
        name: end_time
        required: false
        schema:
          format: date-time
          type: string
      - in: query
        name: domains
        required: false
        schema:
          maxLength: 64
          minLength: 0
          type: string
      - in: query
        name: apikey_labels
        required: false
        schema:
          maxLength: 64
          minLength: 0
          type: string
      - in: query
        name: response_codes
        required: false
        schema:
          maxLength: 64
          minLength: 0
          type: string
      - in: query
        name: requested_features
        required: false
        schema:
          enum:
          - actions
          - browserHtml
          - fileDownload
          - httpResponseBody
          - networkCapture
          - screenshot
          - sessionContext
          - extendedGeolocation
      - in: query
        name: extraction_type
        required: false
        schema:
          enum:
          - article
          - articleList
          - articleNavigation
          - forumThread
          - jobPosting
          - jobPostingNavigation
          - pageContent
          - product
          - productList
          - productNavigation
          - serp
      - in: query
        name: extraction_from
        required: false
        schema:
          enum:
          - httpResponseBody
          - browserHtml
      - description: "Filter requests by\n[tags](/zyte-api/usage/reference.md).\n \nIt must be a comma-separated list of values, where each value can be:\n \n- A key-value pair separated by a colon, i.e. ``<tag>:<value>``, to include only\nrequests where the specified tag has the specified value.\n- A tag, to include only requests where the specified tag exists.\n\nOnly requests that match *all* the specified tag filters will be\nincluded in the results."
        in: query
        name: tags
        required: false
        schema:
          maxLength: 64
          minLength: 0
          type: string
      - in: query
        name: groupby_time
        required: false
        schema:
          default:
          enum:
          - hour
          - day
          - month
          - year
          - 
          nullable: true
          type: string
      - description: "Group results by domain.\n\nWhen set to `true`, the response will include a `domain` field for each result."
        in: query
        name: groupby_domain
        required: false
        schema:
          default: false
          type: boolean
      - description: "Include domain health information in the response.\n\nRequires `groupby_domain=true`. If `include_domain_health=true` is specified without `groupby_domain=true`, a validation error will be returned."
        in: query
        name: include_domain_health
        required: false
        schema:
          default: false
          type: boolean
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsResponse'
          description: Successful response
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Authentication error
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
          description: Validation error
      security:
      - BasicAuth: []
      summary: Stats
  /api/v1/stats:
    get:
      description: "Same as [Stats](#operation/stats), but with multicurrency support.\n \nCost fields are returned as arrays with one entry per currency present in your usage (`cost_micro_total`, `cost_micro_avg`, `cost_micro_p80`), and an additional `billed_traffic_bytes` field is included.\n\nUse this endpoint if your organization is billed in a currency other than USD; the [Stats](#operation/stats) endpoint reports costs in USD only and rejects non-USD organizations."
      parameters:
      - in: query
        name: organization_id
        required: true
        schema:
          type: integer
      - in: query
        name: page
        required: false
        schema:
          default: 1
          minimum: 1
          type: integer
      - in: query
        name: page_size
        required: false
        schema:
          default: 500
          maximum: 500
          minimum: 1
          type: integer
      - description: "The start date and time in\n[ISO 8601-1](https://en.wikipedia.org/wiki/ISO_8601) format (e.g. `2024-09-10T00:00:00Z`).\n\nIt defaults to 7 days in the past."
        in: query
        name: start_time
        required: false
        schema:
          format: date-time
          type: string
      - description: "The end date and time in\n[ISO 8601-1](https://en.wikipedia.org/wiki/ISO_8601) format (e.g. `2024-09-17T00:00:00Z`).\n\nIt defaults to the current date and time."
        in: query
        name: end_time
        required: false
        schema:
          format: date-time
          type: string
      - in: query
        name: domains
        required: false
        schema:
          maxLength: 64
          minLength: 0
          type: string
      - in: query
        name: apikey_labels
        required: false
        schema:
          maxLength: 64
          minLength: 0
          type: string
      - in: query
        name: response_codes
        required: false
        schema:
          maxLength: 64
          minLength: 0
          type: string
      - in: query
        name: requested_features
        required: false
        schema:
          enum:
          - actions
          - browserHtml
          - fileDownload
          - httpResponseBody
          - networkCapture
          - screenshot
          - sessionContext
          - extendedGeolocation
      - in: query
        name: extraction_type
        required: false
        schema:
          enum:
          - article
          - articleList
          - articleNavigation
          - forumThread
          - jobPosting
          - jobPostingNavigation
          - pageContent
          - product
          - productList
          - productNavigation
          - serp
      - in: query
        name: extraction_from
        required: false
        schema:
          enum:
          - httpResponseBody
          - browserHtml
      - description: "Filter requests by\n[tags](/zyte-api/usage/reference.md).\n \nIt must be a comma-separated list of values, where each value can be:\n \n- A key-value pair separated by a colon, i.e. ``<tag>:<value>``, to include only\nrequests where the specified tag has the specified value.\n- A tag, to include only requests where the specified tag exists.\n\nOnly requests that match *all* the specified tag filters will be\nincluded in the results."
        in: query
        name: tags
        required: false
        schema:
          maxLength: 64
          minLength: 0
          type: string
      - in: query
        name: groupby_time
        required: false
        schema:
          default:
          enum:
          - hour
          - day
          - month
          - year
          - 
          nullable: true
          type: string
      - description: "Group results by domain.\n\nWhen set to `true`, the response will include a `domain` field for each result."
        in: query
        name: groupby_domain
        required: false
        schema:
          default: false
          type: boolean
      - description: "Include domain health information in the response.\n\nRequires `groupby_domain=true`. If `include_domain_health=true` is specified without `groupby_domain=true`, a validation error will be returned."
        in: query
        name: include_domain_health
        required: false
        schema:
          default: false
          type: boolean
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatsResponseV1'
          description: Successful response
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPError'
          description: Authentication error
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
          description: Validation error
      security:
      - BasicAuth: []
      summary: Stats V1
servers:
- name: Production Server
  url: https://zyte-api-stats.zyte.com
```
