> Portal Navigation:
> 
> - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version.
> - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages).
> - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`).
> - Top-level index of all portals: https://dev.wix.com/docs/llms.txt
> - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt

## Resource: Query Site Analytics

## Article: Query Site Analytics

## Article Link: https://dev.wix.com/docs/api-reference/business-management/analytics/skills/query-site-analytics.md

## Article Content:

# Query Site Analytics

This article shows how to read a site's analytics with the **Semantic Model API**. A semantic model describes one analytics subject area (such as site traffic, revenue, etc.) and defines the **measures**, **dimensions**, and **parameters** you can query.

## Prerequisites

1. The app/caller has the **Site Analytics – read** permission scope (`SCOPE.DC-ANALYTICS-AND-REPORTS.READ-SITE-ANALYTICS`).
2. A site context is available (the request is authorized against a specific site).

## Required APIs

- **Semantic Model API**: [REST](https://dev.wix.com/docs/api-reference/business-management/analytics/semantic-models/introduction.md)
- **Site Properties API** (for the site's time zone): [REST](https://dev.wix.com/docs/api-reference/business-management/site-properties/properties/get-site-properties.md)

Base path: `https://www.wixapis.com/analytics/semantic-model/v3`

| Step | Method | Endpoint |
|---|---|---|
| List models | `GET` | `/semantic-models` |
| Get model schema | `GET` | `/semantic-models/{semanticModelId}` |
| Query model data | `POST` | `/semantic-models/query-data` |

## Decision flow

Always follow **List → Get → Query**. You cannot construct a valid query without first discovering the model's field names from `Get Semantic Model`.

1. **List Semantic Models** — discover which subject areas exist and their IDs.
2. **Get Semantic Model** — inspect a model's `measures`, `dimensions`, and `parameters` to find the exact `name` values to query and their supported filters/sorting.
3. **Query Semantic Model Data** — request specific field names for a time `interval`, with optional filters, sorting, paging, and formatting.

## Before you begin (sharp edges)

