Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cachet Laravel Package

cachethq/cachet

Cachet is a beautiful, self-hosted status page system built with Laravel. Create incidents, track component status, schedule maintenance, notify subscribers, and expose a JSON API to keep users informed during outages.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: Cachet is an application, not a library. You do not composer require cachethq/cachet into an existing Laravel app. It ships its own routes, models, migrations, and config, and it assumes it owns the whole Laravel bootstrapping. Treat it as a service you deploy next to your product — a Docker image, a separate host, or a subdomain behind your ingress.

Minimal path (Docker Compose, MySQL, queue worker included):

services:
  cachet:
    image: cachethq/docker:2.4   # pin the tag; see Gotchas
    env_file: .env
    ports: ["8080:8000"]
    depends_on: [mysql, redis]
  queue:
    image: cachethq/docker:2.4
    command: php artisan queue:work --tries=3
    env_file: .env
    depends_on: [mysql, redis]
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: cachet
      MYSQL_ROOT_PASSWORD: secret
  redis:
    image: redis:7-alpine

.env essentials: APP_URL, APP_KEY (php artisan key:generate), APP_ENV=production, APP_DEBUG=false, DB_*, CACHE_DRIVER=redis, SESSION_DRIVER=redis, QUEUE_DRIVER=redis, and a working MAIL_* block. Then run migrations, seed the admin user, and change the default credentials immediately:

docker compose run --rm cachet php artisan migrate --force
docker compose run --rm cachet php artisan db:seed --force

Where to look first, in this order:

  1. /api/v1/components and /api/v1/incidents — this is where 90% of your integration work happens.
  2. Your user profile page → API Token. That token is the only credential the API accepts.
  3. config/ (cachet.php, mail.php, database.php) and routes/api.php in the source tree.
  4. resources/views/ for branding, app/Http/Controllers/Api/ for the request/response contract.

First use case — prove the credential, then open an incident:

curl -s -H "X-Cachet-Token: $CACHET_TOKEN" \
  "$CACHET_URL/api/v1/components" | jq '.[] | {id, name, status}'

curl -s -X POST "$CACHET_URL/api/v1/incidents" \
  -H "X-Cachet-Token: $CACHET_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "name": "Elevated error rate on checkout",
        "message": "We are investigating elevated 5xx responses.",
        "status": 1,
        "visible": 1,
        "component_id": 3,
        "component_status": 3,
        "notify": true
      }'

Public GET endpoints (components, incidents, metrics) work without a token, which is what makes the status page and any custom embed possible. Writes always need X-Cachet-Token.

Implementation Patterns

1. CI/CD → incident lifecycle. The highest-value integration: your deploy pipeline opens an incident on failure and resolves it on success. Keep the incident ID so the resolution is deterministic.

# open (only if one isn't already open for this component)
ID=$(curl -s -X POST "$CACHET_URL/api/v1/incidents" \
  -H "X-Cachet-Token: $CACHET_TOKEN" -H "Content-Type: application/json" \
  -d "{\"name\":\"Deploy $GITHUB_SHA failed\",\"message\":\"$SUMMARY\",
       \"status\":1,\"visible\":1,\"component_id\":$COMPONENT_ID,
       \"component_status\":4,\"notify\":true}" | jq -r '.data.id')
echo "CACHET_INCIDENT_ID=$ID" >> "$GITHUB_ENV"

# resolve on the success path
curl -s -X PUT "$CACHET_URL/api/v1/incidents/$CACHET_INCIDENT_ID" \
  -H "X-Cachet-Token: $CACHET_TOKEN" -H "Content-Type: application/json" \
  -d '{"status":4,"component_status":1,"message":"Deploy recovered. All systems operational."}'

2. Monitoring/alerting → your enum mapping table. Cachet's numeric enums are the single biggest source of wrong-looking status pages. Put the mapping in one shared constant file and never inline integers again.

Incident status Meaning Component status Meaning
1 Investigating 1 Operational
2 Identified 2 Performance Issues
3 Watching 3 Partial Outage
4 Fixed 4 Major Outage

Scheduled-maintenance statuses are a different enum (0 Scheduled, 1 In Progress, 2 Complete) — don't reuse the incident one.

3. Alertmanager/webhook bridge. Cachet has no inbound webhook endpoint, so put a thin relay in front of it (a 20-line Lambda, a Laravel route in your app, or a Node worker). The relay owns the mapping "alertname → component_id", dedupes by fingerprint, and calls Cachet. Alertmanager's group_interval plus Cachet's create-on-every-POST means without dedupe you will spam subscribers.

