# Set up Tailglow with an agent

This page is written for AI agents such as Claude Code, Codex, Cursor and Cowork that are helping someone set up Tailglow. People are welcome to read it too.

Tailglow turns the data a product sends into live charts and pages. Data arrives at a **source** and lands in **collections**. **Views** reshape it, and **metrics** count it; charts, **pages** and **monitors** are built on metrics. Every project runs on its own **server**, which Tailglow provisions and operates.

## Start by asking

Unless the person has already said, ask what they want to see first. Each answer maps to one path in step 4:

| They want                                               | Path                            |
| ------------------------------------------------------- | ------------------------------- |
| Visitors, page views and clicks in a web app            | [Web app](#web-app)             |
| Events, jobs or errors from a backend                   | [Backend](#backend)             |
| Screens and errors in a React Native or Expo app        | [React Native](#react-native)   |
| To know that a site or API is up                        | [Uptime check](#uptime-check)   |
| Data they already have: files, exports, another service | [Anything else](#anything-else) |

## 1. Sign in

```bash
npx @tailglow/cli login
```

Without a terminal attached, which is how an agent runs it, the command prints a link and a code, remembers the sign-in, and exits. Show both to the person. They sign in, or create an account if they have none (the first 3 days are free and need no card), check that the page shows the same code, and approve. Then finish signing in:

```bash
npx @tailglow/cli login --wait
```

`--wait` waits up to a minute. Exit code `75` means the person has not approved yet: run it again. Exit code `1` with status `unreachable` means the API could not be reached: the sign-in is kept, so run `login --wait` again once the connection is back. Status `consumed` means the credential was already handed out: start over with `login --new`. Any other exit code `1` means the sign-in was denied, expired or withdrawn: start over with `login`.

This signs the CLI in as the person, with what their role allows in each of their teams, starting in the team they choose. To use an API key for one team instead, with only the permissions the person picks, add `--method api-key`; that team needs a project first.

When Tailglow is at capacity, a brand-new account joins a waitlist instead of signing in, so the sign-in cannot be approved and `--wait` keeps exiting `75` until it expires. If the person sees the waitlist, say so and stop until they are let in.

The credential is saved to `~/.tailglow/config.json` and the CLI uses it from then on. You never need to see it: do not ask for it, print it, or put it in code. `tglow logout` removes it.

To keep the CLI around, install it once. It needs Node 18.3 or newer:

```bash
npm install -g @tailglow/cli
tglow whoami
```

In CI, set `TAILGLOW_API_KEY` to an API key instead of logging in.

## 2. Learn the CLI as you go

Every command has the shape `tglow <resource> <command> [flags]`, and the CLI documents itself:

```bash
tglow                                # every resource and the global flags
tglow sources                        # the commands on one resource
tglow sources create --help --json   # one command's flags, types, required fields and rules
```

Read `--help --json` before you call a command for the first time. It is generated from the same validation the API enforces, so it is always current, and its `notes` carry rules a field list cannot.

- Flags are field names in kebab-case: `time_window_minutes` is `--time-window-minutes`.
- IDs in the path are flags too: `--source-id src_x`, never a positional argument.
- Output is JSON whenever it is piped. Read `.data`, and `.pagination.next_cursor` to continue a list.
- Set the project once so you can leave it off every command: `tglow config set project prj_...`

The CLI also carries these docs, so you do not need to fetch them. `tglow docs` prints the index and `tglow docs guides/sdk` prints one page, as markdown even when piped.

## 3. Pick a project

```bash
tglow projects list
tglow projects create --name "Acme web"
tglow config set project prj_...
```

Reuse a project when the person already has one for this app. A new team's first project comes with a free trial server, which starts in the background: `tglow servers list` shows `provisioning` until it is `active`.

## 4. Connect data

Most paths need a source and an ingest key:

```bash
tglow sources create --name "Web app"
tglow ingest_keys create --source-id src_...
```

The ingest key's `url` is the address to send records to, with the key already in it. It is `null` until the project's server is active; retrieve the key again once it is. An ingest key can only write records into its own source, so it is safe in client-side code. Keep it in the app's environment configuration anyway, so it can be replaced without a code change.

### Web app

```bash
npm install @tailglow/browser
```

```javascript
import { Tailglow } from "@tailglow/browser";

// The ingest key's url, read from the app's public environment configuration.
const tg = new Tailglow({ url: TAILGLOW_INGEST_URL });

tg.track("signup", { plan: "pro" });
tg.identify("user_123");
```

Page views, clicks in elements marked `data-telemetry`, outbound clicks, uncaught errors and performance signals are collected automatically. A site without a build step can use the script tag instead: see [Drop-in script](/guides/quickstart#drop-in-script).

The SDK ignores `localhost` by default. To test locally, pass `excludeLocalhost: false` and tag the traffic, for example `context: { environment: "development" }`, so it can be filtered out of real charts.

### Backend

```bash
npm install @tailglow/core
```

```javascript
import { TailglowCore } from "@tailglow/core";

const tg = new TailglowCore({ url: process.env.TAILGLOW_INGEST_URL });

tg.track("job_completed", { job_id: "abc" });
await tg.flush();
```

Nothing is collected automatically on a backend. Flush before the process or request ends. Node 22 or newer, or Bun. Any other language can [send records over HTTP](#anything-else).

### React Native

Install `@tailglow/react-native` and follow [React Native](/guides/sdk#react-native-tailglowreact-native) in the SDK guide. The app passes the SDK its `AppState`, `Platform`, storage and navigation, which the guide shows in one file.

### Uptime check

A check needs no code. It fetches a public HTTPS address on a schedule and records whether it answered:

```bash
tglow checks create --name "Homepage" --source-id src_... --collection-slug uptime --endpoint-url https://acme.com
tglow checks test --check-id chk_...
```

`test` fetches once and stores nothing. Checks that share a collection chart together, one row each, which is what a status page is. See [Checks](/guides/checks).

### Anything else

POST JSON, JSONL, CSV, TSV or plain text to the ingest URL. Add `&collection=<name>` to choose where the records land; the collection is created the first time data arrives for it.

```bash
curl -X POST "$TAILGLOW_INGEST_URL&collection=orders" \
  -H "Content-Type: application/json" \
  -d '[{"order_id":"o_1","total":42.5,"created_at":"2026-09-27T12:00:00Z"}]'
```

`202 Accepted` means the records are stored and will be processed. Retry on `5xx` and on network errors; a `4xx` means the request itself has to change. One request can carry up to 20 MiB. See [Sending data](/guides/sending-data).

## 5. Confirm data arrived

```bash
tglow collections list --source-id src_...
tglow collections list-docs --collection-id col_...
```

The browser and backend SDKs write to collections named `events`, `errors` and `logs`. A collection appears with its first record.

## 6. Build a chart

A view is written for a settled record shape. By default Tailglow settles a shape when it arrives again at least 60 minutes after it was first seen, or when 100 or more records of it arrive in one batch. Check with:

```bash
tglow collections list-schemas --collection-id col_...
```

If the person confirms a candidate shape is real data rather than a one-off test, settle it by hand:

```bash
tglow collections update-schema --collection-id col_... --schema-version-id csv_... --state settled
```

Then create a view on the collection and declare the fields it should produce, based on the records you sampled in step 5. A metric can only use fields the view declares, and its time field has to be one of them, typed `date`. This example reads the SDK's `events` collection:

```bash
tglow views create --collection-id col_... --name "Product events" \
  --output-schema '[{"name":"event_time","type":"date"},{"name":"type","type":"string"},{"name":"plan","type":"string"}]'
```

Field types are `string`, `number`, `boolean`, `date`, `array` and `null`. Tailglow writes the transform that fills those fields from the records. Add `--hint` only for a rule it cannot read from field names, such as "classify orders above 500 as large". Choose the fields with care: once the transform is written, the view's fields cannot be changed in place.

Retrieve the view until its `status` is `active` before telling the person the chart is ready. If it is `error`, read `error_message`. If `waiting_shapes_count` is above 0, `tglow views list-deferrals --view-id view_...` shows what it is waiting on.

```bash
tglow views retrieve --view-id view_...
```

Then build up from the view. The `events` collection holds page views and clicks as well as your own events, so filter a metric to the event it counts:

```bash
tglow metrics create --view-id view_... --name "Signups per day" --timestamp-field event_time \
  --filters '?type=equals:signup' --ui-chart-value count --ui-chart-interval day
tglow pages create --name "Product"
tglow components create --page-id page_... --metric-id mtrc_...
```

Read `--help --json` on each command for the rest of its fields.

People who would rather describe a chart in words can ask the assistant in the Tailglow dashboard.

## Rules

- Ask before any delete. Without a terminal attached, `delete` runs immediately and never asks.
- Ask before changing servers or billing. Servers cost money.
- Never print, log or commit the CLI credential. Ingest keys are fine in client-side code.
- Send only fields that `--help --json` lists. The API rejects unknown fields.

## More

- The same pages without a network call: `tglow docs`, then `tglow docs <path>` for any page it lists
- Index of the docs for agents: [docs.tailglow.io/llms.txt](https://docs.tailglow.io/llms.txt)
- Every page in one file: [docs.tailglow.io/llms-full.txt](https://docs.tailglow.io/llms-full.txt)
- Any docs page as markdown: add `.md`, for example [docs.tailglow.io/guides/sdk.md](https://docs.tailglow.io/guides/sdk.md)
- Guides: [JavaScript SDK](/guides/sdk), [Sending data](/guides/sending-data), [Checks](/guides/checks), [TGL](/guides/tgl), [Metrics](/guides/metrics), [Pages](/guides/pages), [CLI](/guides/cli)
