# An agent's first Beam analysis

Start with the API base `https://beam.experiment.sh` and a Beam API key. A secret alone cannot reliably identify its service URL; use **Copy agent setup** when creating a key to pass both together. Existing keys work unchanged. `GET /api/v1` is a public entry point with the authentication format and links. All data endpoints require `Authorization: Bearer <key>`.

## Produce a useful first report without business context

1. Read `/api/v1/metadata`, including its `analysis_guide`, `server_time`, and `recommended_periods`. The recommended windows are adjacent completed 28-day UTC periods.
2. List `/api/v1/websites`, following pagination. Report which workspace and domain you choose. With several sites and no goal, summarize the inventory and investigate the most recently active site; do not silently combine unrelated sites.
3. `POST /api/v1/coverage` with that domain filter. Check the observed date bounds, days with events, and missing session/domain identifiers. Flag a comparison window that begins before the first observed event. A quiet site may legitimately have an old last event; this is not proof of an outage.
4. Discover `event` values. `pageviews` counts all stored matching events, following the dashboard convention. Add `event is page_view` when you intend a page-view-only analysis and that event is present.
5. `POST /api/v1/compare` with the domain/event filters. Its default is the latest 28 completed UTC days versus the preceding 28 days. Report absolute counts, relative changes, baseline size, and percentage-point changes in bounce rate.
6. Fetch a daily time series with the same explicit dates and `fill: "zero"`. Inspect whether a trend is gradual, isolated to a few days, or driven by a partial bucket. Compare like weekdays and equal-length periods where appropriate.
7. Investigate referrer, page, device, geography, and UTM campaign breakdowns. Query the same dimensions and filters for both periods. Follow pagination when matching segments, since a site can enter or leave a top-N list. Use `min_visits` before ranking rates; 50 is a practical screening example, not a statistical-significance guarantee.
8. Give a concise report: chosen scope, period, observed coverage, main changes, supporting segments, sample sizes, caveats, and suggested follow-up questions. Business goals and causal explanations are unknown unless supplied; do not invent them.

## Measurement rules that change the conclusions

- **Sessions are not people.** The current collector groups by workspace token, IP, and user agent with a rolling 30-minute inactivity timeout. Its `uid` is a hash of `session_id`, not an independent persistent visitor ID. Cache failures can split sessions. Historical imports may use different conventions.
- **Filters operate on events first.** A page filter makes bounce rate the proportion of sessions with one matching event on that page. It does not measure whole-session landing-page bounce. Duration is the first-to-last matching event, not measured time spent reading a page.
- **Rates need denominators.** Do not average subgroup bounce rates or average durations without weighting. Request an overall summary. Rates and durations returned as zero when visits is zero are placeholders and should not be interpreted as observations. The comparison endpoint returns null changes for these metrics when either period has no sessions.
- **Sessions are not additive across segments.** A session can appear in multiple time buckets, pages, or dimension values. Sum pageviews when the groups form a disjoint event partition; do not sum segmented visits and label the result overall distinct sessions.
- **Attribution is session-initial in the current collector.** Referrer and UTM values are carried from the session's initial values. `Direct` is a referrer value; missing UTM fields commonly use the empty string. Null and empty string are distinct; discover actual values for retained data.
- **Device and location are approximations.** Device Size is based on viewport width: Mobile below 576px, Tablet below 992px, Laptop below 1440px, Desktop otherwise. Browser/OS come from user-agent parsing and geography from IP lookup.
- **Missing events are unknowable from aggregates alone.** The collector attempts crawler exclusion; blockers, failed requests, imports, cache failures, and late arrivals can change observations. No guaranteed ingestion watermark, retention duration, or instrumentation uptime is available.
- **Zero filling does not certify tracking.** `observed: false` means the backend returned no matching event bucket. A zero-filled day may be quiet or may have missing collection. `incomplete: true` means a requested boundary cuts the bucket, including a partial first bucket.
- **Comparisons are descriptive.** A zero baseline makes percent change undefined (`null`), even for 0 → 0. Bounce-rate absolute changes use percentage points. Small samples are noisy; correlations and traffic changes do not establish causation.

## Worked requests

Read metadata and select a domain from the website inventory; substitute it for `example.com` below.

```json
{"filters":[{"field":"domain","operator":"is","value":"example.com"}]}
```

Send that body to `/api/v1/coverage`, then `/api/v1/compare` for the default completed-period comparison.

For the time series, copy the comparison's `meta.current.from` and `meta.current.to`:

```json
{"report":"timeseries","from":"2026-08-11","to":"2026-09-08","granularity":"day","fill":"zero","filters":[{"field":"domain","operator":"is","value":"example.com"}]}
```

Find high-bounce referrers with at least 50 matching sessions, using the same dates:

```json
{"report":"breakdown","dimension":"referrer","from":"2026-08-11","to":"2026-09-08","order_by":"bounce_rate","order":"desc","min_visits":50,"limit":100,"filters":[{"field":"domain","operator":"is","value":"example.com"}]}
```

For an explicit comparison, send `from`, `to`, `compare_from`, and `compare_to` to `/api/v1/compare`. Both windows must have equal duration, be non-overlapping, and be at most 366 days each. Reuse the same filters automatically for both.

## What this API cannot establish

It does not measure unique people across sessions/devices, revenue, conversion goals not represented and defined externally, ordered funnels/journeys, raw user-level records, instrumentation completeness, or causal effects. These limits are also machine-readable in metadata. Within the observed web-traffic data, an agent can discover scope, assess coverage, choose supported measurements, compare periods, and investigate segments without hidden workspace knowledge.

See the [full API reference](/docs/beam-api.md) and [OpenAPI schema](/openapi.json).