- **`interval` is required on every query.** There is no way to query without a date range — omitting it fails.
- **`interval` is start-inclusive, end-exclusive (`[start, end)`).** `start` is included, `end` is not. To get all of January 2026, query `start: "2026-01-01..."` and `end: "2026-02-01..."` — you get Jan 1–31, and Feb 1 is excluded. Set `end` to the day *after* the last day you want.
- **Set `interval.timezone` to the site's time zone to match the Wix dashboard.** Analytics in the Wix business manager are bucketed by the site's time zone. If `interval.timezone` is omitted it defaults to **UTC**, so day boundaries shift and your numbers won't match what the owner sees in the dashboard (and the same goes for using a different time zone). Get the site's IANA time zone from `properties.timeZone` via [Get Site Properties](https://dev.wix.com/docs/api-reference/business-management/site-properties/properties/get-site-properties.md) (`GET https://www.wixapis.com/site-properties/v4/properties`) and pass it through.
- **Field names must come from `Get Semantic Model`.** The `fields`, `filters[].field`, and `sort.fieldName` values must exactly match a `name` returned by the model schema (e.g. `traffic.sessions_count`). Do not guess field names.
- **Field dependencies.** A field returns data only if at least one of the field names in its `dependencies` array is also included in the same query; otherwise it's **silently omitted** from results (no error). For example, a measure may only return data when a specific dimension is also requested.
- **Sorting a nullable measure — set `sort.nullsLast: true`.** `nullsLast` defaults to `false` and only affects **descending** (`DESC`) order. If a measure can return null and you sort it `DESC`, the null rows sort *first* — so a "top N" query surfaces nulls before your real values. Set `nullsLast: true` to push nulls to the end.
- **Result cap: 1,000 rows per query.** `results` is capped at 1,000 rows — paginate with `paging.offset` for larger datasets.
- **Formatting is opt-in.** Set `formattingEnabled: true` to also receive a human-readable `formattedValue` per cell (e.g. `1500` → `"$1,500.00"` or `1.5K`). Raw typed values are always returned.
- **Totals are opt-in.** Set `totalsIncluded: true` to get a `totals` row summing numeric fields across the **full (unpaginated)** result set.
- **Unique fields are not additive.** For `unique` measures (e.g. unique visitors), query the exact time range you want in a **single request** — never sum values from separate date-range queries. Uniques are deduplicated within each queried range, so adding per-range results double-counts anyone who appears in more than one range and overstates the true total.

## Step 1: List semantic models

```bash
curl -X GET \
  'https://www.wixapis.com/analytics/semantic-model/v3/semantic-models' \
  -H 'Authorization: <AUTH>'
```

Response:

```json
{
  "semanticModels": [
    { "id": "cad7fd34-2c8b-4dda-8296-3f9d47fb484d", "slug": "traffic", "description": "Site traffic", "keywords": ["sessions", "views"] }
  ]
}
```

Pick the model whose subject area matches the request, and keep its `id`.

## Step 2: Get the model schema

```bash
curl -X GET \
  'https://www.wixapis.com/analytics/semantic-model/v3/semantic-models/cad7fd34-2c8b-4dda-8296-3f9d47fb484d' \
  -H 'Authorization: <AUTH>'
```

Response shape:

```json
{
  "semanticModel": {
    "id": "string<GUID>",
    "slug": "string",
    "description": "string",
    "keywords": ["string"],
    "measures": [ "Field" ],
    "dimensions": [ "Field" ],
    "parameters": [ "Field" ]
  }
}
```

Each `Field` (in `measures`, `dimensions`, and `parameters`):

| Property | Meaning |
|---|---|
| `name` | The exact value to use in `fields`, `filters[].field`, and `sort.fieldName`. |
| `type` | `STRING`, `NUMBER`, `BOOLEAN`, `DATE`, `DATE_TIME`, `OBJECT`, or `ARRAY`. |
| `filters` | Supported filter `prefixes` (`IS`/`NOT`) and `conditions` (e.g. `EQUAL`, `RANGE_II`, `CONTAINS_ANY`). |
| `sortable` | Whether the field can be used in `sort`. |
| `enumerations` | Allowed values, for enumerated fields. |
| `dependencies` | Other field names this field needs present in the query to return data (see sharp edges). |
| `groupSlug` | Fields sharing a `groupSlug` are logically related. |
| `description` | Human-readable description of the field. |

- **Measures** are quantitative fields you aggregate (revenue, page views, order count).
- **Dimensions** are categorical fields you group by (traffic source, country, product name).
- **Parameters** are optional inputs that customize query behavior (currency, date granularity).

## Step 3: Query the model data

`POST /semantic-models/query-data` (body requires `Content-Type: application/json`).

Required body fields: `semanticModelId`, `interval`, `fields`.

```bash
curl -X POST \
  'https://www.wixapis.com/analytics/semantic-model/v3/semantic-models/query-data' \
  -H 'Authorization: <AUTH>' \
  -H 'Content-Type: application/json' \
  -d '{
  "semanticModelId": "cad7fd34-2c8b-4dda-8296-3f9d47fb484d",
  "interval": {
    "start": "2024-06-01T00:00:00.000Z",
    "end": "2025-06-01T00:00:00.000Z",
    "timezone": "America/New_York"
  },
  "fields": [
    "traffic.referrer_category_name",
    "traffic.sessions_count",
    "traffic.views_count"
  ],
  "filters": [
    {
      "field": "traffic.sessions_count",
      "condition": "GREATER_THAN",
      "values": ["100"]
    }
  ],
  "sort": {
    "fieldName": "traffic.sessions_count",
    "order": "DESC",
    "nullsLast": true
  },
  "paging": {
    "limit": 50,
    "offset": 0
  },
  "formattingEnabled": true,
  "totalsIncluded": true
}'
```

### Request fields

| Field | Required | Notes |
|---|---|---|
| `semanticModelId` | Yes | GUID from List/Get. |
| `interval` | Yes | `{ start, end }` UTC ISO date-times, plus `timezone`. Range is start-inclusive, end-exclusive (`[start, end)`) — set `end` to the day after the last day you want. Set `timezone` to the site's IANA time zone (see Time zone section) so results match the Wix dashboard; defaults to UTC when omitted. |
| `fields` | Yes | Up to 60 field `name`s from the model schema. |
| `filters` | No | Array of `{ field, values[], condition, prefix }`. `condition` defaults to `EQUAL`, `prefix` defaults to `IS`. For `RANGE_*` conditions provide exactly 2 values. |
| `sort` | No | `{ fieldName, order, nullsLast }`. `order` defaults to `ASC`; field must be `sortable`. `nullsLast` (default `false`) applies only to `DESC` order — set it to `true` when the sorted measure can contain nulls, otherwise nulls sort before real values. |
| `paging` | No | `{ limit, offset }`. Defaults: `limit` 50, `offset` 0. |
| `formattingEnabled` | No | Default `false`. Adds `formattedValue` per cell. |
| `totalsIncluded` | No | Default `false`. Adds a `totals` row. |

### Response shape

```json
{
  "results": [
    {
      "fields": {
        "traffic.referrer_category_name": { "stringValue": "Search", "formattedValue": "Search" },
        "traffic.sessions_count": { "numericValue": 1500, "formattedValue": "1.5K" }
      }
    }
  ],
  "pagingMetadata": { "count": 5, "offset": 0 },
  "totals": { "fields": { "traffic.sessions_count": { "numericValue": 9000 } } }
}
```

Each cell in `results[].fields` is a typed value — one of `numericValue`, `stringValue`, `booleanValue`, `timestampValue`, `arrayValue`, or `objectValue` — plus `formattedValue` when `formattingEnabled` is `true`. `totals` is present only when `totalsIncluded` is `true`.

## Time zone (match the Wix dashboard)

Analytics shown in the Wix business manager are aggregated by the **site's time zone**. To return numbers that match what the site owner sees, pass that time zone in `interval.timezone` on every query. **When `timezone` is omitted, the API defaults to UTC** — which shifts day boundaries and produces totals that don't line up with the dashboard (the same applies to any non-site time zone).

Get the site's time zone from **Get Site Properties**:

```bash
curl -X GET \
  'https://www.wixapis.com/site-properties/v4/properties?fields.paths=timeZone' \
  -H 'Authorization: <AUTH>'
```

The IANA time zone string is returned in `properties.timeZone`:

```json
{
  "properties": {
    "timeZone": "America/New_York"
  }
}
```

Use that value as `interval.timezone` in `Query Semantic Model Data`. The Site Properties `timeZone` reflects the site's primary business address and requires the `SITE_SETTINGS.VIEW` permission.

## Pagination

To retrieve more than 1,000 rows, page through with `offset`:

1. Request page 1 with `paging: { limit: 1000, offset: 0 }`.
2. Increment `offset` by the page size until `pagingMetadata.count` is less than the requested `limit`.

## Common Errors

| HTTP | Code | Meaning |
|---|---|---|
| 401 | `NO_ACCOUNT_IDENTITY` / `UNAUTHENTICATED` | Caller isn't authenticated; provide valid credentials. |
| 404 | `SEMANTIC_MODEL_NOT_FOUND` | The `semanticModelId` doesn't exist for this site. |

Silent gap (no error): a requested field returns no data because none of its `dependencies` were included in the query — add a dependency field and re-query.

## Best Practices

1. Always run **List → Get → Query**; never hardcode field names — read them from `Get Semantic Model`.
2. Pass the site's time zone (`properties.timeZone` from Get Site Properties) in `interval.timezone` so results match the Wix dashboard.
3. Include a field's `dependencies` in the query, or expect that field to be silently dropped.
4. Use `formattingEnabled: true` for anything shown directly to a user; keep raw values for calculations.
5. Use `totalsIncluded: true` to get period totals alongside a paged breakdown in a single call.
6. Keep `fields` minimal (projection) and paginate large result sets with `offset`.

## Related Documentation

- [Semantic Model API: Introduction](https://dev.wix.com/docs/api-reference/business-management/analytics/semantic-models/introduction.md)
- [Semantic Model API: Sample Flows](https://dev.wix.com/docs/api-reference/business-management/analytics/semantic-models/sample-flows.md)
- [List Semantic Models](https://dev.wix.com/docs/api-reference/business-management/analytics/semantic-models/list-semantic-models.md)
- [Get Semantic Model](https://dev.wix.com/docs/api-reference/business-management/analytics/semantic-models/get-semantic-model.md)
- [Query Semantic Model Data](https://dev.wix.com/docs/api-reference/business-management/analytics/semantic-models/query-semantic-model-data.md)
- [Get Site Properties](https://dev.wix.com/docs/api-reference/business-management/site-properties/properties/get-site-properties.md) (source of the site's `timeZone`)