<!-- https://developers.silktide.com/v1/analytics/audience/get-countries | Analytics / Audience -->

# List the countries visitors came from

`GET /v1/results/analytics/countries`

Lists the countries visits came from, with each country's visitors and page views, most visitors first. It is a [table](https://developers.silktide.com/v1/concepts/tables.md): choose its columns, sort it, search it by country name or code, and page through it.

Visits whose country could not be worked out are left out, so the rows can add up to less than the period's totals.

With `previousPeriod=1`, each row also carries its figures for the period before, and a country that had no visits then reads `0`. The comparison needs a period with a start: with `all` it is left out. When you send `columns`, name the `previous…` columns you want too.

Columns you choose with `columns` always come back with `countryCode`. Send `sort` with `columns`, naming one of them.

Narrow other Analytics queries to one country with `filters[countryCode]=is:GB`.

## Request

### Query parameters

- `view` (string, optional, matches `^(all|[1-9]\d*)$`): The analytics view to read: its id, the number after `/analytics/` in its address in Silktide, or `all` for all of the account's analytics. Send this or `websiteId`.
- `websiteId` (integer, optional, at least 1): Instead of `view`, a website whose analytics to read. The website must have Analytics set up.
- `sectionId` (integer, optional): With `websiteId`, a section of the website. Defaults to `0`, the whole website.
- `period` (string, optional): The date range. Defaults to `all`. The spaced forms (`-7 days`, `month to date`) are older names that keep working. `custom` needs `from` and `to`. One of: `all`, `today`, `last-7-days`, `last-30-days`, `last-90-days`, `month-to-date`, `last-month`, `year-to-date`, `last-12-months`, `custom`, `-7 days`, `-30 days`, `-90 days`, `-1 month`, `month to date`, `year to date`, `-12 months`.
- `from` (string, optional): With `period=custom`, the first day, such as `2026-10-01`.
- `to` (string, optional): With `period=custom`, the last day.
- `timezone` (string, optional): The IANA time zone days are read in, such as `America/New_York`. Defaults to `UTC`.
- `filters` (map of strings, optional): Only visits matching every filter, keyed by what is filtered: `filters[url]=contains:/blog`. Each value is `{operator}:{value}`, with operator `is`, `not`, `contains`, `starts`, `gt` or `lt`. Keys include `url`, `hostName`, `entryUrl`, `exitUrl`, `event`, `outgoingUrl`, `referrer`, `source`, `medium`, `campaign`, `content`, `term`, `countryCode`, `regionCode`, `language`, `deviceType` (`desktop`, `tablet` or `mobile`), `operatingSystem` and `browser`.
- `columns` (string, optional): The columns to return, comma-separated, such as `url,pageViews`. Left out, the table's default columns. Send a string even in a JSON body: an array is ignored.
- `sort` (string, optional): The column to sort by, then `:a` for ascending or `:d` for descending, such as `pageViews:d`. Left out, the table's own order.
- `search` (string, optional): Only rows matching this text. What it searches depends on the table, most often the URL or title.
- `page` (integer, optional, at least 1): The page of rows to return, from `1`. Defaults to `1`.
- `rowsPerPage` (integer, optional, at least 1): How many rows a page holds. Defaults to `100`.
- `previousPeriod` (string, optional): `1` to add the figures of the period before, the same length and ending where this one starts, as `previous…` fields. Left out or `0`, none. Needs a `period` with a start: with `all`, nothing is added. One of: `0`, `1`.

## Response

Status `200`.

