Docs menu

Integrations

Record deploys

Send one request after each deploy, from GitHub Actions, Forge, Ploi, Envoyer, Vercel or any CI, so charts get a marker and new errors point to the deploy.

Updated View as Markdown

On this page

A deploy marker tells Lampwick which release is live. Charts get a line at each deploy, every issue shows the deploy it was first seen in, and the issue list can show only the errors that are new since the last deploy. Recording one is a single POST request; add it as the last step of your deploy.

Requirements

  • The project's ingest token, from the Connect your app card on its Settings page. It's the same token your app sends data with (LAMPWICK_TOKEN), so CI needs no personal API token. Only team owners see it.
  • curl and jq for the shell recipes, or the lampwick/laravel package for php artisan lampwick:deploy.

GitHub Actions

Add the ingest token as a repository secret named LAMPWICK_TOKEN (Settings → Secrets and variables → Actions), then add this step after your deploy step:

YAML
- name: Record deploy in Lampwick
  env:
    LAMPWICK_TOKEN: ${{ secrets.LAMPWICK_TOKEN }}
  run: |
    body=$(jq -n --arg version "${GITHUB_SHA::12}" --arg commit_sha "$GITHUB_SHA" \
      --arg repo_url "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" \
      --arg author "$GITHUB_ACTOR" --arg environment production '$ARGS.named')
    printf 'header = "Authorization: Bearer %s"\n' "$LAMPWICK_TOKEN" |
    curl -fsS --max-time 30 -K - -X POST https://app.lampwick.dev/api/v1/deploys \
      -H "Content-Type: application/json" --data "$body" \
      || echo "::warning::Lampwick: deploy marker not recorded"

It sends the first 12 characters of the commit as the version, with the full commit, the repository URL and the GitHub user who started the workflow. The token goes to curl on stdin, and GitHub masks it in the log. For a workflow that runs on tags, use "$GITHUB_REF_NAME" as the version. A failed request is a warning in the log and the step still succeeds: your deploy went fine, only its marker is missing. Leave out the || echo line to fail the step instead.

Laravel Forge

Record the deploy from the server, in the deploy script. Then the marker lands when the release is live, and the token is the one in the site's .env, so it needs no secret in CI.

With the lampwick/laravel package, add one line to the site's Deploy script after $ACTIVATE_RELEASE() (zero-downtime deployments) or at the end (other sites):

Terminal
$ACTIVATE_RELEASE()

$FORGE_PHP artisan lampwick:deploy --commit="$FORGE_DEPLOY_COMMIT" --author="$FORGE_DEPLOY_AUTHOR" || true

The command reads LAMPWICK_TOKEN from .env and sends LAMPWICK_DEPLOY as the version, or the first 12 characters of the commit when that isn't set. The environment is the app's (APP_ENV), and the repository URL comes from the git remote origin when there is one. It prints Recorded deploy 9f1c2ab3d4e5 in Lampwick. || true keeps a failed request from marking a live release as a failed deployment.

Without the package (any app with LAMPWICK_TOKEN in its .env):

Terminal
LAMPWICK_TOKEN=$(grep -E '^LAMPWICK_TOKEN=' .env | head -n1 | cut -d= -f2- | tr -d "\"' \r")
body=$(jq -n --arg version "${FORGE_DEPLOY_COMMIT:0:12}" --arg commit_sha "$FORGE_DEPLOY_COMMIT" --arg author "$FORGE_DEPLOY_AUTHOR" \
  '{version: $version, commit_sha: $commit_sha, author: $author, environment: "production"}')
printf 'header = "Authorization: Bearer %s"\n' "$LAMPWICK_TOKEN" |
curl -fsS --max-time 30 -K - -X POST https://app.lampwick.dev/api/v1/deploys \
  -H "Content-Type: application/json" --data "$body" || true

The script runs in the release directory, where .env is the site's shared one. It reads only the token line from .env (it doesn't source the file), and hands the token to curl on stdin so it stays out of the server's process list. FORGE_DEPLOY_COMMIT and FORGE_DEPLOY_AUTHOR are Forge's deploy script variables (checked 10 Nov 2026).

Ploi

Add the line at the end of the site's Deploy script:

Terminal
php artisan lampwick:deploy --commit={COMMIT_HASH} || true

Ploi replaces {COMMIT_HASH} with the deployed commit before the script runs. With zero-downtime deployment, Ploi runs the deploy script before it switches the current link to the new release, so the marker can land a few seconds early.

Envoyer

Add a deployment hook (Deployment Hooks) that runs after Activate New Release, as the user that owns the app:

Terminal
cd "{{release}}" && php artisan lampwick:deploy --commit={{sha}} || true

Envoyer cancels a deployment when a hook fails; || true stops a failed request from doing that. {{release}} and {{sha}} are Envoyer's hook variables (checked 10 Nov 2026).

Vercel

Vercel has no deploy script to add a step to. Its GitHub integration reports each deployment to GitHub, so a workflow on deployment_status can record the deploy once Vercel says it's live:

