Skip to content

Discord Notification

Posts embed-style or plain-text Discord webhook messages with sensible defaults sourced from the current GitHub run.

Inputs

Input Required Default Description
webhook_url HTTPS Discord webhook endpoint the action POSTs to; must point to discord.com/discordapp and is always required.
message_type embed Controls the payload structure; defaults to 'embed', but set to 'message' to send plain text content.
title Embed title text; ignored when message_type is set to message.
description Embed body/description text appended under the title; ignored for plain messages.
content Plain-text body sent when message_type is message.
color Decimal color value applied to the embed sidebar; Discord falls back to its default gray when omitted.
fields Literal JSON array string inserted into the embed fields collection (for example [{"name":"Field","value":"Value","inline":true}]).
username Overrides the webhook display name; defaults to the triggering GitHub actor when blank.
avatar_url Sets a custom avatar image; defaults to the actor's GitHub avatar URL.
footer_text Footer text rendered at the bottom of embeds; defaults to "/".
footer_icon_url Optional icon that appears next to the footer text; left unset otherwise.
image_url Displays a full-width image inside the embed when provided.
thumbnail_url Sets the small thumbnail shown in the embed's upper-right corner.
author_url Hyperlink applied to the embed author name (usually the GitHub actor).
url Destination URL applied to the embed title when set.

Usage

Embed notification with dynamic fields (.github/workflows/check-pr.yml):

build-discord-fields-completion:
  name: Build Discord Fields
  runs-on: ubuntu-latest
  needs: [run-integration-tests]
  if: always()
  outputs:
    discord_fields: ${{ steps.discord_fields.outputs.fields }}

  steps:
    - name: Build Discord Fields
      id: discord_fields
      run: |
        SUMMARY_STATUS="${{ needs['run-integration-tests'].result }}"

        # Build JSON fields with readable formatting
        FIELDS=$(jq -n \
          --arg summary_status "$SUMMARY_STATUS" \
          --arg pr_number "${{ github.event.pull_request.number }}" \
          --arg pr_url "${{ github.event.pull_request.html_url }}" \
          --arg actor "${{ github.actor }}" \
          --arg run_url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
          --arg total_tests "${{ needs.run-integration-tests.outputs.total_tests }}" \
          --arg passed_tests "${{ needs.run-integration-tests.outputs.passed_tests }}" \
          --arg failed_tests "${{ needs.run-integration-tests.outputs.failed_tests }}" \
          --arg total_duration "${{ needs.run-integration-tests.outputs.total_duration }}" \
          --arg average_duration "${{ needs.run-integration-tests.outputs.average_duration }}" \
          '[
            {"name": "Step Summary Test", "value": (($summary_status == "success" and "✅ Passed" or "❌ Failed")), "inline": true},
            {"name": "Total Tests", "value": $total_tests, "inline": true},
            {"name": "Passed Tests", "value": ("✅ " + $passed_tests), "inline": true},
            {"name": "Failed Tests", "value": ((($failed_tests == "0") | if . then "✅ " else "❌ " end) + ($failed_tests | tostring)), "inline": true},
            {"name": "Total Duration", "value": ($total_duration + "s"), "inline": false},
            {"name": "Average Duration", "value": ($average_duration + "s"), "inline": false},
            {"name": "PR Details", "value": ("[#" + $pr_number + "](" + $pr_url + ") by @" + $actor), "inline": false},
            {"name": "Run Details", "value": ("[View Full Run](" + $run_url + ")"), "inline": false}
          ]')

        # Use delimiter to safely output the multiline JSON
        delimiter="$(openssl rand -hex 8)"
        {
          echo "fields<<${delimiter}"
          echo "$FIELDS"
          echo "${delimiter}"
        } >> "$GITHUB_OUTPUT"

notify-completion:
  name: Notify Discord
  uses: ./.github/workflows/discord-notify.yml
  needs: [build-discord-fields-completion, run-integration-tests]
  if: always()
  secrets:
    webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
  with:
    message_type: "embed"
    title: ${{ needs['run-integration-tests'].result == 'success' && '✅ PR CI Workflow Completed Successfully' || '⚠️ PR CI Workflow Completed with Issues' }}
    description: ${{ needs['run-integration-tests'].result == 'success' && 'All validation checks and tests passed successfully. The pull request is ready for review.' || 'The workflow completed but some checks failed. Please review the results and address any issues.' }}
    color: ${{ needs['run-integration-tests'].result == 'success' && '3066993' || '16776960' }}
    fields: ${{ needs.build-discord-fields-completion.outputs.discord_fields }}

Field payloads

Provide fields as a JSON array of { "name": "...", "value": "...", "inline": bool } objects. Remember to escape quotes or use heredocs when building multi-line JSON.