# Traffic and analytics

Every app and static site on Nimbus Land gets three things without a script, a cookie or any setting:

- **Analytics**: who visits your site and what they look at, in plain language for site owners.
- **Traffic**, on the **Monitoring** tab: how busy your app is, how fast it responds and how often it fails, for developers.
- **Alerts**, also on **Monitoring**: an email when your site is down, when visitors are seeing errors, or when it is slow.

Visits are counted as they reach your site through Nimbus Land's edge.

## Analytics

Open your app and choose **Analytics**. You see:

- **Visitors** and **page views** for the period, with a chart of both over time.
- **Top pages**: the pages people looked at most.
- **Sources**: the websites that sent people to you. Only the site's name is kept (for example `news.example.com`). Visitors who typed your address or used a bookmark show as **Direct**.
- **Campaigns**: links you tagged yourself (below). Shown once a tagged link has been used.
- **Devices**: desktop, mobile or tablet.

Each list shows up to 10 entries. Choose **Today**, **Last 7 days** (the default), **Last 30 days** or **Last 12 months**. If the app has more than one environment, Analytics shows production first and lets you switch.

Visits are counted on every address the app answers on: its `nimbusapps.ca` address, its verified [custom domain](custom-domains.md) and that domain's `www` or root partner. If you move a custom domain to another app, past visits stay with the first app.

A page view is one web page that loaded successfully. The images, fonts and other files on the page don't count on their own.

### How visitors are counted

Nimbus Land counts visitors without cookies. For each visit it combines the visitor's network address, their type of browser, your site and a secret value that changes every day, and turns them into a scrambled number that can't be turned back into those details. Each day's secret is destroyed within 48 hours, so a visitor can't be followed from one day to the next. Network addresses are not kept in the data behind Analytics or Traffic.

As a result:

- **A person counts once per day.** Someone who visits on Monday and Tuesday counts as two visitors over the last 7 days.
- **The same person on two of your sites counts separately.**
- **People sharing a connection and browser may count as one.**
- **Automated visitors are left out** of visitors and page views: search engine crawlers, site-monitoring services and programs that don't identify as a browser. They are recognised by known patterns, so a program that imitates a browser well can slip through.

The figures won't match script-based analytics tools, which can often recognise returning visitors and filter bots in their own way. Use Analytics for trends and comparisons between periods.

### Campaigns

Tag a link you share with up to three parameters so visits from it are grouped:

```
https://example.com/spring-sale?utm_source=newsletter&utm_medium=email&utm_campaign=spring-sale
```

Visits through that link appear under **Campaigns** as `newsletter / email / spring-sale`. Each tag is kept up to 100 characters.

### What is stored

Stored: the page address without anything after the `?`, the time, the source's site name, the device type, the campaign tags, the daily scrambled number and, for Traffic, technical details such as response time. Page addresses are kept as they appear, so if yours contain a name or an account number, that is kept too.

Not stored: visitors' network addresses, the detailed browser identification string, cookies, form contents, and anything after the `?` except the three campaign tags.

Analytics is visible only to people who can already see the app. Whether you need to tell your own visitors about it or ask their consent depends on your situation; that is for you to decide.

### How long data is kept

- Visitor and page-view totals and the Analytics lists: 400 days.
- The minute-by-minute Traffic charts: 30 days.
- Detailed records of individual requests: 7 days.

Older data is removed automatically.

## Measuring visitors in the browser

Counting served pages misses what happens inside a single-page app (one page view per visit, however many screens are opened), how long visitors stay, and the speed and errors they see. The **Measure visitors in the browser** switch on the Analytics tab adds a small script (under 8 KB) that reports these from the visitor's browser. It is off by default. Members who manage the app can turn it on or off, and each change is recorded in the audit log.

- **Static sites:** the script is added to every page as it is served, within a minute. Nothing to publish.
- **Container apps:** the card shows one line to add inside `<head>` on every page. It reads **Waiting for the first visit** until the script reports, then **Working**. If your app sets a Content Security Policy, allow the host shown on the card in `script-src` and `connect-src`.

Once browser reports arrive, Analytics counts every page or screen a visitor opens, including moves inside a single-page app, and adds **Sessions** (one visit in one browser tab), **Time on site** (how long the site was visible, averaged per session) and **Goals**, for custom events your site reports:

```js
rayo.track("signup");
```

The chart marks the day measurement started, because browser and served-page counts differ (visitors with JavaScript off and some automated visitors are only in the served-page count).

The script records page views, where the visit came from, campaign tags, page title and language, time visible, custom events, Core Web Vitals, page-load timing, JavaScript errors and failed loads, a summary of the files the page loaded, and long pauses on the main thread. It sets no cookies, keeps nothing beyond the current tab (and not even that when the browser sends the Global Privacy Control signal), never sends anything after the `?` in an address, never sends what visitors type, and doesn't run in automated browsers.

Each app has a daily allowance of browser reports, 50,000 by default. Past it, Nimbus Land stops keeping per-visit detail, errors and resource lists for that app until the next UTC midnight. Totals keep updating, and your visitors are never affected.

