Skip to content
Smoke Signal

Continuous integration

Send CI results to your phone.

Add one HTTPS POST at the end of a job to send its result as a push notification. It works without an open dashboard tab, email digest, or chat channel.

  • Builds, tests, and deployments

    Send the final result of any job and include its run URL in the notification.

  • Push failed builds immediately

    Send a failure to Channel subscribers as soon as the job ends, without waiting for the next dashboard check.

  • Channels for a team

    Share a Channel invite with the team. Subscribers can receive notifications without creating an account.

Setup

Add one notification step.

Create a Channel, store its webhook URL as a CI secret, and post to it when the job ends. This example targets a GitHub-hosted Ubuntu runner. In another CI system, send the same request with its equivalent shell tools.

  1. 01

    Post the result

    Run the step on success and failure. Bound the request, use a fresh Idempotency-Key, and fail the step if the request fails or the Channel has no subscribers.

    - name: Notify phone
      if: always()
      env:
        WEBHOOK_URL: ${{ secrets.SMOKE_SIGNAL_WEBHOOK }}
        TITLE: "${{ github.workflow }}: ${{ job.status }}"
        BODY: "${{ github.repository }} on ${{ github.ref_name }}"
        RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
      run: |
        idempotency_key=$(openssl rand -hex 16)
        response=$(jq -n --arg title "$TITLE" --arg body "$BODY" --arg url "$RUN_URL" \
          '{title: ($title | .[0:80]), body: ($body | .[0:240]), url: $url, ttl_seconds: 3600}' |
          curl -sS --fail-with-body "$WEBHOOK_URL" \
            --request POST \
            --connect-timeout 10 \
            --max-time 30 \
            --header 'Content-Type: application/json' \
            --header "Idempotency-Key: $idempotency_key" \
            --data @-) || { echo "$response"; exit 1; }
        test "$(jq -r .dropped <<< "$response")" = false ||
          { echo "Nobody is subscribed to this channel."; exit 1; }
  2. 02

    Expire stale results

    Set ttl_seconds so a delayed result expires instead of arriving after it is useful.

Decisions

Pause a pipeline for a Decision.

A deploy job can create a Decision such as "Promote to production?" with two to four choices, then wait for a Channel subscriber to select an answer.

Waiting uses runner time, so set a short deadline and a failure or timeout fallback. The API docs include the endpoints, schemas, and a worked example.

Good to know

Requirements and limits.

  • Plain REST: webhook URL or bearer API key, JSON in, JSON out.
  • Every send needs an Idempotency-Key of 16 to 128 characters. Reuse one only to retry the same request.
  • A 201 with "dropped": true means nobody was subscribed to receive it. Treat it as a failure in CI, not a success.
  • Free for individuals. No card required.
  • Rate limits apply.

Start receiving

Add Smoke Signal to your pipeline.