Catch performance slippage during development

Catch slowdowns in everyday app flows as you develop by checking each run against your budgets and earlier results.

Trends helps you catch performance slippage during normal development. Pick an interaction you use often, such as logging in or opening a screen, and the metric you care about. As you record sessions, Ansight checks the result against your budget and comparable earlier runs so you can spot a slowdown while working on the app.

A Trends definition answers two questions:

  1. Did this run stay within its numeric budget?
  2. If historical monitoring is enabled, did the metric regress against comparable earlier runs?

Each JSON file beneath ansight/trends defines which part of an interaction to measure, what to measure, and what counts as acceptable performance.

This example checks frame rate during login. Start with an SDK-enabled app and a workspace linked to that App ID. Save the following as ansight/trends/login-responsiveness.json, replacing com.example.app with your App ID:

{
  "schemaVersion": 1,
  "enabled": true,
  "id": "login-responsiveness",
  "appId": "com.example.app",
  "span": {
    "start": { "event": { "label": "auth.login.started" } },
    "end": { "event": { "label": "auth.login.completed" } },
    "selection": "lastCompleted",
    "maximumDurationMs": 30000
  },
  "required": true,
  "missingDataOutcome": "fail",
  "metrics": [
    {
      "id": "fps-p10",
      "channel": { "type": "fps" },
      "statistic": "p10",
      "budget": { "gte": 55 },
      "minimumSamples": 10,
      "maximumSampleGapMs": 1000,
      "regression": {
        "percent": 10,
        "confirmRuns": 2
      },
      "display": {
        "title": "Login frame rate",
        "unit": "fps",
        "fractionDigits": 0,
        "minimum": 0,
        "includeZero": true
      }
    }
  ]
}

The example measures the last completed login lasting no more than 30 seconds. p10 is the 10th-percentile frame rate, a measure of the lower end of the captured FPS values. Its budget requires at least 55 FPS. The check needs at least 10 samples, with no sampling gap longer than one second.

Capture your first result

  1. In your app code, use the Ansight SDK to emit auth.login.started when login begins and auth.login.completed when it finishes. Enable FPS telemetry for that build. Keep the event names identical to the definition; if you rename one, update both places.
  2. Start the host, launch the development app, and complete the login flow while the session is being captured.
  3. Close the app and leave the host running so it can finish the capture and evaluate the definition.
  4. Open Trends in the local player, select your app, and review Login frame rate. You can also run ansight trends history --app-id com.example.app --metric login-responsiveness.fps-p10 --json.

The FPS budget can be checked on the first capture. Historical comparison needs more runs: Warmup means there is not enough comparable history yet. If no result appears, check the app’s linked workspace and App ID, both captured event names, and whether enough FPS samples were recorded between them.

Set "enabled": false to keep the definition available for inspection without evaluating it. The field defaults to true.

Observation span

The span is the interval between the app’s start and end events, such as the time from starting login to completing it.

span.start and span.end can select SDK or host events by label, with optional eventType or telemetry channelId qualifiers. selection chooses firstCompleted, lastCompleted, exactlyOne, or all when a session contains multiple completed spans. maximumDurationMs prevents an old start from pairing with an unrelated end.

Start and end events must also have matching details values. Leave both empty for one login flow, or use the same value on both events to separate variants. For example, details: "password" groups password logins separately from details: "passkey", even when both use the same login event names. This value is the span group shown in results and accepted by --span-group.

Use native logs without the SDK

Each boundary can instead use a log selector. This works with captured Android Logcat and iOS simulator unified logs, including externally monitored apps:

{
  "schemaVersion": 1,
  "id": "notes-loading-cpu",
  "appId": "com.example.notes",
  "span": {
    "start": { "log": {
      "streamId": "android-logcat", "tag": "Notes",
      "message": "Loading notes"
    } },
    "end": { "log": {
      "streamId": "android-logcat", "tag": "Notes",
      "message": "Loaded notes:", "match": "contains"
    } },
    "selection": "all",
    "maximumDurationMs": 30000
  },
  "metrics": [{
    "id": "cpu-average",
    "channel": { "name": "Process CPU" },
    "statistic": "average",
    "budget": { "lte": 500 }
  }]
}

Use messages and tags observed in your app’s captured logs. Set streamId to apple-unified-log for iOS simulator logs, or sdk for SDK logs. Native log capture must be enabled and supported by the selected target. Log selectors require streamId and message; optional filters are priority, source, tag, and processId. Matching is case-sensitive, with match: "exact" by default or "contains" for a substring. Regex matching is not supported.

