Charts

Chart Annotations

Mark releases, campaigns, and incidents on your app's charts from the dashboard or the Superwall API.

Chart annotations mark what happened on your app's timeline, such as a release, an App Store feature, a marketing campaign, or an outage. Every time-series chart for the app draws them, so you can see a change in a metric next to the event that might explain it.

Annotations belong to the app, not to one chart or one person. Everyone who can see the app sees the same annotations.

An annotation is one of two kinds:

KindWhat it marksHow it's drawn
PointOne moment, such as a release.A dashed vertical line.
RangeA span of time, such as a sale or an App Store feature.A faint shaded band.

Each annotation keeps the same color on every chart.

Annotations on charts

Annotations are drawn in Dashboard v2. Enable New Dashboard Experience from Settings > Public Beta, then open your charts at app.superwall.com. The API works whichever dashboard you use.

Annotations appear on:

  • The Charts page, where you can also add, edit, and delete them.
  • Charts pinned to the app's Overview.
  • The Results chart of a campaign.

Overview pins and campaign results only display annotations. To change one, use the Charts page.

Charts without a date axis, such as a breakdown by country, a retention-period chart, or a Totals view, don't draw annotations.

Where an annotation lands

Charts group data into UTC buckets, such as hours or days. An annotation is drawn in the bucket that contains its moment. For example, a release at 2

PM UTC is drawn on the 2 PM bucket of an hourly chart and on that day's bucket of a daily chart. A range covers every bucket it touches.

Hover a bucket to see its annotations. Their labels are listed at the top of the chart's tooltip, each marked in its color: a short dashed line for a point, a small square for a range.

A Proceeds chart with two point annotations and a Spring sale range, with the tooltip listing Spring sale above the day's proceeds

Annotations never get in the way of the chart. You can still drag across the chart to zoom into a date range.

The Annotations control

The chart toolbar has an Annotations control, just before the chart type. It shows how many annotations the current chart draws, or Hidden if you've turned them off.

Click it to open the list of annotations. In view lists the ones in the chart's current date range, and All lists every annotation for the app. Both are newest first, and each row shows the annotation's label and when it happened, in your time zone.

The Annotations control open, listing three annotations with edit and delete actions, the Show on charts switch, and Add annotation

Show or hide annotations

Use the Show on charts switch in the Annotations control to hide or show annotations. This setting only affects you, is saved in your current browser, and applies to every chart that draws annotations, including Overview pins and campaign results. It's on by default.

Add, edit, and delete annotations

You need permission to write annotations. Owners, Admins, and Editors can add, edit, and delete them. Readers and Analysts, and members with the project Viewer role, can see annotations but don't get add, edit, or delete controls. See Access Controls.

Add an annotation

There are two ways to add an annotation on the Charts page:

  • From the chart: Click a point on the chart, without dragging. A small Add annotation popover opens for that bucket. Type a label and click Add annotation to add a point there, or click More options to open the full form. Clicking next to an existing annotation opens that annotation instead; see Edit or delete an annotation.
  • From the Annotations control: Open Annotations and click Add annotation.
The Add annotation popover open on Oct 12 with a label typed in, and More options and Add annotation buttons

Clicking the chart only opens the popover when annotations are shown and the chart has a date axis.

The full form has these fields:

FieldWhat to enter
LabelWhat happened, shown on the chart. Required, up to 191 characters.
DescriptionOptional detail, up to 2,000 characters.
TypePoint for one moment, or Range for a span of time.
When / Start and EndThe moment for a point, or the start and end for a range. A range must end after it starts.

Enter times in your own time zone. The form shows which time zone it's using, and Superwall saves each time as an exact moment, so everyone sees the annotation in the same place on the chart, whatever their time zone.

Edit or delete an annotation

There are two ways to edit an annotation:

  • From the chart: Click next to it. For a point, click anywhere in its bucket or right on its line. For a range, click in the bucket where it starts or where it ends. A small Edit annotation popover opens with its label. Change the label and click Save changes, or click More options to edit everything else. To add a new annotation there instead, click Add new. If several annotations are that close, the popover lists them so you can pick one.
  • From the Annotations control: Open Annotations and use the edit action on an annotation's row.
The Edit annotation popover opened by clicking the v4.2.0 released line, with its label, a delete icon, More options, Save changes, and Add new

Clicking inside a range, away from its start and end, still adds a new annotation, so you can mark something that happened during it.

To delete an annotation, use Delete annotation in the edit form, the delete icon next to More options in the chart's Edit annotation popover, or the delete action on its row in Annotations.

The Edit annotation form for the Spring sale range, with its label, description, Range type, start and end times, and Delete annotation at the left of the footer

Deleting asks you to confirm, then removes the annotation from every chart for the app. This is permanent and can't be undone. Every create, update, and delete is recorded in the organization's Audit Log with before and after values, so a deleted annotation's contents remain in the log.

Manage annotations with the API

Use the Superwall API to add annotations from scripts or CI, for example to mark every release automatically. The full reference, with request and response schemas, is at api.superwall.com/docs.

Authentication

  1. Open Settings > API Keys in the Superwall dashboard.
  2. Create an organization API key, or edit an existing one.
  3. Give the key the charts:write scope to create, update, or delete annotations. Add charts:read if it also needs to list or retrieve them.
  4. Copy the token when Superwall shows it.

API keys created before chart annotations were released don't have the charts:write scope. Requests to create, update, or delete annotations with those keys return 403. Edit the key to add charts:write, or create a new key with it.

