How to Send Discord Webhooks From a Cron Job
🔍 WiseChecker

How to Send Discord Webhooks From a Cron Job

You want to send automated messages to a Discord channel at scheduled times. A cron job running on a Linux server can trigger a webhook URL that posts messages to Discord. This setup lets you send daily reports, server alerts, or any periodic notification without manual effort. This article explains how to create a Discord webhook, write a script that sends data to it, and schedule that script with cron.

Key Takeaways: Sending Discord Webhooks via Cron

  • Server Settings > Integrations > Webhooks: Create a webhook URL that posts messages to a specific channel.
  • curl command with JSON payload: Send a POST request with content-type application/json to the webhook URL.
  • crontab -e: Schedule the script to run at any interval using cron syntax.

What a Discord Webhook Is and How It Works

A Discord webhook is a simple way to send messages to a Discord channel from an external source. You create a webhook URL inside a server channel, and any application that sends a properly formatted HTTP POST request to that URL can post a message. The message can include text, embeds, file attachments, and mentions. No bot token or OAuth is required. The webhook acts like a user account that posts messages under the webhook name and avatar you set during creation.

Prerequisites for Sending Webhooks From Cron

Before you start, you need three things. First, a Discord server where you have the Manage Webhooks permission. Second, a Linux or Unix server where you can edit crontab and execute scripts. Third, the curl command must be installed on that server. Most Linux distributions include curl by default. If it is missing, install it with your package manager, for example sudo apt install curl on Debian or Ubuntu.

How Cron Scheduling Works

Cron is a time-based job scheduler in Unix-like operating systems. You define a schedule using five fields: minute, hour, day of month, month, and day of week. A cron job runs a command or script at the times you specify. For example, 0 9 runs a job every day at 9:00 AM. The cron daemon executes the job in a minimal environment, so you must use absolute paths for scripts and commands.

Steps to Create and Schedule a Discord Webhook With Cron

Step 1: Create a Webhook in Discord

  1. Open Server Settings
    Right-click your server name in the left sidebar and select Server Settings. If you do not see this option, you do not have the Manage Server permission.
  2. Go to Integrations
    In the left menu of Server Settings, click Integrations. Then click the Webhooks button.
  3. Create a Webhook
    Click the Create Webhook button. A new webhook entry appears with a default name and avatar.
  4. Set the Channel and Name
    Click the webhook entry to expand it. Under Channel, select the text channel where messages will appear. Under Name, type a display name such as Server Alerts. You can also upload a custom avatar.
  5. Copy the Webhook URL
    Click the Copy Webhook URL button. The URL looks like https://discord.com/api/webhooks/1234567890/abcdefg. Save this URL in a secure place. Anyone with this URL can post messages to the channel.

Step 2: Write a Script That Sends the Webhook

Create a shell script that uses curl to send a POST request to the webhook URL. The minimal payload is a JSON object with a content field. Below is a complete example script named send-discord.sh.

#!/bin/bash

WEBHOOK_URL="https://discord.com/api/webhooks/1234567890/abcdefg"
MESSAGE="Hello from cron job at $(date)"

curl -H "Content-Type: application/json" \
     -X POST \
     -d "{\"content\":\"$MESSAGE\"}" \
     $WEBHOOK_URL

Replace the WEBHOOK_URL value with the URL you copied. Save the file and make it executable with chmod +x send-discord.sh. Test the script by running ./send-discord.sh from the terminal. You should see the message appear in your Discord channel.

Step 3: Advanced Payloads With Embeds

You can send richer messages using Discord embed objects. An embed can include a title, description, color bar, fields, footer, and timestamp. Below is an example script that sends an embed.

#!/bin/bash

WEBHOOK_URL="https://discord.com/api/webhooks/1234567890/abcdefg"

curl -H "Content-Type: application/json" \
     -X POST \
     -d '{
       "embeds": [{
         "title": "Daily Report",
         "description": "Server status for $(date)",
         "color": 5814783,
         "fields": [
           {"name": "CPU Load", "value": "0.45", "inline": true},
           {"name": "Memory Usage", "value": "3.2 GB / 8 GB", "inline": true}
         ],
         "footer": {"text": "Cron Job"},
         "timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
       }]
     }' \
     $WEBHOOK_URL

The color value is a decimal representation of a hex color. For example, 5814783 corresponds to the hex color #58B9FF. Use a color converter to find the decimal value for any color.

Step 4: Schedule the Script With Cron

  1. Open the Crontab Editor
    Run crontab -e in your terminal. If this is the first time, you may be asked to choose an editor. Select nano or vim.
  2. Add a Cron Job Line
    At the bottom of the file, add a line that defines the schedule and the script path. Use the absolute path to the script. For example, to run the script every day at 9 AM:
    0 9
    /home/username/send-discord.sh
  3. Save and Exit
    In nano, press Ctrl+O to save, then Ctrl+X to exit. In vim, press Esc, type :wq, and press Enter. Cron installs the new schedule and starts running the job at the specified times.

Step 5: Verify the Cron Job Is Running

Check the cron log to see if the job ran. On most systems, cron logs are written to /var/log/syslog or /var/log/cron. Search for your script name with grep send-discord /var/log/syslog. You can also add a simple log file inside your script by appending a line like echo "$(date): Message sent" >> /home/username/cron.log.

Common Issues When Sending Webhooks From Cron

Script Runs From Terminal But Not From Cron

Cron runs with a limited PATH environment variable. If curl is not in the default PATH, the script fails. Use the full path to curl in your script. Find it by running which curl — typically /usr/bin/curl. Replace curl with /usr/bin/curl in the script. Also, use absolute paths for all file references.

Webhook URL Is Exposed in the Script

Storing the webhook URL in a script file is a security risk if the script is readable by other users. Set restrictive permissions with chmod 700 send-discord.sh. Alternatively, store the URL in an environment variable and reference it in the script. Add the variable to your crontab with WEBHOOK_URL=your_url before the job line, then use $WEBHOOK_URL in the script.

JSON Payload Is Malformed

If the Discord API returns a 400 Bad Request, the JSON payload is invalid. Common mistakes include missing commas, unescaped double quotes inside strings, or trailing commas in arrays. Validate your JSON with a tool like jq. Run echo 'your_json' | jq . to see parsing errors.

Rate Limiting From Frequent Posts

Discord enforces rate limits on webhook requests. The limit is 30 requests per 60 seconds per webhook. If your cron job runs more often than once per two seconds, you may receive 429 Too Many Requests responses. Schedule your cron job at intervals of at least two seconds or implement retry logic with exponential backoff.

Cron Scheduling Patterns vs Discord Webhook Payload Types

Item Simple Text Message Embed with Fields
Payload size Small, under 2000 characters Larger, up to 6000 characters total
Use case Quick alerts or status updates Detailed reports with structured data
curl complexity Simple single-line JSON Multi-line JSON with nested objects
Color support No Yes, via color field
Multiple fields No Up to 25 fields

You now have a working system that sends Discord messages automatically using cron. The webhook URL and curl script handle the communication. To extend this setup, consider adding conditional logic in the script to send different messages based on server metrics. A useful next step is to include file attachments by using the multipart/form-data content type instead of JSON.