Log boundaries pair chronologically without event details groups. An event boundary with empty details can also be paired with a log boundary. A missing boundary yields an inconclusive span. Logs define the measurement interval; the metrics still use captured telemetry. External Process CPU is measured in millicores, so the example budget of 500 equals 50% of one core. Minimum sample and maximum gap checks still apply. Choose memory or supported FPS channels in the same way.

Register the workspace with the monitored App ID to evaluate these definitions when recordings finalize. Existing SDK and external telemetry baselines remain separate.

Metrics and budgets

A metric is a number calculated from captured telemetry, such as a frame rate or an increase in memory use. Select the telemetry channel by type, name, source, or kind. Use channel match: "exactlyOne" when only one channel should match, or "any" when matching channels may be combined. platform can limit a metric to android, ios, macos, windows, or other.

Choose how to summarize the samples:

  • min, max, and average give the lowest, highest, or mean value; p05, p10, p50, and p95 give percentiles, with p50 being the median.
  • memoryPeakIncreaseMiB measures peak memory growth during the operation; memoryRetainedIncreaseMiB measures how much extra memory remains afterward.
  • tailSlopeMiBPerSecond measures whether memory keeps growing after the operation; tailSpreadMiB measures how much it varies during that period.
  • timeBelowRatio measures the fraction of the interval spent below a threshold.

The budget is the acceptable limit: gte means at least, lte means at most, and absoluteLte limits the value’s size regardless of its sign. For example, this metric allows at most 35 MiB of memory to remain above its pre-login level after login finishes:

{
  "id": "retained-growth-mib",
  "channel": { "type": "memory" },
  "statistic": "memoryRetainedIncreaseMiB",
  "budget": { "lte": 35 },
  "minimumSamples": 5,
  "maximumSampleGapMs": 2000,
  "baselineBeforeStartMs": 5000,
  "tailAfterEndMs": 15000
}

minimumSamples requires enough readings, and maximumSampleGapMs rejects large gaps between them. In this example, baselineBeforeStartMs measures memory during the five seconds before login, and tailAfterEndMs measures it for 15 seconds afterward. Keep capture running through that final period.

Regression monitoring

Add regression to a metric to compare new measurements with earlier runs:

"regression": {
  "percent": 20,
  "absolute": 15,
  "confirmRuns": 2,
  "baselineRuns": 12,
  "minimumBaselineRuns": 5,
  "blocking": false
}

The budget normally determines which direction is worse: lower FPS or higher retained memory, for example. Set worseWhen to higher or lower to choose explicitly. If both percent and absolute are present, both thresholds must be crossed.

By default, the comparison uses the median of up to 10 comparable reference runs and needs at least 5 before making a decision. A first result beyond the limit is Suspect. It becomes Regressed after the configured number of consecutive affected runs; a later result within the limit is Recovered. Warmup means more reference runs are needed. Set blocking: true if a confirmed regression should fail the overall evaluation.

By default, comparisons keep different platforms, device models, and major OS versions separate, so unlike devices are not treated as the same test setup. Choose other grouping fields with seriesBy, using any combination of buildNumber, platform, deviceModel, operatingSystemMajor, and buildConfiguration.

Monitor finalized sessions automatically

When a session finishes, the host reads enabled Trends definitions from the app’s linked workspace and evaluates those with the same App ID. Per-session results are stored as trends-results.json.

Inspect and rebuild history

ansight trends history --app-id com.example.app
ansight trends history \
  --app-id com.example.app \
  --metric login-responsiveness.fps-p10 \
  --json

If you used details: "password" on both login events, add --span-group password to show only that login method’s history.

ansight trends rebuild --dry-run
ansight trends rebuild --app-id com.example.app
ansight trends rebuild \
  --app-id com.example.app \
  --app-version 2.4.0

Rebuild replays stored metric values against the current workspace rules; it does not rerun the app. Use --workspace <path> with --app-id to override the registered codebase.

The local player’s Trends view shows the current measurement, the reference value it was compared with, the difference, the result, and earlier runs.

ansight auth login --email you@example.com --otp
ansight cloud app register com.example.app \
  --team-id <organisation-uuid> \
  --name "Example App"
ansight cloud trends sync com.example.app --team-id <organisation-uuid>

Cloud Trends requires a current product grant and an exact registered App ID. Repeating an upload updates matching evaluation records.

Open Trends in the cloud portal to review uploaded measurements and their history charts. External sessions can contribute supported process telemetry and native-log observation spans. They still need a workspace Trends definition and an upload; adding an app monitor alone does not publish Trends history.