OpenClaw can send output to multiple messaging channels simultaneously, and you have full control over which output goes where. Cron job results can go to Telegram while interactive commands come through Discord. Alerts can go to a high-priority channel while routine reports go somewhere less intrusive. This article covers how to configure openclaw channel routing so each type of output reaches the right place, every time.
TL;DR
- Channel routing in OpenClaw (outbound delivery) is configured per cron job, per skill, and per tool call using the channel and target parameters.
- Interactive commands route automatically to the channel the message came in on.
- Cron jobs need explicit delivery config (channel + target) to reach a specific destination.
- Multiple channels can be active simultaneously, each with independent access controls.
Throughout this article you will see indented blocks like the ones below. Each one is a command you can paste directly into your OpenClaw chat. Your agent will run it and report back. You do not need to open a terminal or edit any files manually.
How OpenClaw channel routing works
When you send a message to OpenClaw from Discord, the response goes back to Discord. When you send from Telegram, the response goes back to Telegram. This is the default behavior for all interactive sessions in OpenClaw: the response channel matches the inbound channel automatically, with no configuration required. You do not need to configure anything for this to work.
Channel routing for openclaw becomes relevant in two scenarios. First: cron jobs and scheduled tasks, which are not triggered by an inbound message and have no automatic return channel. These need an explicit delivery destination configured or the output goes nowhere. Second: proactive outbound notifications, where you want the agent to reach out to a specific channel without waiting to be asked.
List all my active cron jobs. For each one, show me: the schedule, what it does, and where it delivers output. Flag any cron jobs that have no delivery destination configured.
If an openclaw cron job has no delivery config, it runs silently. The task executes, but any output the agent produces is discarded. This is a common source of confusion when a cron job that worked in testing appears to do nothing in production.
Configuring cron job delivery destinations
Every cron job in OpenClaw can have a delivery block that specifies where to send the result. The two required fields are channel (which messaging integration to use) and to (the recipient ID or channel ID within that integration).
Show me the delivery config for all my cron jobs. Which ones send to Telegram? Which ones send to Discord? Are any missing a delivery destination entirely?
To send a cron job result to Telegram:
Update cron job [job-id] to deliver output to Telegram. The recipient is my Telegram chat ID [your-chat-id]. Show me the updated delivery config before applying.
To send a cron job result to a Discord channel:
Update cron job [job-id] to deliver output to Discord channel [channel-id]. Show me the updated cron job config before applying.
To find a Discord channel ID: right-click the channel name in Discord with Developer Mode enabled and select Copy Channel ID.
Routing specific task types to specific channels
A useful pattern is to separate task types by channel based on urgency and interaction style. Telegram works well for time-sensitive alerts and quick notifications because push delivery to mobile is reliable and immediate. Discord works well for longer interactive sessions where you want to scroll back through context and work through a problem step by step.
One common setup that works well for personal operators:
- Telegram: morning brief, daily summaries, urgent alerts, anything that needs to reach you when you are away from a keyboard
- Discord: interactive sessions, debugging, long-running tasks where you want to track progress in a scrollable channel, pipeline runs
Review all my cron jobs. Which ones produce short summary output that would be well-suited for Telegram? Which ones produce longer output better suited for Discord? Suggest a routing plan, but do not apply any changes yet.
This split is not required. Many operators run everything through one channel and that works fine. The routing separation becomes valuable when you find yourself scrolling past pipeline logs to find an alert that needed your attention.
Sending proactive messages to a specific channel
Proactive messages are messages the agent sends without being asked, triggered by a cron job or an internal event. For these, the agent uses the message tool with an explicit channel and target.
Send a test message to my Telegram chat to confirm proactive delivery is working. The message should say: “Proactive delivery test from OpenClaw. If you received this, Telegram routing is working correctly.”
Send a test message to my Discord DM to confirm proactive delivery is working. The message should say: “Proactive delivery test from OpenClaw. If you received this, Discord routing is working correctly.”
If either test fails, the most likely cause is that the channel is not configured or the recipient ID is incorrect. The agent will report the error from the message tool if the send fails.
Setting up alert routing separate from regular output
Alerts benefit from a dedicated routing path. An alert is any output that requires your attention quickly: an agent error, a failed cron job, a detected anomaly, a threshold crossed. Regular output (summaries, reports, completed task notifications) can wait. Alerts should not.
The pattern for alert routing in OpenClaw is to use a high-priority notification channel (typically Telegram with push notifications enabled) and configure the agent to send alerts there explicitly.
Create a test alert scenario: simulate what happens when a cron job fails. Does the agent send a failure notification anywhere? If not, set up alert routing so that any cron job failure sends a notification to my Telegram chat ID [your-chat-id] with the job name and error message.
This requires configuring the cron job with a failure delivery path separate from its normal delivery path. Some setups use the same channel for both; others route successes to Discord and failures to Telegram to make failures immediately visible regardless of whether Discord is open.
Per-channel configuration for access control
Each channel in OpenClaw has its own access control config independent of the others. This means you can allow different sets of users on each channel without those settings affecting each other.
Show me the current access control config for all active channels. For each channel: what is dmPolicy, what is groupPolicy (if applicable), and who is in allowFrom? Are there any inconsistencies between channels that could cause unexpected access?
A common pattern for a personal agent with both Telegram and Discord active:
- Telegram: dmPolicy “allowlist” with your chat ID. Telegram does not have a groupPolicy equivalent in the same way Discord does , control is at the bot level.
- Discord: dmPolicy “allowlist” with your user ID, groupPolicy “allowlist” or “off”.
The access controls are independent. Locking down Discord does not affect who can reach the agent on Telegram, and vice versa. This is by design , each channel is a separate surface with its own trust model.
Testing your routing configuration end-to-end
Before relying on channel routing for important cron jobs or alerts, test every path you have configured. A delivery configuration that looks correct can fail silently if the recipient ID is wrong or the channel is not active.
Run a full channel routing test. For each active channel (Telegram, Discord), send a test message with the text “Routing test [channel-name] [timestamp]”. Confirm each message was delivered successfully and report any failures with the exact error.
After confirming the delivery paths work, run a test cron job end-to-end:
Trigger my [job-name] cron job immediately and confirm the output is delivered to the configured destination. Show me the delivery confirmation.
Troubleshooting: output not reaching the right channel
When output is not arriving at the expected channel, work through this sequence:
1. Confirm the channel is active. A channel that is configured but disabled (enabled: false) will not receive or send anything.
Check all channels in my openclaw.json. Is channels.telegram.enabled set to true? Is channels.discord.enabled set to true? Report the enabled status of each configured channel.
2. Confirm the recipient ID is correct. A wrong Telegram chat ID or Discord channel ID silently fails. The send call returns an error, but if the cron job does not surface errors, you will not see it.
Attempt to send a message to Telegram chat ID [your-chat-id] and Discord channel [channel-id]. Report whether each send succeeded or failed, and show me the exact error if it failed.
3. Confirm the cron job delivery config is saved. After updating a cron job’s delivery config, verify the change was actually persisted.
Show me the full config for cron job [job-id] including the delivery section. Is the channel and target I configured actually present in the saved config?
How session context interacts with channel routing
When you send a message to OpenClaw from a channel, you open an interactive session rooted in that channel. The agent’s responses during that session go back to the originating channel. If you then open a different channel and send another message, that creates a separate session with its own context.
This matters for channel routing because the two sessions do not share context by default. If you start a task in Discord and then follow up in Telegram, the agent does not automatically know the two are related. For tasks that span channels, use the same channel for the full task, or explicitly provide context when switching.
I am currently chatting with you from Discord. If I send you a message from Telegram about the same topic, will you have context from this Discord session? How should I handle follow-up questions that span channels?
The practical rule for managing multi-channel OpenClaw setups: pick one channel for interactive work on a given task and stay there. Use the second channel for automated delivery of cron output and alerts rather than interactive follow-up questions. This keeps session context clean and avoids confusion about which channel has the relevant history.
Logging task output alongside channel delivery
For critical cron jobs, it is worth writing output to a log file in addition to sending it to a channel. This gives you a persistent record that survives even if the channel delivery fails, and lets you review past runs without scrolling through chat history.
Update my [job-name] cron job so that in addition to delivering output to [channel], it also appends a summary to a log file at /home/node/.openclaw/workspace/logs/[job-name]-run.log with the timestamp and result. Show me the updated job config before applying.
Keeping logs in the workspace means they survive gateway restarts and are included in git commits if you push the workspace. For high-frequency jobs (every few minutes), log rotation prevents the file from growing indefinitely.
How large are the log files in my workspace logs/ directory? Are any of them growing large enough to need rotation? If so, suggest a log rotation approach that does not require external tools.
Running Telegram and Discord simultaneously
OpenClaw supports having multiple channels active at the same time with no performance penalty. The Telegram and Discord plugins run independently. Each handles its own WebSocket or API connection, its own access control config, and its own message queue independently. A problem with one does not affect the other.
The main thing to be aware of in a multi-channel setup is that both channels can receive commands simultaneously. If you send a task from Discord and another from Telegram at the same time, both will be processed. The agent runs them sequentially (one at a time per session), but both commands are in the queue.
Are both my Telegram and Discord channels currently active and connected? Show me the connection status of each channel plugin.
If you want to temporarily suspend one channel without disabling it permanently, set enabled: false for that channel and restart the gateway. The config stays intact and re-enabling is a single setting change plus restart.
Structuring cron output for channel delivery
How you format cron output affects how readable it is in the destination channel. Telegram renders markdown natively. Discord renders markdown with some differences. Raw HTML renders poorly in both. For channel delivery, plain text with light markdown is the most portable format.
For Telegram delivery, messages with bullet points, bold text, and short paragraphs read well. Telegram has a 4,096 character limit per message. Messages longer than this are automatically split by the OpenClaw Telegram plugin.
For Discord delivery, messages with code blocks and bullet points read well in most channels. Discord has a 2,000 character limit per message. Longer messages are split similarly.
Review the output format for my [job-name] cron job. Is the output structured appropriately for delivery to [channel]? If the output is too long or uses formatting that does not render well in that channel, suggest an improved format.
A practical pattern for long-output jobs: have the cron task produce a short summary (3 to 5 bullet points, under 500 characters) for channel delivery, and write the full output to a log file. This keeps the channel readable while preserving the full detail for when you need it.
Update my [job-name] cron job to produce a short summary for channel delivery (3 to 5 bullets, under 500 characters) and write the full detailed output to a log file. The channel should receive the summary; the log file keeps the full record.
Channel routing in shared team setups
When multiple people share an OpenClaw instance, channel routing can separate personal notifications from shared team output. The agent can be configured to send individual user alerts to each person’s DM while sending shared reports to a team channel.
This requires configuring multiple delivery targets: some cron jobs deliver to a shared Discord channel, others deliver via DM to individual Telegram or Discord accounts.
I want to set up channel routing so that shared reports go to Discord channel [channel-id] visible to the whole team, but alerts about my personal tasks go to my Telegram chat [chat-id] only. What cron job delivery config do I need for each type of job?
For team setups, it is also worth auditing which team members can trigger which channels. A team member with access to the Discord channel can send commands to the agent. Make sure the allowFrom list on each channel reflects who should actually have that access.
Channel routing best practices
A few patterns that consistently work well across different OpenClaw deployments:
Name cron jobs descriptively. When a delivery arrives in Discord or Telegram with a notification from a cron job, the job name tells you what ran. Job names like “morning-brief” and “disk-check” are immediately clear. Job names like “job-1” and “task-a” are not.
Test every delivery path after any config change. A change to channel config, a new cron job, or a gateway restart can silently break a delivery path. Run a proactive test message after any change that touches channel or cron config.
Route failures and successes separately for critical jobs. Configure the most important cron jobs with two delivery paths: one for successful completion (Discord, lower urgency) and one for failure (Telegram, higher urgency). This ensures a failure always reaches you even if Discord is not open.
Keep delivery configs in the cron job, not in the task prompt. Do not put channel delivery instructions inside the cron job’s task text. Use the delivery config block. Instructions in task text can be overridden by the model; the delivery config block is enforced by the framework.
Audit all my cron jobs for channel routing best practices. Check: are all jobs named descriptively? Do critical jobs have failure delivery paths? Are delivery destinations in the config block rather than the task prompt? Report any jobs that do not follow these practices.
External triggers and inbound webhook routing
OpenClaw channel routing covers both outbound delivery and inbound processing. Some setups involve inbound triggers from external systems, such as a webhook that fires when a server metric crosses a threshold or an external service sends a notification. When these inbound events arrive as part of an openclaw channel routing setup, they need to be processed and the resulting output needs a destination.
For setups using OpenClaw’s gateway with external integrations, the inbound channel determines where any resulting agent output goes. If an inbound webhook triggers an agent task, the result can be routed back out to any configured channel using the same delivery config patterns.
Do I have any external services or webhooks configured to send events to OpenClaw? If so, list them and tell me where the resulting agent output gets routed. Are there any inbound integrations without a configured output destination?
Channel routing in cron job chains
Some cron setups use chained jobs, where one job triggers the next based on a result or schedule. In a chain, the channel routing for each job in the chain needs to be considered separately. The first job delivers its output somewhere; the second job may deliver to a different destination.
The pattern that works reliably for cron chains is to define delivery at the chain level, not the individual job level. One job in the chain is designated the “reporter” and all delivery flows through it. The intermediate jobs write to shared state (a file or memory entry) rather than delivering directly to a channel.
Do I have any cron jobs that are part of a chain where one job triggers another? If so, show me how the output routing works across the chain. Is there a single delivery point at the end of the chain, or does each job in the chain deliver separately?
If you have intermediate jobs in a chain delivering to a channel, you may be getting partial updates that are confusing out of context. Consolidating delivery to the final job in the chain produces cleaner channel output with a complete picture of what happened across the full run.
Monitoring channel delivery health
Delivery failures are easy to miss. A cron job runs, the delivery attempt fails, and nothing appears in your channel. The cron job ran successfully but the output was silently dropped. From your perspective, the job simply did not run. In reality, the job ran fine but the delivery broke.
A simple monitoring approach: create a lightweight daily cron job that sends a single test message to each configured delivery channel. If you receive the test message, delivery is working. If you do not receive it, delivery is broken and needs investigation.
Create a daily cron job that runs at 9am and sends a one-line delivery health check to each of my configured channels (Telegram and Discord). The message should be: “Delivery health check [channel-name] [date] , all systems operational.” This job should run every day and confirm that outbound delivery is working.
When this test message stops arriving, you know delivery is broken before a real cron job fails silently. The investment is one short daily message per channel. The return is early warning on delivery failures that would otherwise be completely invisible until a real cron job fails and you have no idea why.
Discord-specific routing features
Discord offers channel structure features that Telegram does not: categories, dedicated channels for specific topics, and threads. You can take advantage of this structure in OpenClaw’s channel routing config by using different Discord channel IDs as delivery targets for different job types.
A practical Discord server structure for an OpenClaw operator:
- #openclaw-reports: daily summaries, completed task notifications, research results
- #openclaw-alerts: failures, errors, anything requiring action
- #openclaw-logs: verbose output, pipeline progress, detailed run records
- #openclaw-chat: interactive sessions, ad-hoc requests
I want to set up dedicated Discord channels for different OpenClaw output types. What channel IDs do I need to configure to route reports to one channel, alerts to another, and logs to a third? Show me the cron job delivery config format for targeting a specific Discord channel by ID.
Once the channels exist and have the right bot permissions, each cron job’s delivery target is just a channel ID. Changing where a job delivers requires only updating the ID in the delivery config.
Keeping your routing config documented
Channel routing config spreads across multiple cron jobs and potentially multiple config files. Over time, it becomes hard to remember which job delivers where and why. A simple routing map in your workspace prevents this from becoming a problem.
Create a file at /home/node/.openclaw/workspace/CHANNEL-ROUTING.md that documents all my current channel routing. For each cron job: name, schedule, delivery channel, and delivery target ID. For each configured channel: access control settings, current status. Keep this as a plain text reference I can check when I need to update routing.
Update this file whenever you change a delivery destination. It takes 30 seconds and saves significant debugging time when a delivery stops working and you are trying to remember what that cron job was supposed to send and where.
Read /home/node/.openclaw/workspace/CHANNEL-ROUTING.md. Is it current? Does it match the actual delivery config in my cron jobs? Update it if any entries are out of date.
Using memory to make routing decisions dynamically
Static delivery config routes all cron job output to a fixed destination. For more dynamic setups, OpenClaw can use stored memory to make routing decisions at runtime. For example, a memory entry could store a preference for where to receive certain output types, and the cron job task prompt could read that preference and route accordingly.
This is an advanced routing pattern and requires the memory plugin to be active and reliably storing values across sessions. It is not necessary for most setups. But for operators who want the agent to adapt its routing based on current context, such as routing to Telegram when traveling and Discord when at a desk, memory-driven routing makes this possible.
Store a routing preference in memory: my preferred channel for alerts is Telegram, and my preferred channel for reports is Discord. Then write a cron job task prompt that reads this preference from memory and delivers to the appropriate channel based on what is stored. Show me the task prompt before I apply anything.
If memory-driven routing feels like more complexity than the problem warrants, use static delivery config. The fixed destination approach covers the vast majority of OpenClaw multi-channel routing needs with zero runtime complexity and is the recommended starting point for all operators.
Troubleshooting: output arriving on the wrong channel
When openclaw channel routing output arrives somewhere unexpected, the cause is almost always one of three things: a cron job delivery config pointing to the wrong channel ID, an agent task explicitly routing output somewhere in its task prompt, or a default routing fallback kicking in because the configured destination failed.
A cron job is sending output to [wrong-channel] instead of [correct-channel]. Check the cron job delivery config and the task prompt for that job. Is the destination specified in the config, in the prompt, or both? Which one is taking precedence?
When both the delivery config and the task prompt specify a destination, the delivery config takes precedence. If the task prompt says “send to Telegram” but the delivery config says “send to Discord”, the output goes to Discord. The solution is to keep routing instructions in the config block only and remove them from the task prompt to avoid the conflict.
Check all my cron job task prompts for routing instructions (phrases like “send to”, “deliver to”, “notify via”). For any that have routing instructions in the prompt, confirm whether the delivery config block also has a destination set, and tell me which one will actually be used.
Verifying your complete routing setup
Before treating your openclaw channel routing config as production-ready, run a full end-to-end verification pass. This takes about five minutes and confirms every delivery path you have configured actually works.
- For each active channel, send a proactive test message from the agent and confirm it arrives.
- For each cron job, trigger it manually and confirm the output is delivered to the configured destination.
- For each cron job with a failure path configured, simulate a failure and confirm the failure notification arrives at the failure destination.
- Confirm that a message from an unauthorized user ID gets no response on each channel.
Run the complete openclaw channel routing verification. Step through each check: proactive delivery test for each channel, manual trigger of each cron job with delivery confirmation, and access control check. Report pass or fail for each item with enough detail to diagnose any failure.
If any item fails, address it before considering the routing setup complete. A routing configuration that has not been tested end-to-end is a routing configuration that will fail at the worst possible time, typically when a genuine time-sensitive alert needs to reach you and the delivery path is broken.
Once all items pass, your openclaw multi-channel routing is verified and ready for real use.
Frequently asked questions
Can one cron job deliver to both Telegram and Discord at the same time?
Not natively through a single delivery config entry. The delivery block supports one destination at a time. To send the same output to two channels, the two most reliable approaches are: configure two separate cron jobs on the same schedule each with a different delivery destination, or include explicit instructions in the task prompt to send output to both channels as part of completing the task. The two-job approach is more reliable because delivery is handled by the framework rather than the model.
What happens if the delivery channel is down when a cron job runs?
The cron job runs and the agent produces its output as normal. The delivery attempt then fails with an error from the messaging plugin. OpenClaw does not retry delivery automatically on failure. The output is not queued for later delivery when the channel recovers. If reliable delivery matters for a specific cron job, configure it to write output to a log file in addition to the channel send. The file write succeeds even when the channel delivery fails, so the result is always preserved.
Can I change which channel a cron job delivers to without stopping it?
Yes. Update the delivery config on the cron job and the change takes effect on the next scheduled run. Any currently running instance of that job completes using the old delivery config. The change does not interrupt a job in progress. No gateway restart is required for cron job delivery config changes, only for changes to the channel plugin config itself (the channels.discord or channels.telegram section).
How do I find my Telegram chat ID?
Send any message to your OpenClaw Telegram bot from your Telegram account. The agent receives the message and the metadata includes your chat ID. Ask your agent: “What is my Telegram chat ID from the message I just sent?” It will extract the exact numeric ID from the message metadata and tell you. This is the ID to use in all openclaw channel routing delivery configs that target Telegram.
Does routing to Discord require the bot to be in a specific channel?
Yes. The bot must have View Channel and Send Messages permissions in the specific Discord channel you are routing to. Channel-level permission overrides can block the bot even if the role-level permissions look correct. If delivery to a Discord channel is failing silently, check the channel permissions directly rather than just the role. Verify the bot’s channel-level permissions before relying on that channel as a delivery target in your openclaw channel routing config.
Can I route different cron jobs to different Discord channels?
Yes. Each cron job has its own delivery config. Set the target field to a different Discord channel ID for each job. One job can deliver to a #reports channel, another to a #alerts channel, another to a #logs channel, all from the same OpenClaw instance and the same Discord bot.
What is the difference between the channel parameter and the to parameter in delivery config?
Channel specifies which messaging integration to use: telegram, discord, or any other configured provider. To specifies the recipient within that integration, either a numeric user ID for direct messages or a channel/group ID for server channels and group chats. Both fields are required for delivery to work correctly. If channel is set but to is missing or empty, the openclaw channel routing delivery will fail because the framework has no way to determine where within the integration the message should go. Always verify both fields are populated when setting up or updating a delivery config.
