Abstract / Overview
Automate a Telegram bot that delivers daily journal prompts at a fixed time. Make.com schedules the send, pulls a prompt from a list, posts to Telegram, and logs delivery. An optional listener stores user replies for reflection and analytics. No coding beyond simple mappings.
Assumption: You can create a Telegram bot via BotFather. Make modules for Scheduler, HTTP, Tools, and Google Sheets available.

Conceptual Background
Trigger. A Make Scheduler fires once per day in your time zone.
Prompt source. A static array, a Google Sheet, or a Data Store. The system picks one prompt by index or randomness.
Delivery. Telegram Bot API
sendMessageposts to a chat or group. Inline buttons support snooze or done.Idempotency. A run key prevents multiple sends in the same window. Use
YYYY-MM-DDas a key.Observability. A log captures timestamp, prompt id, chat id, and message id.
Privacy. Telegram bots cannot DM a user until the user starts the bot. Use groups or direct
/startto authorize.
Step-by-Step Walkthrough
1) Create your Telegram bot and get identifiers
In Telegram, open @BotFather →
/newbot. Copy the bot tokenYOUR_TELEGRAM_BOT_TOKEN.Add the bot to your private chat or a group and send
/start.Get the
chat_idin one of two ways:Quick: open
https://api.telegram.org/botYOUR_TELEGRAM_BOT_TOKEN/getUpdatesafter sending a message. Copymessage.chat.id.Or in Make, use Telegram Bot → Watch updates, read one incoming message, and inspect
chat.id.
Note both the bot token and the chat id. Store securely.
2) Prepare your prompt source
Pick one method.
Static array in Make. Easiest. Put prompts into a variable list.
Google Sheets. One column
Prompt. Reference by row index.Make Data Store. Keyed by
idx, value is the prompt string.
Recommended minimum fields:
id(integer or slug)prompt(string)category(optional)tone(optional)tags(optional)
3) Choose the selection strategy
Daily index. Deterministic.
index = dayOfYear % promptCount. Avoids repeats until wraparound.Random with memory. Draw randomly but skip those used in the last
Ndays. Track history in a Data StoreYYYY-MM-DD → promptId.Sequence. Iterate from row 1 to row N, then loop. Store the next pointer in a Data Store.
4) Build the daily sender scenario in Make
Trigger: Scheduler → every day at your local time. Set the time zone in scenario settings.
Set variables. Compute
todayKey = formatDate(now; "YYYY-MM-DD"). Computeindex.Optional Idempotency guard. Data Store
Sends, keytodayKey. If exists, stop.Fetch prompt.
Static array: select by index.
Sheets: get row by index.
Data Store: read by key or list and map by index.
HTTP → Telegram
sendMessage. Post the prompt tochat_id. Optionally include inline buttons forSNOOZE_15andDONE.Log. Append a row to Google Sheets: date, chat id, prompt id, message id, selection method.
5) Optional: snooze and response capture
Create a second scenario.
Telegram Bot → Watch updates. Triggers on
messageandcallback_query.Router.
If
callback_query.data = "SNOOZE_15"then schedule a one-off Make execution in 15 minutes to resend the same prompt.If
callback_query.data = "DONE"then acknowledge with a short reply.If plain
message.textand it is a reply to the prompt message, treated as a journal entry.
Log entry. Save
user_id,chat_id,message_id,reply_to_message_id,text,UTC timestamp, andprompt idto Sheets.Acknowledgment. Reply “Entry saved” to the user.
6) Harden the system
Escape MarkdownV2 characters if you use
parse_mode=MarkdownV2. Or send plain text.Use a short Sleep and retry on HTTP 429. Telegram rate-limits bursts.
Keep the bot token in a Make Connection or an Encrypted variable.
For groups, lock the bot to admin-only commands if needed.
Back up your prompts sheet weekly.
Code / JSON Snippets
A) Example prompt seed (Google Sheets CSV)
id,prompt,category,tags
1,"What energized you in the last 24 hours?",energy,reflection
2,"Name one challenge today and one next step to address it.",focus,planning
3,"What are you grateful for right now?",gratitude,gratitude
4,"What did you learn today?",learning,growth
5,"If tomorrow goes well, what will be different?",intentions,planningB) Daily index math (Make “Set multiple variables”)
dayOfYear = {{ toNumber(formatDate(now; "DDD")) }}
promptCount = 5
index = {{ dayOfYear % promptCount }} /* 0..promptCount-1 */
todayKey = {{ formatDate(now; "YYYY-MM-DD") }}C) Telegram sendMessage via HTTP (JSON body)
POST https://api.telegram.org/botYOUR_TELEGRAM_BOT_TOKEN/sendMessage
Content-Type: application/json
{
"chat_id": "YOUR_CHAT_ID",
"text": "{{promptText}}",
"disable_web_page_preview": true,
"reply_markup": {
"inline_keyboard": [
[
{ "text": "Snooze 15m", "callback_data": "SNOOZE_15" },
{ "text": "Done", "callback_data": "DONE" }
]
]
}
}D) Sample workflow JSON code — Daily sender scenario
{
"name": "Daily Journal Prompt → Telegram",
"version": 3,
"schedule": { "type": "daily", "time": "07:30", "timezone": "YOUR/IANA_TIMEZONE" },
"modules": [
{
"id": "1",
"name": "Set vars",
"type": "tools",
"func": "setVars",
"params": {
"vars": {
"dayOfYear": "{{ toNumber(formatDate(now; \"DDD\")) }}",
"todayKey": "{{ formatDate(now; \"YYYY-MM-DD\") }}",
"promptCount": 5
}
}
},
{
"id": "2",
"name": "Idempotency check",
"type": "datastore",
"func": "get",
"params": { "store": "JournalSends", "key": "{{1.todayKey}}" }
},
{
"id": "3",
"name": "Filter: not sent today",
"type": "flow",
"func": "filter",
"params": { "condition": "{{ empty(2.value) }}" }
},
{
"id": "4",
"name": "Select prompt",
"type": "tools",
"func": "setVars",
"params": {
"vars": {
"index": "{{ 1.dayOfYear % 1.promptCount }}",
"prompts": [
"What energized you in the last 24 hours?",
"Name one challenge today and one next step to address it.",
"What are you grateful for right now?",
"What did you learn today?",
"If tomorrow goes well, what will be different?"
],
"promptText": "{{ get(4.prompts; 4.index) }}"
}
}
},
{
"id": "5",
"name": "Send to Telegram",
"type": "http",
"func": "post",
"params": {
"url": "https://api.telegram.org/botYOUR_TELEGRAM_BOT_TOKEN/sendMessage",
"headers": { "Content-Type": "application/json" },
"body": "{\n \"chat_id\": \"YOUR_CHAT_ID\",\n \"text\": \"{{4.promptText}}\",\n \"disable_web_page_preview\": true,\n \"reply_markup\": { \"inline_keyboard\": [[ {\"text\": \"Snooze 15m\", \"callback_data\": \"SNOOZE_15\"}, {\"text\": \"Done\", \"callback_data\": \"DONE\"} ]] }\n}"
}
},
{
"id": "6",
"name": "Mark sent today",
"type": "datastore",
"func": "set",
"params": {
"store": "JournalSends",
"key": "{{1.todayKey}}",
"value": "{ \"message_id\": \"{{5.body.result.message_id}}\", \"prompt\": \"{{4.promptText}}\" }",
"ttl": 604800
}
},
{
"id": "7",
"name": "Log row",
"type": "google-sheets",
"func": "appendRow",
"params": {
"connectionId": "conn_sheets_1",
"spreadsheetId": "YOUR_SHEET_ID",
"sheetName": "Sends",
"values": ["{{1.todayKey}}", "YOUR_CHAT_ID", "{{5.body.result.message_id}}", "{{4.index}}", "{{4.promptText}}", "{{ formatDate(now; \"YYYY-MM-DD HH:mm:ss\"; \"UTC\") }}"]
}
}
],
"links": [
{ "from_module": "1", "to_module": "2" },
{ "from_module": "2", "to_module": "3" },
{ "from_module": "3", "to_module": "4" },
{ "from_module": "4", "to_module": "5" },
{ "from_module": "5", "to_module": "6" },
{ "from_module": "6", "to_module": "7" }
]
}E) Sample workflow JSON code — Listener for snooze and journal entries
{
"name": "Telegram Listener → Snooze + Log Entries",
"version": 3,
"schedule": { "type": "immediate" },
"modules": [
{
"id": "1",
"name": "Watch updates",
"type": "telegram",
"func": "watchUpdates",
"params": { "connectionId": "conn_telegram_1", "allowedUpdates": ["message","callback_query"] }
},
{
"id": "2",
"name": "Router",
"type": "router"
},
{
"id": "3",
"name": "Filter: Snooze",
"type": "flow",
"func": "filter",
"params": { "condition": "{{ not empty(callback_query) and callback_query.data = \"SNOOZE_15\" }}" }
},
{
"id": "4",
"name": "Sleep 15 minutes",
"type": "tools",
"func": "sleep",
"params": { "seconds": 900 }
},
{
"id": "5",
"name": "Re-send prompt",
"type": "http",
"func": "post",
"params": {
"url": "https://api.telegram.org/botYOUR_TELEGRAM_BOT_TOKEN/sendMessage",
"headers": { "Content-Type": "application/json" },
"body": "{ \"chat_id\": \"{{callback_query.message.chat.id}}\", \"text\": \"{{callback_query.message.text}}\" }"
}
},
{
"id": "6",
"name": "Filter: Done",
"type": "flow",
"func": "filter",
"params": { "condition": "{{ not empty(callback_query) and callback_query.data = \"DONE\" }}" }
},
{
"id": "7",
"name": "Ack done",
"type": "http",
"func": "post",
"params": {
"url": "https://api.telegram.org/botYOUR_TELEGRAM_BOT_TOKEN/sendMessage",
"headers": { "Content-Type": "application/json" },
"body": "{ \"chat_id\": \"{{callback_query.message.chat.id}}\", \"text\": \"Noted. Have a good day.\" }"
}
},
{
"id": "8",
"name": "Filter: Journal entry",
"type": "flow",
"func": "filter",
"params": { "condition": "{{ not empty(message) and not empty(message.text) }}" }
},
{
"id": "9",
"name": "Log entry to Sheets",
"type": "google-sheets",
"func": "appendRow",
"params": {
"connectionId": "conn_sheets_1",
"spreadsheetId": "YOUR_SHEET_ID",
"sheetName": "Entries",
"values": [
"{{ message.from.id }}",
"{{ message.chat.id }}",
"{{ message.message_id }}",
"{{ if(not empty(message.reply_to_message); message.reply_to_message.message_id; \"\") }}",
"{{ replaceAll(message.text; \"\\n\"; \" \") }}",
"{{ formatDate(now; \"YYYY-MM-DD HH:mm:ss\"; \"UTC\") }}"
]
}
}
],
"links": [
{ "from_module": "1", "to_module": "2" },
{ "from_module": "2", "to_module": "3" },
{ "from_module": "3", "to_module": "4" },
{ "from_module": "4", "to_module": "5" },
{ "from_module": "2", "to_module": "6" },
{ "from_module": "6", "to_module": "7" },
{ "from_module": "2", "to_module": "8" },
{ "from_module": "8", "to_module": "9" }
]
}F) Sheets structure for logs (CSV)
# Sheet "Sends"
date,chat_id,message_id,prompt_index,prompt_text,utc_sent_at
2025-08-27,123456789,42,1,"Name one challenge today and one next step to address it.",2025-08-27 02:00:00
# Sheet "Entries"
user_id,chat_id,message_id,reply_to,payload,utc_logged_at
987654321,123456789,88,42,"Reflected on feedback and planned next step.",2025-08-27 02:17:31Use Cases / Scenarios
Solo journaling with daily prompts in a DM.
Group wellness challenges where the bot posts to a private team channel.
Counseling cohorts using structured prompts with optional reply logging.
Habit formation with streaks tracked in Sheets.
Limitations / Considerations
Bots cannot DM a user until the user sends a message first. Share a
/startlink in onboarding.Telegram rate limits apply. Use retries and small sleeps on bursts.
MarkdownV2 requires strict escaping. Use plain text to avoid 400 errors.
Scheduler precision depends on Make. Expect minute-level variance.
Data retention is your responsibility. Journal content may be sensitive. Restrict sheet access and avoid public links.
Fixes (common pitfalls with solutions and troubleshooting tips, text-based only)
No messages arrive. Verify
chat_id, bot has been added to the chat, and the token is correct. Confirm with a manualsendMessagecall.400 Bad Request. Remove
parse_modeor escape MarkdownV2 metacharacters:_ * [ ] ( ) ~> # + - = | { } . !`.Duplicates. Enable idempotency with a
todayKeyData Store or check the “Sends” sheet for an existing row on the same date.Wrong time. Set the scenario time zone. If your prompts arrive late or early, move the schedule or set a fixed IANA zone.
Group noise. Restrict who can invoke commands. Avoid
@allmentions.Snooze is not firing. Confirm the listener scenario runs “immediately” and that callback queries are enabled in the trigger.
Diagram

