# Check rollout health

> Connect feature exposure and releases to the customers and failures that followed.

Canonical page: https://anectico.com/docs/investigate/rollout-health/


Feature flags and releases are both delivery controls and investigation context. Use them to answer
whether a change affected a specific customer or concentrated an Issue in the exposed audience.

## Create and evaluate a flag

Open **Analytics → Feature Flags** to create a boolean or multivariate flag. Give it a permanent key,
then configure percentage, property, or cohort targeting. The key cannot be renamed after creation.
Saved analytics audiences use an exact generation through MCP/CLI or the dashboard and require current source
permissions on the server; see [audience flag targeting](/docs/investigate/product-analytics/#target-a-flag-at-an-exact-audience).
They are omitted from local-evaluation snapshots.

Keep a safe default for clients that cannot reach the decision endpoint. Activate a new flag only
after testing a known matching and non-matching customer. Editing takes effect on subsequent SDK
evaluations; cached clients can temporarily retain an earlier decision.

Evaluate with the customer ID and the properties used by targeting:

<div data-language-tabs="feature-flag-evaluate" data-language-tabs-label="Choose an SDK"></div>

**JavaScript / TypeScript**

```typescript
import { AnalyticsClient, FlagsClient } from '@anectico/sdk/analytics';

const events = new AnalyticsClient({
  endpoint: 'https://api.anectico.com',
  apiKey: import.meta.env.VITE_ANECTICO_FLAGS_KEY,
});
events.identify('user_8842', { plan: 'pro' });
const flags = new FlagsClient({
  endpoint: 'https://app.anectico.com',
  apiKey: import.meta.env.VITE_ANECTICO_FLAGS_KEY,
}, (event, properties) => events.capture(event, properties));

await flags.reload('user_8842', { plan: 'pro' });
const showNewCheckout = flags.isFeatureEnabled('new-checkout');
```

**Python**

```python
import os
import anectico
from anectico.feature_flags import FeatureFlags

events = anectico.AnalyticsClient(
    endpoint='https://api.anectico.com',
    api_key=os.environ['ANECTICO_API_KEY'],
)
flags = FeatureFlags(
    endpoint='https://app.anectico.com',
    api_key=os.environ['ANECTICO_API_KEY'],
    capture=lambda event, props, distinct_id: events.capture(
        event, props, distinct_id=distinct_id
    ),
)
flags.reload('user_8842', {'plan': 'pro'})
show_new_checkout = flags.is_feature_enabled('new-checkout', 'user_8842')
```

**Go**

```go
events, err := anectico.NewAnalytics(anectico.AnalyticsConfig{
	Endpoint: "https://api.anectico.com",
	APIKey:   os.Getenv("ANECTICO_API_KEY"),
})
if err != nil {
	return err
}
flags := anectico.NewFlags(anectico.FlagsConfig{
	Endpoint: "https://app.anectico.com",
	APIKey:   os.Getenv("ANECTICO_API_KEY"),
	Capture: func(ctx context.Context, event string, props map[string]any, distinctID string) {
		_ = events.Capture(ctx, event, props, anectico.WithDistinctID(distinctID))
	},
})
if err := flags.Reload(ctx, "user_8842", map[string]any{"plan": "pro"}, nil); err != nil {
	return err
}
showNewCheckout := flags.IsFeatureEnabled(ctx, "new-checkout", "user_8842")
```

<div data-language-tabs-end="feature-flag-evaluate"></div>

Flag decisions use the Edge host, `https://app.anectico.com`; exposure events use the ingestion
host, `https://api.anectico.com`. Keep the explicit capture callback shown above. In JavaScript,
the default callback sends capture requests to the flag client's own endpoint, which does not
work across these two hosted origins. Identify the same customer in the event client and flag
reload, and update both when the signed-in customer changes.

The key needs project-scoped `flags:read` to call `/api/v1/decide` and `analytics:write` to record
the exposure event. Add `ingest:write` only when the same client sends other telemetry. A browser
key is visible to the browser user, and `flags:read` can read flag configuration through the current
API. Treat flag keys, targeting rules, variants, and payloads as public client data; never store a
secret in them.

## Record exposure

Identify the customer before evaluating a flag. The SDK records the flag result with the active
customer so it can appear in timelines and affected-customer analysis. If the decision request
fails, keep the application's safe default and surface the failure in application diagnostics; do
not silently reuse an indefinitely stale decision.

Use stable flag keys and keep evaluation payloads small. Do not put secrets in flag payloads or
customer properties.

Open **Health** on a flag to compare one-day exposure counts, unique customers, and the observed
response distribution with the configured rollout. All counts share one frozen measurement;
**New measurement** includes newly captured exposures. The global time selector does not change
this one-day window. Health needs `analytics:query`, `analytics:read` and `persons:read` in addition
to `flags:read`. It is based on SDK exposure events, not every raw evaluation. Low volume can make
the distribution noisy, and an observed zero does not establish complete instrumentation. Typed
responses and missing/null/invalid/omitted groups remain distinct. See
[product analytics](/docs/investigate/product-analytics) for retry, expiry and coverage semantics.

## Register a release

Record a deploy from CI so Anectico can order Issues and regressions against a release:

```bash
anectico releases create "$RELEASE" --commit "$GIT_SHA" --ref "$GIT_REF"
```

Registering a release replaces its deploy details in full rather than merging them, so pass every
detail you want kept on every call. A later call that passes only `--commit` clears the ref,
author, link and deploy time an earlier one set. Leaving `--deploy-at` off stores no deploy time
and the release is ordered by when it was first seen.

Use the exact same release identifier in the SDK and symbol uploads. Open **Analytics → Releases** to
compare native adoption, error-free rate, new Issues, regressions, total error events, and affected
customers, then open a release for its detailed blast radius.

Native adoption is a privacy-safe people count, not an app-open volume or a hardware installation
count. Android/iOS emit one SDK-owned release marker on process activation; Anectico resolves aliases
through the identity spine and counts each canonical person once in the trailing 30 days. Error-free
rate is the share of those adopters with no error event for that exact release. A release with no
observed adopters shows no rate rather than implying either 0% or 100%.

## Investigate a suspected regression

1. Open the Issue or affected customer.
2. Check the release and flag exposures immediately before the failure.
3. Compare affected customers with customers on the previous release or control variant.
4. Open a representative replay and trace.
5. Disable or narrow the rollout only when the evidence supports it.

## Avoid false conclusions

Exposure before a failure is correlation, not proof of cause. Confirm the changed code path in the
trace, stack, logs, or replay before attributing the Issue to the flag.

## Keep flags operational

Deactivate a flag before deleting it, and allow clients time to refresh. Remove stale flags after a
rollout is complete. Long-lived inactive flags make investigation context harder to interpret and
increase the chance of evaluating the wrong variant. Deleting a cohort used for targeting stops that
cohort from matching; update the flag first.

- [Capture errors and releases](/docs/instrument/errors)
- [Inspect events and customer cohorts](/docs/investigate/events-and-cohorts)