4. Component status as a health mirror — but explicitly. A cron that runs GET /api/v1/components, compares against your own health checks, and PUTs changed components is a great lightweight uptime signal. Remember that component status and incident status are independent columns: closing an incident does not reset the component. Always send component_status: 1 on resolve.

5. Maintenance windows. POST /api/v1/schedules with name, message, scheduled_at, completed_at, status, and the component list. Create the schedule when you book the change, then PUT it to 1 (In Progress) at start and 2 (Complete) at end. This keeps planned downtime off the incident feed, which is exactly what on-call people want.

6. Metrics for uptime graphs. Create a metric once (POST /api/v1/metrics, {"name":"API Uptime","suffix":"%","default_view":1}), then push points from cron:

curl -s -X POST "$CACHET_URL/api/v1/metrics/$METRIC_ID/points" \
  -H "X-Cachet-Token: $CACHET_TOKEN" -H "Content-Type: application/json" \
  -d "{\"value\": 99.94, \"timestamp\": $(date +%s)}"

Points are append-only; there is no update endpoint, so compute correctly before pushing.

7. Subscribers and email. POST /api/v1/subscribers with {"email":"[email protected]"} triggers double opt-in. Keep the queue worker running and mail configured before you flip notify: true on any incident — synchronous mail on a large subscriber list will hang the request.

8. Custom embedding. No official badge widget, but unauthenticated GET /api/v1/components plus GET /api/v1/incidents?sort=created_at&order=desc gives you everything needed for a status pill in your own app, refreshed by a queued job with a short cache TTL.

9. Branding. Fork resources/views/ for layout changes and drop static assets in public/. Prefer CSS overrides in a custom view layer; patching PHP directly makes every upgrade a merge conflict.

10. Config as code. Bootstrap components via API in a seed script rather than clicking them in, so a rebuilt instance converges to the same state.

Gotchas and Tips

  • Licensing metadata is NOASSERTION. Read LICENSE in the repo before bundling or redistributing, especially for a commercial white-label status page. Don't assume MIT because it's a Laravel app.
  • API tokens are unscoped and effectively root. Any token can delete components, read subscribers, and rewrite incidents. Never put it in front-end JS or a public CI log — use a masked secret, rotate on every offboarding, and route writes through your relay rather than handing the token to five pipelines.
  • Pin the image tag. Last tagged release was November 2023 and the project has been through a heavy rewrite (v3). v2 and v3 differ in framework version, frontend, and API surface; an unpinned latest is how you get a Friday-night migration. Back up the database before any upgrade and read the changelog for migrations.
  • APP_DEBUG=false in production. Cachet stack traces will happily print DB credentials and env vars on the public status page.
  • Config and route caching bite after .env edits. php artisan config:clear && php artisan cache:clear (or rebuild the container) — otherwise mail/DB changes silently don't apply.
  • Empty MAIL_* is not an error, it's a silent drop. Incidents resolve fine, subscribers get nothing. Add a smoke test that subscribes a real address and checks delivery.
  • Always send Accept: application/json. Without it you can get HTML error pages back and your jq pipeline reports nulls instead of the actual validation message.
  • visible is a separate flag from status. A resolved incident with visible: 0 disappears from the public page but stays in the DB — handy for internal-only blips, confusing when someone forgets to set it to 1.
  • No outbound webhooks and no built-in SSO/multi-team. If you need Slack fan-out, poll the API on a schedule or have your relay emit to both Cachet and Slack. Auth beyond local users requires a reverse proxy (OAuth2 proxy, SAML gateway) in front.
  • Data growth. subscribers and metric points grow unboundedly. Prune stale unverified subscribers and roll up old points; a four-second status page is usually an unindexed table, not a PHP problem.
  • Deleting is hard to undo. Components referenced by incidents and metrics are best archived/hidden rather than deleted. Test delete flows against a scratch instance.
  • Extension points, in order of safety: custom views/CSS → the public API from your own system → a thin relay service → last resort, a fork. Do not write directly to Cachet's tables from another app; the schema is not a stable contract.
  • Debugging loop: storage/logs/laravel.log inside the container, php artisan route:list | grep api/v1 to confirm the endpoint actually exists in your pinned version, and a GET /api/v1/components with the token to separate auth failures from request-shape failures.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core