Browser detail is kept for 7 days, hourly summaries for 30 days, and daily totals and lists for 400 days.

## Traffic on the Monitoring tab

The **Traffic** section on the **Monitoring** tab has three charts:

- **Requests per minute.**
- **Response time**: the median and the 95th percentile (the time 95% of requests were faster than).
- **Error rate**: the share of responses that were server errors (5xx).

Choose a window of 1 hour, 6 hours, 24 hours or 7 days. Unlike Analytics, these charts include automated traffic such as crawlers and site-monitoring services, so request counts are higher than page views. A new request shows up within about two minutes.

Below the charts, **recent failed requests** lists up to 20 of the newest requests that ended in a server error, with time, method, path, status and response time. It covers the last 7 days at most.

### "Detailed request records are paused"

Each app may keep up to 100,000 detailed request records per UTC day by default. Past that, detailed records stop until the next UTC day; the notice says when they resume. Your app keeps serving every visitor, and the charts and Analytics keep updating; only the recent failed requests list stops gaining entries. The allowance is a limit, not a charge.

### Browser

With browser measurement on, **Monitoring** also has a **Browser** section:

- **Core Web Vitals**: Largest Contentful Paint, Interaction to Next Paint and Cumulative Layout Shift at the 75th percentile, with the share of page views rated good, needs improvement and poor.
- **Page load phases**: median redirect, DNS, connect, TLS, request, response and load times.
- **JavaScript errors**, gathered into error groups in the **Errors** section of the same tab. See [Errors](errors.md).
- **Slowest resources**, and the **scripts behind long frames** (main-thread pauses over 50 ms).

### The health line on the Overview

A container app's **Overview** shows one line under **Running now**: how many instances are running out of how many are wanted, how many times they have restarted, and the last 24 hours of requests with the share that failed. It links to **Monitoring**. Static sites show their 7-day visitors and page views instead.

If Traffic or Analytics says the data is temporarily unavailable, your app is not affected, and recording resumes on its own.

## Alerts

Alerts are set up for you. The **Alerts** section on the **Monitoring** tab lists each one, whether it is on, its threshold, and recent incidents.

| Alert | In plain words | Exact definition | Default |
|---|---|---|---|
| **Down** | Nearly every visit is failing | At least 90% of requests over the last 3 minutes failed, with at least 5 requests. Not adjustable | On |
| **Errors** | More visits than usual are failing | 5% or more of requests over the last 5 minutes failed, with at least 20 requests and at least 3 failures. Adjustable from 1% to 50% | On |
| **Slow** | Pages take too long | The 95th-percentile response time over the last 5 minutes was 2 seconds or more, with at least 20 requests. Adjustable from 0.2 to 30 seconds | Off |
| **New error** | A kind of error your app hasn't had before | An error group seen for the first time, or a resolved one that came back. See [Errors](errors.md#the-new-error-alert) | On |

A failed request is one that ended in a server error (5xx). Down, Errors and Slow watch the **production** environment only and count all traffic, including crawlers and site-monitoring services.

### When an alert opens and closes

When the condition is met, an incident opens and you are emailed once. It closes after 5 healthy checks in a row, and you are emailed again with how long it lasted. If the site gets no visits at all for 24 hours, the incident closes as "no visits". An open incident also appears at the top of the app's **Overview**.

Alerts don't open:

- while a deploy is in progress, or for 2 minutes after it finishes;
- while the app is stopped or suspended;
- while the app has never had a healthy release (Slow still can).

Alerts are based on real visits. A site that nobody visits has nothing to measure, so it won't raise an alert even if it is down, and a very quiet site may never reach the minimum request counts.

### Who is emailed

Your organization's owners and admins get alert emails automatically. To also send alerts to a shared inbox or a webhook for your chat or on-call tool, open your organization settings, add a destination under **Notifications** and tick **Site down**, **Visitors seeing errors**, **Site slow** or **A new kind of error**. Someone whose own address is also a destination gets one copy.

At most 10 alerts are emailed per app per UTC day. Past that, incidents are still recorded and shown on **Monitoring**.

### Turning an alert off

On the **Monitoring** tab's **Alerts** section, use the switch next to an alert, and change the Errors or Slow threshold there. Turning an alert off closes its open incident. You need permission to manage the app; everyone else sees alerts read-only.

## From the CLI, the API and Claude

```sh
nimbus traffic           # requests, error rate, response times, recent failed requests
nimbus analytics         # visitors, page views, top pages, sources and devices (--period)
nimbus browser           # Core Web Vitals, page load, slowest resources
nimbus incidents         # alert rules and recent incidents
nimbus status            # a short health summary
```

The HTTP API answers `GET /api/v1/apps/:id/health`, `/traffic`, `/analytics`, `/browser` and `/incidents`, and the [Claude connector](claude.md) offers the same figures. Request paths, page URLs and referrers come from your visitors and are passed through unchanged, so treat them as untrusted data when you hand them to another program.