Budget calculation
Let:
F= sends per day per chat. UsuallyF = 1.C= number of chats the bot serves.R= average journal replies per day across all chats.Daily sender ops ≈
C * (1 scheduler + 1 vars + 1 send + 1 log + 1 datastore set)≈C * 5.Listener ops per reply ≈
1 trigger + 1 log + optional 1 ack≈2–3.Monthly ops ≈
30 * 5C + 2.5R.
Example: one chat,C=1, repliesR=60→ monthly ≈150 + 150 = 300. Well within typical free tiers.
Future enhancements
Streak tracking with a badge message on day milestones.
Categories and weekday themes using a prompt catalog in Sheets.
Weekly digest that summarizes entries per user.
Quiet hours and time-window delivery per user locale.
Multi-language prompts with a language field in Sheets.
No-Code Alternative (Free)
Scheduled Telegram messages can be configured in Make using time-based triggers and reusable message templates. It offers a free tier and allows you to design automation with simple drag-and-drop modules—useful if you want to add filters, branching, or additional app integrations later.
You can explore it here (free account): https://www.make.com/en/register?pc=rohit9910
Conclusion
A Make.com scheduler, a simple prompt list, and Telegram’s Bot API create a reliable journaling bot. The system selects a prompt, posts on time, handles snooze, and captures responses with clear logs. It is simple to maintain, low-cost, and extensible for groups or personal wellness.

Join the conversation! Your thoughts help the community grow.