- `result` (object, required): The answer.
  - `page` (integer, required, at least 1): The page returned. Not always the page asked for, when that was out of range.
  - `minPage` (integer, required, at least 1): The first page. Always `1`.
  - `maxPage` (integer, required): The last page at this `rowsPerPage`. With no rows, `0` or `1` depending on the table.
  - `numRows` (integer, required): How many rows there are across every page.
  - `rowsPerPage` (integer, required, at least 1): How many rows a page holds.
  - `rows` (list of objects, required): The rows on this page.
    - `countryCode` (string, required): The country, as its two-letter ISO 3166 code, such as `GB`. Always present.
    - `countryName` (string, optional): The country's name in English. The code when Silktide has no name for it. Absent when `columns` leaves it out.
    - `visitors` (integer, optional): Unique visitors from the country. Absent when `columns` leaves it out.
    - `pageViews` (integer, optional): Page views from the country. Absent when `columns` leaves it out.
    - `previousVisitors` (integer, optional): Unique visitors from the country in the period before. Only with `previousPeriod=1` and a period other than `all`. With `columns`, only when named there.
    - `previousPageViews` (integer, optional): Page views from the country in the period before. Only with `previousPeriod=1` and a period other than `all`. With `columns`, only when named there.
- `selector` (string, required): The query that answered, as its path: `/v1/results/scores`.
- `duration` (number, required): Seconds Silktide took to answer.

## Errors

| Status | Type | When |
| --- | --- | --- |
| 404 | `ModelNotFound` | No view or website with that id exists in the account, or the API key's user cannot see it. |
| 403 | `AccessDenied` | The API key's user cannot read that analytics view. |
| 200 | `ModelNotFound` | The website has no Analytics set up. The body is an error despite the status. |
| 200 | `InvalidRequest` | Neither `view` nor `websiteId` was sent. The error's own `status` is `400` and `properties.field` is `view`. The body is an error despite the status. |
| 200 | `InvalidArgument` | A filter names a key or operator Analytics does not know. The body is an error despite the status. |
| 200 | `InvalidArgument` | `period` is not one of its values, or is `custom` without both `from` and `to`. The body is an error despite the status. |
| 401 | `NotLoggedIn` | No API key was sent, or it is not a key for this region. |
| 429 | `TooManyRequests` | Too many requests to this path in five seconds. Retry after the number of seconds in the `Retry-After` header, which `properties.retryAfter` repeats. |
| 503 | - | Silktide is busy. Retry after the number of seconds in the `Retry-After` header. |

## Access

- Permission: View analytics view (View all analytics for `view=all`)
- Plan feature: none
- Edition: Silktide 4 and Silktide 5
- Cost: free
- Stability: stable, since 1.0.0

## Example: The top countries

```bash
curl "https://api.eu.silktide.com/v1/results/analytics/countries?view=all&rowsPerPage=3" \
  -H "Authorization: silktide token=$SILKTIDE_API_KEY"
```

Response:

```json
{
  "result": {
    "page": 1,
    "minPage": 1,
    "maxPage": 4,
    "numRows": 10,
    "rowsPerPage": 3,
    "rows": [
      {
        "countryName": "United States",
        "countryCode": "US",
        "pageViews": 412,
        "visitors": 168
      },
      {
        "countryName": "Ireland",
        "countryCode": "IE",
        "pageViews": 353,
        "visitors": 126
      },
      {
        "countryName": "United Kingdom",
        "countryCode": "GB",
        "pageViews": 268,
        "visitors": 125
      }
    ]
  },
  "selector": "/v1/results/analytics/countries",
  "duration": 0.021
}
```

## Example: Page views by country in October, against September

```bash
curl "https://api.eu.silktide.com/v1/results/analytics/countries?view=all&period=custom&from=2026-10-01&to=2026-10-31&columns=countryName%2CpageViews%2CpreviousPageViews&sort=pageViews%3Ad&previousPeriod=1&rowsPerPage=2" \
  -H "Authorization: silktide token=$SILKTIDE_API_KEY"
```

Response:

```json
{
  "result": {
    "page": 1,
    "minPage": 1,
    "maxPage": 5,
    "numRows": 10,
    "rowsPerPage": 2,
    "rows": [
      {
        "countryName": "Ireland",
        "countryCode": "IE",
        "pageViews": 243,
        "previousPageViews": 110
      },
      {
        "countryName": "United States",
        "countryCode": "US",
        "pageViews": 202,
        "previousPageViews": 210
      }
    ]
  },
  "selector": "/v1/results/analytics/countries",
  "duration": 0.021
}
```
