# Remembered visitors

> The API operations about remembered visitors, each with its input, its output and an example.

The operations about remembered visitors. Each one is a `POST` with a JSON object as its body: [Making a request](/docs/api#start) has the rules they share.

## Remembered visitor

`POST /api/v1/visitors.get` · Read

One remembered visitor of one site over time: the profile (first and latest visit, number of visits, the places, devices and sources the visits came with, and how many visits completed a conversion goal) and the journey, the visits newest first, each with its page views and custom events. Get the siteId from sites.list and the visitorKey from visitors.list, or from remembered.visitorKey of realtime.visitor. The profile's conversions and its three lists cover the newest 200 visits, and basedOnVisits says how many that was. A visit of the journey lists at most 50 page views and 50 custom events, the oldest ones. The journey pages by cursor: limit visits per page (20 unless set, 50 at most) and journey.nextCursor; send that as cursor for older visits, until it is null. Every page repeats the profile. A cursor this list did not issue answers 400 invalid_cursor. A key the site has no visitor for answers 404 not_found; a key is only valid on the site it came from, so the key of a visitor of another site is not found either. No row names a person: names and pictures are generated from a random id; a profile is a random id, places, devices and pages. There is no name, no email and no address in it. While the switch is off for the site the answer is 409 feature_off: "Remember returning visitors is off for this site. An owner or admin can switch it on under Settings, Visitors." That is not a missing site, and switching it on is done in the dashboard only. Answers 402 workspace_locked while the workspace's dashboards are locked.

Needs a token with the Read permission. Answers 402 while the dashboards of the workspace are locked.

### Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `siteId` | string | required | The site id, from sites.list. |
| `visitorKey` | string | required | The id of the visitor on this site, 16 hex characters: visitorKey of a visitors.list row. |
| `cursor` | string, at most 200 characters | optional | Where the journey continues: journey.nextCursor of the page before. Leave it out for the newest visits. |
| `limit` | integer, 1 to 50 | optional | Visits of the journey per page, 1 to 50. 20 when left out. |

### Output

| Field | Type | Present | Description |
| --- | --- | --- | --- |
| `profile` | object | always | The visitor: the fields of a visitors.list row, plus conversions, the places, devices and sources of the visits, and basedOnVisits, the number of newest visits those four cover. |
| `journey` | object | always | One page of the visits, newest first. Each visit has visitId, startedAt and endedAt in milliseconds since 1970 UTC, its page views (pages) and custom events (events) oldest first, its source, place and device, and converted. nextCursor continues with older visits; null on the last page. |

### Example

**curl**

```bash
curl -s -X POST https://clearsaga.com/api/v1/visitors.get \
  -H "Authorization: Bearer $CLEARSAGA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"siteId":"site_abc123def456","visitorKey":"0123456789abcdef"}'
```

**CLI**

```bash
clearsaga visitors get --input '{"siteId":"site_abc123def456","visitorKey":"0123456789abcdef"}'
```

**MCP**

```text
Tool: visitors_get
Arguments: {"siteId":"site_abc123def456","visitorKey":"0123456789abcdef"}
```

Run `clearsaga help visitors get` for one flag per field.

## List remembered visitors

`POST /api/v1/visitors.list` · Read

The remembered visitors of one site, the one seen latest first: for each, a key, when the first and the latest remembered visit began, how many visits, and the place, device and source of the latest visit. Get the siteId from sites.list first. It pages by cursor: the answer holds limit rows (50 unless set, 100 at most) and nextCursor; send that as cursor for the next page, until it is null. A cursor this list did not issue answers 400 invalid_cursor. There is no total, no range and no filter: the list is every visitor the site remembers. A visitor stays on the list until 13 months after the latest visit, or until the site owner deletes them in the dashboard. For the pages and events of one visitor call visitors.get with the visitorKey; for totals of a period call visitors.summary. No row names a person: names and pictures are generated from a random id; a profile is a random id, places, devices and pages. There is no name, no email and no address in it. While the switch is off for the site the answer is 409 feature_off: "Remember returning visitors is off for this site. An owner or admin can switch it on under Settings, Visitors." That is not a missing site, and switching it on is done in the dashboard only. Answers 402 workspace_locked while the workspace's dashboards are locked.

Needs a token with the Read permission. Answers 402 while the dashboards of the workspace are locked.

### Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `siteId` | string | required | The site id, from sites.list. |
| `cursor` | string, at most 200 characters | optional | Where to continue: the nextCursor of the page before. Leave it out for the visitors seen latest. |
| `limit` | integer, 1 to 100 | optional | Rows per page, 1 to 100. 50 when left out. |

### Output

| Field | Type | Present | Description |
| --- | --- | --- | --- |
| `rows` | array of object | always | One row per remembered visitor, the one seen latest first: visitorKey (the id for visitors.get), persona (a seed for a generated name), firstSeen and lastSeen (when the first and the latest remembered visit began), visitCount, and the place, device, browser, system and source of the latest visit. |
| `nextCursor` | string \| null | always | Send it as cursor for the next page. Null on the last page. |

### Example

**curl**

```bash
curl -s -X POST https://clearsaga.com/api/v1/visitors.list \
  -H "Authorization: Bearer $CLEARSAGA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"siteId":"site_abc123def456"}'
```

**CLI**

```bash
clearsaga visitors list --input '{"siteId":"site_abc123def456"}'
```

**MCP**

```text
Tool: visitors_list
Arguments: {"siteId":"site_abc123def456"}
```

Run `clearsaga help visitors list` for one flag per field.

## Returning visitors summary

`POST /api/v1/visitors.summary` · Read

How many visits of one site and period came from remembered visitors, how many of those were first and returning visits, how many distinct visitors were new and returning, and how many visits were not remembered, with the same numbers for the comparison period. It only has numbers for a site that switched "Remember returning visitors" on, which sets a cookie with a random id in the browser of a visitor who agreed. Get the siteId from sites.list first; sites.get says whether the switch is on (remembersVisitors). The words: a visit is returning when the same remembered visitor had an earlier remembered visit, however long ago within the time data is kept, so somebody who comes back after a break of 30 minutes or after midnight is returning within the hour. A visitor is a distinct remembered visitor with a visit in the period. A new visitor is one whose first remembered visit is in the period. Not remembered counts the visits without a remembered visitor: no consent, no answer yet, the light script, a page on plain http, or a browser that no longer had the cookie. A browser that sends Global Privacy Control or Do Not Track is not counted at all, here or anywhere else. The honest limit, also in the answer as limits: the cookie lasts up to 400 days, but Safari and every browser on an iPhone or iPad delete it after 7 days without a visit, and after 1 day when the visitor arrived through an ad click. A person who comes back later than that is counted as a new visitor. It takes the site and a period with its comparison, and no filters. No row names a person: names and pictures are generated from a random id; a profile is a random id, places, devices and pages. There is no name, no email and no address in it. While the switch is off for the site the answer is 409 feature_off: "Remember returning visitors is off for this site. An owner or admin can switch it on under Settings, Visitors." That is not a missing site, and switching it on is done in the dashboard only. Answers 402 workspace_locked while the workspace's dashboards are locked.

Needs a token with the Read permission. Answers 402 while the dashboards of the workspace are locked.

### Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `siteId` | string | required | The site id, from sites.list. |
| `range` | "today" \| "yesterday" \| "30m" \| "12h" \| "24h" \| "week" \| "7d" \| "30d" \| "60d" \| "90d" \| "mtd" \| "ytd" \| "12mo" \| "all" \| "custom" | optional | The period to report on: one of today, yesterday, 30m, 12h, 24h, week, 7d, 30d, 60d, 90d, mtd, ytd, 12mo, all. Left out, the workspace's default range is used (30d unless it was changed). For exact dates send from and to and leave range out (custom is accepted with them and means the same). A preset together with dates answers 400. |
| `from` | string | optional | First day of a custom period, YYYY-MM-DD in the site's time zone. Send it together with to: one without the other answers 400, and so does a day that does not exist or a from after to. A day after today is read as today; window in the answer shows the period that was used. |
| `to` | string | optional | Last day of a custom period, inclusive, YYYY-MM-DD in the site's time zone. Send it together with from. |
| `compare` | "prev" \| "week" \| "month" \| "quarter" \| "year" \| "custom" \| "off" | optional | What the period is compared with: prev (the period just before, the default), week, month, quarter or year earlier, custom (cfrom and cto are then required), or off for no comparison. The range all never has a comparison. |
| `cfrom` | string | optional | First day of a custom comparison period, YYYY-MM-DD. Required with compare set to custom, where a day that does not exist or a cfrom after cto answers 400. |
| `cto` | string | optional | Last day of a custom comparison period, inclusive, YYYY-MM-DD. Required with compare set to custom. |

### Output

| Field | Type | Present | Description |
| --- | --- | --- | --- |
| `serverNow` | number | always | The clock the period was resolved with: the start of the next whole minute, milliseconds since 1970 UTC. |
| `serverTime` | number | always | When the answer was built, milliseconds since 1970 UTC. |
| `window` | object | always | The period the numbers cover: from and to in milliseconds since 1970 UTC (to is exclusive), the time zone, a label and the bucket size. |
| `compare` | object \| null | always | The comparison period in the same form, or null when there is none. |
| `rawFrom` | number \| null | always | The earliest time detailed data is kept from, or null when nothing was trimmed. |
| `truncated` | boolean | always | True when a filtered answer could only cover the part of the period that still has detailed data. |
| `remembered` | object | always | The remembered visits of the period, counted by when the visit began: visits, firstVisits and returningVisits (they add up to visits), and the distinct visitors behind them: visitors, newVisitors and returningVisitors. |
| `notRemembered` | object | always | visits: the visits of the period without a remembered visitor: the visitor gave no consent or has not answered yet, the site runs the light script, or the browser no longer had the cookie. Such a visit is counted like on a site that remembers nobody. |
| `previous` | object \| null | always | The same numbers for the comparison period (remembered and notRemembered), or null when there is no comparison. |
| `limits` | object | always | How long a browser keeps the cookie after a visit, in days: maxAgeDays at most, safariDays in Safari and in every browser on an iPhone or iPad, adClickDays in those browsers when the visitor arrived through an ad click. A visitor who comes back later than that counts as new. |

### Example

**curl**

```bash
curl -s -X POST https://clearsaga.com/api/v1/visitors.summary \
  -H "Authorization: Bearer $CLEARSAGA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"siteId":"site_abc123def456"}'
```

**CLI**

```bash
clearsaga visitors summary --input '{"siteId":"site_abc123def456"}'
```

**MCP**

```text
Tool: visitors_summary
Arguments: {"siteId":"site_abc123def456"}
```

Run `clearsaga help visitors summary` for one flag per field.
