Building an Automated Discord Notification System with n8n and Dynamic Timestamps
Step-by-step developer tutorial on creating automated Discord notifications using n8n workflows, webhook payloads, and localized Unix timestamps.
Key Takeaways & Summary
- •Discord webhooks accept dynamic timestamp syntax (<t:EPOCH:STYLE>) inside message content, embed descriptions, and embed field values.
- •The top-level embed 'timestamp' property requires an ISO 8601 string and only controls the static footer timestamp.
- •In n8n Code nodes, use Math.floor(new Date(inputDate).getTime() / 1000) to produce valid 10-digit epoch seconds.
- •Discord webhook endpoints enforce a strict rate limit of 5 requests per 2 seconds per webhook URL.
- •Always set up error fallback handling in n8n to capture invalid dates before they trigger 400 Bad Request responses.
- •Batch execution in n8n should include throttled delays to prevent Cloudflare IP rate limits.
Connecting external systems to Discord via n8n automation is standard practice for modern teams. Here is how to format webhook payloads with dynamic, auto-adjusting timestamps.
Automated server alerts for server health monitoring, calendar events, GitHub pull requests, and automated deployment pipelines keep distributed teams informed. However, when an automation workflow posts a static timestamp like 'Deployed at 14:00 UTC', team members must mentally convert that time to their local clock. By incorporating Discord dynamic timestamp tokens (<t:EPOCH:STYLE>) into your n8n webhook nodes, your automated messages render in each viewer personal timezone. This developer guide demonstrates how to configure n8n workflows, handle ISO 8601 date transformations in JavaScript Code nodes, and format Discord webhook embed payloads cleanly.
Discord Webhook Architecture: Two Different Timestamp Types
When working with Discord REST API webhooks, developers frequently confuse two distinct timestamp mechanisms supported by Discord embed specifications:
1. The Top-Level Embed Timestamp: This is a JSON property named 'timestamp' on the root embed object. It requires a standardized ISO 8601 string (such as '2026-09-25T20:00:00.000Z'). Discord renders this string as a tiny static date in the bottom footer of the embed.
2. Dynamic Content Timestamps: These are inline tokens (<t:EPOCH:STYLE>) placed inside the regular 'content' string, the embed 'description', or within embed 'fields'. Discord client parses these tokens into interactive, localized badges.
For calendar alerts, release notifications, and upcoming deadlines, you should always place dynamic tokens inside embed descriptions and field values.
{
"username": "Release Bot",
"avatar_url": "https://i.imgur.com/4M34hi2.png",
"content": "🚀 **New Production Release Deployed**",
"embeds": [
{
"title": "Version 2.4.0 Deployment Summary",
"color": 5793266,
"description": "Deployment completed at <t:1790379960:f>.\nPost-deployment health checks finalize <t:1790381760:R>.",
"fields": [
{
"name": "Service Restart Time",
"value": "<t:1790379960:T>",
"inline": true
},
{
"name": "Next Maintenance Window",
"value": "<t:1790984760:D>",
"inline": true
}
],
"timestamp": "2026-09-25T20:00:00.000Z",
"footer": {
"text": "Infrastructure Monitor"
}
}
]
}Building the n8n Workflow: Transforming Dates to Epoch Seconds
In an n8n workflow, external triggers (such as Google Calendar, Jira, or Stripe) typically provide dates in ISO 8601 strings or formatted calendar dates. Before sending this data to Discord, we insert an n8n Code node to compute the 10-digit Unix epoch integer.
The n8n Code Node Script
Add a Code node (Run Once for Each Item) immediately following your trigger node and paste this transformation script:
// Extract incoming date from upstream trigger (e.g., event_start)
const inputDateString = $input.item.json.start_time || new Date().toISOString();
// Convert input string to JavaScript Date object
const dateObj = new Date(inputDateString);
// Guard against invalid date strings
if (isNaN(dateObj.getTime())) {
throw new Error(`Invalid date received: ${inputDateString}`);
}
// Compute 10-digit Unix epoch in seconds (floor division)
const epochSeconds = Math.floor(dateObj.getTime() / 1000);
// Construct pre-formatted Discord tokens for easy webhook mapping
return {
json: {
...$input.item.json,
discord_epoch: epochSeconds,
discord_full: `<t:${epochSeconds}:F>`,
discord_relative: `<t:${epochSeconds}:R>`,
discord_short_time: `<t:${epochSeconds}:t>`
}
};Configuring the Discord Webhook Node in n8n
Next, connect an HTTP Request node configured to send a POST request to your Discord Webhook URL:
• Method: POST • URL: Your Discord Webhook URL • Body Content Type: JSON • Specify Body: Using JSON
In the JSON body editor, reference your pre-formatted tokens using n8n expression syntax:
{ "content": "Scheduled Maintenance Alert: {{ $json.discord_full }} ({{ $json.discord_relative }})" }
Securing Webhook Credentials in n8n
Never paste raw Discord webhook tokens into hardcoded workflow strings. Store the webhook URL in n8n Credentials or Environment Variables. This ensures that exporting your workflow JSON does not leak your Discord channel posting authority.
Testing Your Webhook Payload with cURL
Before activating your n8n workflow in production, test your Discord webhook endpoint directly from your terminal using cURL. This validates that your webhook token is active and your payload syntax is accepted by Discord API servers.
curl -H "Content-Type: application/json" \
-X POST \
-d '{
"username": "Alert System",
"content": "Incident resolved at <t:1790379960:F> (<t:1790379960:R>)"
}' \
https://discord.com/api/webhooks/123456789012345678/your_webhook_token_hereProduction Reliability: Rate Limits and Error Handling
When deploying production automation workflows, you must handle network edge cases and Discord platform restrictions.
Discord Webhook Rate Limits
Discord enforces a limit of 5 requests per 2 seconds per webhook URL. If your workflow processes batch events (such as importing 50 calendar events at once), firing 50 consecutive HTTP requests will result in HTTP 429 Too Many Requests errors.
In n8n, resolve this by adding a Split In Batches node set to a batch size of 4, followed by a Wait node set to 2.5 seconds between batches. This guarantees that your automation stays comfortably within Discord rate limit windows.
Handling Null or Undefined Dates
If an external API occasionally returns null for a date property, passing null into new Date() produces a date initialized to January 1, 1970 (epoch 0). Your Discord message will render as 'Thursday, January 1, 1970'. Always include a conditional check in your n8n code to provide a fallback notice or halt the notification when date properties are missing.
Frequently Asked Questions
Straightforward answers to common questions about this topic.
No. The embed footer text field does not support Markdown or dynamic timestamp tokens. If you place a token in footer.text, it displays as raw code. Use the top-level timestamp property for footers instead.
Generate Your Discord Timestamps Now
Convert any date or countdown into auto-adjusting Discord tags with 1-click copy.