Compare releases
Tag deploys from CI/CD and answer "did this deploy regress LCP?" in one query.
The cleanest way to catch performance regressions is to tag every deploy as a release and let the analytics API do the before/after comparison. This guide wires it up end-to-end: API key, release call from CI/CD, comparison query.
Time to set up: 10–15 minutes. You'll need: an authenticated fastmon account, edit access to your CI/CD pipeline, and a site that's already ingesting beacons.
1. Create an API key
- In fastmon, open your organization's settings, then Access, and click Create key. An organization key (
fmo_…) belongs to the organization, so it keeps working when its creator leaves: the right shape for a pipeline. (A personal key under Account → Access works too, but follows your role and memberships.) - Tick
release:writeandanalytics:read; the release call and the comparison query below need nothing else. Choose an expiry. - Copy the value: it is shown once. Store it in your CI's secret store as
FASTMON_API_KEY.
A pipeline that only posts releases can skip the settings page: the CI/CD snippet on the application page creates a release:write key in place, asks whether it should belong to you or to the organization, and writes it into the curl command.
If the key leaks, revoke it; if you just need a fresh secret, rotate it (the successor keeps name, scopes, and expiry, with an optional grace window for the switchover). See Authentication for what a key can and cannot do.
2. Find the site ID
In fastmon, open the site, then Settings. Copy the site's id (UUID v7, looks like 01HZX...). Store it in your CI as FASTMON_SITE_ID.
3. Add a release call to your deploy job
The release call goes at the end of your deploy job, after the deploy has finished. The minimum payload is just version:
curl -fsS https://api.fastmon.eu/sites/$FASTMON_SITE_ID/releases \
-H "Authorization: Bearer $FASTMON_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"version\": \"$DEPLOY_VERSION\",
\"released_at\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"
}"The -fsS flags make curl fail loudly on non-2xx responses without spamming progress output. released_at is optional; if you skip it, the server just sets "now."
GitHub Actions
- name: Tag fastmon release
if: success()
env:
FASTMON_API_KEY: ${{ secrets.FASTMON_API_KEY }}
FASTMON_SITE_ID: ${{ vars.FASTMON_SITE_ID }}
run: |
curl -fsS https://api.fastmon.eu/sites/$FASTMON_SITE_ID/releases \
-H "Authorization: Bearer $FASTMON_API_KEY" \
-H "Content-Type: application/json" \
-d "{ \"version\": \"${{ github.sha }}\" }"GitLab CI
fastmon-release:
stage: post-deploy
needs: ["deploy"]
script:
- |
curl -fsS https://api.fastmon.eu/sites/$FASTMON_SITE_ID/releases \
-H "Authorization: Bearer $FASTMON_API_KEY" \
-H "Content-Type: application/json" \
-d "{ \"version\": \"$CI_COMMIT_SHORT_SHA\" }"Vercel
Vercel doesn't run arbitrary post-deploy commands inside the build itself. Two options:
- Deploy hook: set up a webhook receiver that fires on Vercel's
deployment.succeededevent, and have the receiver call the fastmon endpoint with the SHA from the payload. - Edge function: add a small cron-triggered function that polls the Vercel API for new deployments and tags them.
4. Verify the release was recorded
Reload your site's release list:
curl https://api.fastmon.eu/sites/$FASTMON_SITE_ID/releases \
-H "Authorization: Bearer $FASTMON_API_KEY"You should see your new release in the data array, with the version you supplied.
In the dashboard, the release picker on the Performance view will list it.
5. Compare metrics
The dashboard has a release picker on Performance: pick the release and the chart overlays before/after. For programmatic comparison, pass compare_to_release_id:
curl https://api.fastmon.eu/organizations/$ORG_ID/analytics/query \
-H "Authorization: Bearer $FASTMON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"time_range": { "from": "2026-05-07T12:00:00Z", "to": "2026-05-08T12:00:00Z" },
"metrics": ["lcp", "inp", "cls"],
"aggregations": ["p75"],
"filters": { "site_id": "01HZX..." },
"compare_to_release_id": "01HZY..."
}'The response contains a compare block with the same metrics for the same-length window ending at the release's released_at. So the example above compares 24 hours after the release against the 24 hours immediately before it.
What "good" looks like
- Every successful deploy tags a release automatically, nothing by hand.
- The release version is something you can resolve back to a commit: git SHA, tag, build number, whatever your team uses.
- Your CI has a step that fails the deploy if the release call fails. Otherwise you'll get silent gaps and stop trusting the comparisons.
Common surprises
- Omitting
released_atdefaults to "now." That fits most of the time. Watch out when your deploy job runs minutes before the artifact is actually live (blue/green flips later, etc.). Then back-date it. - Releases are per site. A monorepo deploy that ships three sites needs three release calls.
- Comparison windows follow the query length. A 7-day query compares against the 7 days before the release. Keep the window short (1–24 h) if you want to catch regressions sharply.
Related
- Releases concept: what a release is.
- Analytics API:
compare_to_release_iddetails. - Notification rules: alert automatically on per-release regressions.