Run tracking checks in CI
Synthetic journeys normally run against your live site on a schedule, so a theme or checkout change that stops purchase firing is caught in the next run — after it shipped. Running the same journeys against the preview deployment of a pull request catches it before merge: the build goes red, with the step that failed and what was observed instead, and the run is listed on the Journeys page with its branch, commit and PR.
Available on the Business plan and above (the plan that includes synthetic journeys). Nothing changes about the journeys themselves — the ones you already have are the ones CI runs.
Step 1 — Create a CI API key
Go to Settings › API keys › Create key, name it after the pipeline, and tick Run journeys in CI. That grants the journeys:run scope, which lets the key start journeys against a URL and read their results — and nothing else, so a key that leaks from a build log cannot read or change the rest of your account. Give it an expiry if your pipeline can rotate secrets. Store the key as a secret named TAGEASY_API_KEY.
Step 2 — Add the GitHub Action
The action lives at packages/cli/action in the TagEasy repository. It runs after a preview deployment is ready, waits for the results, prints a table to the job log and writes a report to the job summary. The deployment_status event is the simplest trigger when Vercel, Netlify or another host deploys the preview for you:
# .github/workflows/tageasy.yml
name: Tracking checks
on:
deployment_status:
jobs:
journeys:
# Vercel, Netlify and most hosts post a deployment_status when a preview is ready.
if: github.event.deployment_status.state == 'success'
runs-on: ubuntu-latest
steps:
- uses: hexcorpIO/tageasy/packages/cli/action@main
with:
api-key: ${{ secrets.TAGEASY_API_KEY }}
base-url: ${{ github.event.deployment_status.environment_url }}
website-id: ${{ vars.TAGEASY_WEBSITE_ID }} # omit when the organisation has one website
# journey-ids: clx1abc,clx2def # default: all enabled journeys (first 5)
# fail-on-warn: 'true'If the workflow deploys with the Vercel CLI itself, feed the URL it prints into base-url:
- name: Deploy preview to Vercel
id: vercel
run: |
npm i -g vercel
vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
vercel build --token=${{ secrets.VERCEL_TOKEN }}
echo "url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})" >> "$GITHUB_OUTPUT"
- name: Run TagEasy journeys against the preview
uses: hexcorpIO/tageasy/packages/cli/action@main
with:
api-key: ${{ secrets.TAGEASY_API_KEY }}
base-url: ${{ steps.vercel.outputs.url }}Inputs: api-key and base-url (required), website-id, journey-ids (comma-separated), fail-on-warn, timeout and version. Outputs: passed, failed and run-ids.
Step 3 — Or run the CLI anywhere
@tageasy/cli needs Node 20 and nothing else. It works in GitLab CI, CircleCI, Buildkite, a Netlify build plugin or a laptop:
TAGEASY_API_KEY=te_live_… npx @tageasy/cli journeys run \
--base-url https://my-shop-git-feat-x.vercel.app \
--website clx… # when the organisation has several websites
--wait --fail-on-warn--wait keeps polling until every run has finished (default limit 10 minutes). tageasy journeys list prints the journey ids for --journey. Branch, commit and pull-request labels are read from the GitHub Actions, GitLab CI and Vercel environment variables automatically; pass --branch, --commit or --pr to override them.
Exit codes: 0 all passed, 1 a journey failed (or a warning with --fail-on-warn), 2 bad arguments or the API refused the call, 3 the runs were still in progress when the command gave up.
Step 4 — Read a failure
Every failure names the step, what the journey expected and what was observed instead — the same text the Journeys page shows. A missing event reads expected dataLayer event "purchase" — No "purchase" event was captured during the journey; a wrong parameter reads "purchase" fired but payload.currency = "EUR" (expected "USD"); a page that would not load reads expected click "#buy" — Timeout 10000ms exceeded. When a screenshot was captured at the failing step, screenshotUrl points at it; fetch it with the same Bearer key to attach it to the build.
How the preview URL is used
- Every visit step whose host is the website's production domain is rewritten to the preview origin, keeping the path, query string and fragment.
https://www.shop.com/products/shoe?c=redbecomeshttps://my-shop-git-feat-x.vercel.app/products/shoe?c=red. - Visits to other hosts — a payment provider, an identity provider — are left alone; the preview does not serve them.
- If no visit matches the production domain (the journey was written against a staging host), the first visit is rewritten so the run still exercises the deployment under test.
- Clicks, form fills, waits, variables and the dataLayer / network assertions run unchanged.
- The base URL must be
httpsand publicly resolvable; private addresses are refused.
Journeys that reference the production host in an expect request pattern will keep looking for that host. Match on the vendor endpoint (google-analytics.com/g/collect) rather than your own domain and the assertion holds on every environment.
Limits
- At most 5 journeys per call. With
journeyIds: "all"the first five enabled journeys run and a warning names the rest; pass explicit ids to choose. - 10 calls per 10 minutes per API key — each call may launch five browsers.
- A call blocks for up to
waitForSeconds(default 240, max 270). Runs that take longer continue in the background and are polled by id; the CLI does this for you with--wait. - Each step has a 10-second timeout, as in scheduled runs.
API reference
The CLI and the action are thin clients over three endpoints of the REST API. All take Authorization: Bearer te_live_….
POST /api/v1/journeys/run — scope journeys:run
curl -X POST https://www.tageasy.io/api/v1/journeys/run \
-H "Authorization: Bearer te_live_…" \
-H "Content-Type: application/json" \
-d '{
"websiteId": "clx…",
"journeyIds": "all",
"baseUrl": "https://my-shop-git-feat-x.vercel.app",
"labels": { "commit": "3f9c2a1", "branch": "feat/x", "pullRequest": "42" }
}'baseUrl(required) — https origin to run against.websiteId— required when the organisation has more than one website and no journey ids are given.journeyIds—"all"(default) or up to five ids, all from one website.waitForSeconds— 0–270, default 240.labels—{ commit?, branch?, pullRequest? }, shown on the Journeys page.
Response (200 when complete, 202 with status: "running" when the runs outlived the wait):
{
"status": "completed",
"runIds": ["clxrun1…", "clxrun2…"],
"baseUrl": "https://my-shop-git-feat-x.vercel.app",
"results": [
{
"journeyId": "clx1abc", "runId": "clxrun1…", "name": "Checkout", "passed": false, "durationMs": 8400,
"failures": [
{ "step": 4, "expected": "dataLayer event \"purchase\" with {\"currency\":\"USD\"}",
"observed": "No \"purchase\" event was captured during the journey." }
],
"screenshotUrl": "https://www.tageasy.io/api/v1/journeys/runs/clxrun1…/screenshot?step=3"
},
{ "journeyId": "clx2def", "runId": "clxrun2…", "name": "Newsletter signup", "passed": true, "durationMs": 950, "failures": [] }
],
"summary": { "passed": 1, "failed": 1, "pending": 0 },
"warnings": []
}Errors: 400 invalid body or base URL, 401 bad key, 403 missing scope or plan, 404 website or journey not in the key's organisation, 429 rate limited.
GET /api/v1/journeys/runs/{runId} — scope read or journeys:run
Polls one run: status, labels, baseUrl and the same result object. /screenshot?step=N on the same path serves the JPEG captured at that step.
GET /api/v1/journeys?websiteId= — scope read or journeys:run
Lists journeys with their id, website, schedule, step count and last run. Paginated with limit / offset and hasMore, like /api/v1/sites.
What is recorded
Each call writes a journey.ci-run activity entry with the key, the origin, the run ids and the labels. The runs themselves appear under CI runs on the Journeys page, filterable by website, branch and result, with the preview URL linked. CI runs never trigger the failure alerts or the recovery emails that scheduled runs send — the build status is the alert.
See also Synthetic journeys for writing journeys and Approvals & environments for staging a GTM container version the same preview can load.