YAML
# .github/workflows/lampwick-deploy.yml
name: Lampwick deploy
on: deployment_status
permissions: {}
jobs:
  record:
    if: github.event.deployment_status.state == 'success' && github.event.deployment_status.environment == 'Production'
    runs-on: ubuntu-latest
    steps:
      - name: Record deploy in Lampwick
        env:
          LAMPWICK_TOKEN: ${{ secrets.LAMPWICK_TOKEN }}
        run: |
          body=$(jq -n --arg version "${GITHUB_SHA::12}" --arg commit_sha "$GITHUB_SHA" \
            --arg repo_url "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" \
            --arg author "$GITHUB_ACTOR" --arg environment production '$ARGS.named')
          printf 'header = "Authorization: Bearer %s"\n' "$LAMPWICK_TOKEN" |
          curl -fsS --max-time 30 -K - -X POST https://app.lampwick.dev/api/v1/deploys \
            -H "Content-Type: application/json" --data "$body" \
            || echo "::warning::Lampwick: deploy marker not recorded"

The job doesn't check out or run your code, and permissions: {} leaves it no access to the repository; keep it that way. Leave Vercel's fork protection on: every deployment, also one of a pull request from a fork, triggers this workflow with your secrets. The workflow file must be on the default branch. Drop the environment check to record preview deployments too, but send those to a separate project. On deployment_status, GITHUB_SHA is the deployed commit. Deploying with vercel deploy --prod from your own CI instead? Add the step after that, as in GitHub Actions.

Any other CI

GitLab CI, Bitbucket Pipelines, CircleCI, Buildkite or a shell script: store the token as a secret variable LAMPWICK_TOKEN and run this after the deploy:

Terminal
body=$(jq -n --arg version "$VERSION" --arg commit_sha "$COMMIT_SHA" \
  '{version: $version, commit_sha: $commit_sha, environment: "production"}')
printf 'header = "Authorization: Bearer %s"\n' "$LAMPWICK_TOKEN" |
curl -fsS --max-time 30 -K - -X POST https://app.lampwick.dev/api/v1/deploys \
  -H "Content-Type: application/json" --data "$body" \
  || echo "Lampwick: deploy marker not recorded"

Set VERSION and COMMIT_SHA from your CI's variables, for example $CI_COMMIT_SHA on GitLab or $BITBUCKET_COMMIT on Bitbucket. jq builds the JSON, so a version with quotes can't break it. The token goes to curl on stdin (-K -), not on its command line, where other processes on the machine could read it. The || echo keeps a failed request from failing the pipeline; leave it out if a missing marker should stop the pipeline. The answer is 201 with the deploy:

JSON
{"deploy":{"author":null,"commit_sha":"9f1c2ab3d4e5f60718293a4b5c6d7e8f90a1b2c3","environment":"production","id":3,"new_issues":0,"source":"ingest_token","version":"v1.4.2", …}}

What to send

FieldWhat to put in it
versionrequiredWhat's live now, at most 100 characters: a tag (v1.4.2), a release name or the commit. Use the same value you set as LAMPWICK_DEPLOY, if any.
commit_shaoptionalThe deployed commit, hex.
repo_urloptionalThe repository's https:// URL. Lampwick links the commit as {repo_url}/commit/{commit_sha}.
authoroptionalWho deployed.
environmentoptionalproduction, staging, …
deployed_atoptionalRFC 3339 time it went live. Default: now. Never later than now.

Send it when the new release is live, not when the build starts. A deploy stays live until the next one, and issues belong to the deploy that was live when they were first seen. Staging and production in one project mix up: use a project per environment.

Let your agent add it

Paste this into Claude Code, Cursor or Codex in your repository:

Add a Lampwick deploy marker to this project's deploy. Docs: https://lampwick.dev/docs/deploys.md
1. Find where the app is deployed: a GitHub Actions workflow, a Forge/Ploi/Envoyer deploy script
   in the repo or its README, vercel.json, or another CI config. If you can't tell, ask me.
2. Add the matching recipe from the docs as the last step, after the release is live. Use the
   project's ingest token from the LAMPWICK_TOKEN secret or the server's .env; never write the
   token into a file in the repository.
3. A failed marker must never fail the deploy (keep the recipe's `|| true` or `|| echo`).
4. Tell me which secret I need to add and where, and show me the diff.

Check that it works

Run a deploy, then open the project's Deploys page in Lampwick. The deploy shows its version, commit and from CI. The charts get a marker at that time.

Troubleshooting

MessageCauseFix
401 send the project's ingest tokenThe token is a personal API token, or empty.Use the ingest token from the project's Settings page.
400 commit_sha must be a hexadecimal commit hash (4 to 64 characters)A tag or branch name in commit_sha.Put the tag in version and the hash in commit_sha.
400 version is requiredversion is empty, for example an unset CI variable.Check the variable you send as version.
429 at most 20 deploys sent with the ingest token per project per hourMore than 20 deploys in an hour, often a workflow that runs on every push to every branch.Record only production deploys.
Could not record the deploy: HTTP 401lampwick:deploy sent a token that isn't the project's ingest token.Copy the ingest token into .env again.
LAMPWICK_TOKEN is not set.lampwick:deploy runs where .env has no token.Add LAMPWICK_TOKEN to the site's .env.

Next: work with issues, including the list of issues new since the last deploy.