Pass the token as a bearer token:

Authorization: Bearer YOUR_SECRET_TOKEN

Endpoints

The base URL is https://api.superwall.com.

OperationMethod and pathScope
ListGET /v2/applications/{application_id}/chart_annotationscharts:read
CreatePOST /v2/applications/{application_id}/chart_annotationscharts:write
RetrieveGET /v2/applications/{application_id}/chart_annotations/{chart_annotation_id}charts:read
UpdatePATCH /v2/applications/{application_id}/chart_annotations/{chart_annotation_id}charts:write
DeleteDELETE /v2/applications/{application_id}/chart_annotations/{chart_annotation_id}charts:write

An application ID outside your organization, or an annotation ID that belongs to a different application, returns 404.

Timestamps

start_at and end_at are exact moments. Send them as ISO 8601 timestamps with a timezone, either Z or an offset such as +02:00. Superwall rejects these with 400:

  • Date-only values, such as 2026-10-28.
  • Values without a timezone, such as 2026-10-28T14:00:00.
  • Dates that don't exist, such as 2026-02-30T00:00:00Z.
  • Years before 2000 or after 9999.

Responses always return timestamps in UTC with milliseconds. For example, if you send 2026-10-28T16:00:00+02:00, the response returns 2026-10-28T14:00:00.000Z.

Create an annotation

Send label and start_at to create a point. Add end_at to create a range.

Prop

Type

curl https://api.superwall.com/v2/applications/$APP_ID/chart_annotations \
  --request POST \
  --header "Authorization: Bearer $SUPERWALL_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "label": "Summer sale",
    "description": "20% off annual plans",
    "start_at": "2026-07-01T00:00:00Z",
    "end_at": "2026-07-08T00:00:00Z"
  }'

The response is the annotation. id and application_id are returned as strings:

{
  "object": "chart_annotation",
  "id": "42",
  "application_id": "123",
  "label": "Summer sale",
  "description": "20% off annual plans",
  "start_at": "2026-07-01T00:00:00.000Z",
  "end_at": "2026-07-08T00:00:00.000Z",
  "created_at": "2026-06-30T18:12:05.000Z",
  "updated_at": "2026-06-30T18:12:05.000Z"
}

An application can hold up to 1,000 annotations. Creating one beyond that returns 400. Delete an annotation first to make room.

List annotations

List returns the application's annotations ordered by start_at. Use from and to to limit it to a window:

Prop

Type

The window is inclusive and returns every annotation that overlaps it: a point at or between from and to, or a range that starts at or before to and ends at or after from.

In a query string, a literal + is decoded as a space, so an offset like +02:00 is rejected. Encode it as %2B, for example from=2026-10-01T00:00:00%2B02:00, or use UTC timestamps ending in Z.

curl --get https://api.superwall.com/v2/applications/$APP_ID/chart_annotations \
  --header "Authorization: Bearer $SUPERWALL_API_KEY" \
  --data-urlencode "from=2026-10-01T00:00:00Z" \
  --data-urlencode "to=2026-10-31T23:59:59Z"

The response includes a top-level can_write field that says whether the caller can create, update, and delete annotations. Use it to hide write controls in your own tools:

{
  "object": "list",
  "data": [
    {
      "object": "chart_annotation",
      "id": "43",
      "application_id": "123",
      "label": "v4.2.0 released",
      "description": null,
      "start_at": "2026-10-28T14:00:00.000Z",
      "end_at": null,
      "created_at": "2026-10-28T14:00:03.000Z",
      "updated_at": "2026-10-28T14:00:03.000Z"
    }
  ],
  "can_write": true
}

Update an annotation

PATCH changes only the fields you send and keeps the rest:

  • Omit a field to keep its current value.
  • Send description: null to remove the description.
  • Send end_at: null to turn a range into a point.

The result must still end after it starts. If you move only start_at or only end_at, Superwall checks the combined result and returns 400 if it would end at or before its start.

curl https://api.superwall.com/v2/applications/$APP_ID/chart_annotations/$ANNOTATION_ID \
  --request PATCH \
  --header "Authorization: Bearer $SUPERWALL_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"end_at": "2026-07-10T00:00:00Z"}'

Delete an annotation

DELETE removes the annotation from every chart. This is permanent. The change is recorded in the Audit Log.

curl https://api.superwall.com/v2/applications/$APP_ID/chart_annotations/$ANNOTATION_ID \
  --request DELETE \
  --header "Authorization: Bearer $SUPERWALL_API_KEY"
{
  "object": "chart_annotation",
  "id": "42",
  "deleted": true
}

Mark releases from CI

Add a step to your release pipeline that creates a point annotation when a build ships. Store the API key as a CI secret, and generate start_at in UTC with date -u +%Y-%m-%dT%H:%M:%SZ:

curl https://api.superwall.com/v2/applications/$APP_ID/chart_annotations \
  --request POST \
  --header "Authorization: Bearer $SUPERWALL_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"label\":\"v$VERSION released\",\"start_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}"

The key only needs the charts:write scope. Restrict it to the project the app belongs to.

Troubleshooting

StatusWhat to check
400A timestamp is missing its timezone or isn't a real date, end_at isn't after start_at, to is before from, the label is empty or too long, or the application already has 1,000 annotations.
401The request is missing a bearer token, or the token is invalid or revoked.
403The API key doesn't have the scope the operation needs: charts:read to list or retrieve, charts:write to create, update, or delete.
404The application isn't in your organization, or the annotation belongs to a different application.

How is this guide?

On this page