How It Works
Understand how NxCreator runs your bot code, what tools are available, and how to set up automated tasks.
This page explains what happens behind the scenes when you write and save bot code on NxCreator — and how to use the built-in tools that come with every bot.
What is NxCreator doing?
When you create a bot on NxCreator, the platform takes care of everything you would normally have to set up yourself: renting a server, installing software, keeping the bot process running 24/7, and connecting to Telegram. You just write the logic — what should happen when a user sends a message — and NxCreator handles the rest.
Think of it like this: NxCreator is the kitchen, and your code is the recipe. You write the recipe, and the kitchen handles the oven, the electricity, and making sure everything stays hot.
How your code runs
Each bot runs in its own private environment, completely separate from other bots on the platform. Your code sections are combined into one unified bot program, and the platform connects that program to Telegram on your behalf.
NxCreator uses a popular bot library called Telegraf under the hood. You do not need to set it up or configure it — it is already running. Your job is simply to tell it what to do by registering handlers on the pre-existing bot object. Never create your own bot instance or import Telegraf yourself.
Saving and testing
When you hit save in the editor, NxCreator immediately applies your changes to the live running bot — no deployment steps, no waiting. Just save, switch to Telegram, and test your change. If something is wrong, fix it and save again.
Built-in tools
NxCreator provides a set of ready-to-use tools inside every bot. These are called globals — they are available automatically without needing to install or import anything. Just use them by name.
Do not use require(...) to load packages. If you need something, check the table below — it is almost certainly already available.
What is available
| What you want to do | Global to use | Notes |
|---|---|---|
| Respond to messages and commands | bot`, `Telegraf`, `Scenes`, `Markup | The main bot object is already set up. Register handlers directly on `bot`. |
| Use the Grammy bot framework instead | GrammyBot`, `Grammy`, `InlineKeyboard`, `Keyboard`, `grammySession | Only available if your bot is configured to use the Grammy framework. |
| Use node-telegram-bot-api instead | TelegramBot | Only available if your bot is configured to use node-telegram-bot-api. |
| Make HTTP requests to external APIs | axios | A standard HTTP client. Use this to fetch data from any web API. |
| Store and retrieve data | db | A built-in database helper. No configuration needed. |
| Run tasks on a schedule | cron | For repeating tasks. See the Scheduled Tasks section below for details. |
| Send emails | nodemailer | Available with some restrictions on file attachments. |
| Generate text-to-speech audio URLs | googleTTS | Useful for voice bots or audio responses. |
| Draw images or graphics | createCanvas`, `loadImage | Image creation with size limits. File and URL-based image loading is restricted. |
| Resize or process images | sharp | Image transformation with limits. Saving files directly is not allowed. |
| Generate unique IDs | uuid | Useful for creating unique keys or identifiers. |
| Hash data or generate tokens | crypto | Standard cryptographic utilities. |
| Send a message to all your bot users | broadcast(payload) | Queues a background broadcast job. Supports text, photo, video, audio, document, and more. |
| Broadcast from a different bot you own | broadcastAnotherBot(payload) | Same as broadcast() but targets a different bot using its botId and your account apiKey. |
| Copy this bot to another NxCreator account | botTransfer({ recipientEmail }) | Clones the bot logic and sections to a recipient. Optionally attaches a new token and auto-starts. |
Calling external APIs
Your bot can reach out to the internet and fetch data from any external service. Use the built-in axios global to make these requests. This is how you would connect your bot to a weather service, a payment API, a news feed, or anything else.
The try/catch block is important here — external APIs can fail or go down, and you want your bot to handle that gracefully instead of crashing.
Delays and repeating actions
Sometimes you want your bot to do something after a delay, or on a repeating schedule. JavaScript provides two built-in tools for this:
setTimeout(fn, ms)— runs something once after a delay. For example, send a follow-up message 5 seconds after a user signs up.setInterval(fn, ms)— runs something repeatedly on a fixed interval. For example, check a feed every 60 seconds.
Scheduled tasks that last
Imagine you want your bot to send a daily summary to a user every morning at 9am. A simple timer like setTimeout would not work for this — if the bot ever restarts, the timer is gone and the task never runs again.
NxCreator solves this with persistent scheduled tasks. These are jobs that get stored safely outside the bot process, so they survive restarts, re-saves, and updates. Even if your bot goes down and comes back up, the scheduled task will still run at the right time.
How to think about it
Setting up a persistent task is a two-step process:
- Step 1: Define what should happen. You write the function and give it a name — for example
daily-report. This is your task definition. - Step 2: Set when it should run. You use the scheduler to tell NxCreator when to trigger that task — once, or on a repeating schedule.
The key insight is that NxCreator stores the name of your task, not the code itself. When the time comes to run it, it looks up the registered task by name and executes it. This is why the name you use in Step 1 must exactly match the name you use in Step 2.
Choosing the right tool
| Tool | Best for | Survives bot restarts? |
|---|---|---|
setTimeout | A short one-time delay (e.g. wait 10 seconds) | No |
setInterval | A simple repeating action (e.g. ping every minute) | No |
cron | Time-based repeating actions while the bot is running | No |
persistentScheduler.setTimeout | A one-time future action that must not be lost | Yes |
persistentCron.schedule | A repeating time-based task that must keep running | Yes |
Example: send a daily report every morning
This example shows how to send a message every morning at 9:00 AM. Read it from top to bottom — first the task is defined, then a bot command schedules it.
Breaking down what each part does:
registerPersistentTask('daily-report', ...): registers the job logic under the namedaily-report. This is the work that will run on schedule.payload: a small piece of data that gets saved alongside the schedule and passed back to your task when it runs. Here it carries the chat ID so the bot knows who to message.persistentCron.validate(timePattern): checks that your time pattern is valid before saving it.persistentCron.schedule(...): saves the task into the persistent scheduler so it will keep running even after restarts.key: 'daily-report-main': a unique name for this particular scheduled job. If a user runs the command again, it updates the existing schedule instead of creating a duplicate.
Example: send a message after a delay
Sometimes you do not need a repeating schedule — you just need something to happen once, later. For example, sending a reminder one hour after a user signs up, even if the bot restarts in between.
This pattern works well for reminders, delayed follow-ups, expiring access codes, or anything else that should fire once at a specific time in the future.
Understanding the time pattern format
Persistent repeating schedules use a time pattern with five parts, separated by spaces. Each part controls one unit of time — minute, hour, day, month, and day of the week. A * means "every".
Some practical examples to get you started:
0 9 * * *— every day at 9:00 AM.*/15 * * * *— every 15 minutes, all day long.0 0 * * 1— every Monday at midnight.30 18 * * 5— every Friday at 6:30 PM.
Quick reference
registerPersistentTask(name, handler)— defines a named task that the scheduler can call later.persistentCron.validate(pattern)— returnstrueif the time pattern is valid,falseotherwise.persistentCron.schedule(name, pattern, payload, options)— saves a repeating scheduled task.persistentScheduler.setTimeout(name, ms, payload)— saves a one-time delayed task.persistentCron.cancel(jobId)orpersistentScheduler.cancel(jobId)— removes a saved task.
Common mistakes to avoid
- Scheduling before registering: Always call
registerPersistentTaskfirst, then schedule it. The scheduler needs the task to already exist. - Mismatched names: The name in
registerPersistentTaskand the name inpersistentCron.schedulemust be exactly the same. - No key set: If a user can trigger the scheduling command more than once, always pass a
keyin options. Without it, each run of the command creates a new copy of the job. - Too much data in payload: Only put small identifiers in the payload (like a user ID or chat ID). Store everything else in the database.
db, register a simple named task, and schedule it with a stable key. That covers most real use cases without overcomplicating things.Broadcasting messages
The broadcast function sends a message to every user who has ever interacted with your bot. It runs entirely in the background — your bot code does not wait for all messages to be sent. Instead, it queues the job and returns a jobId immediately.
Broadcasting respects Telegram's rate limits automatically (30–40 messages per second). If Telegram returns a rate-limit error (429), the broadcaster pauses and retries from the exact same user without losing progress.
Basic usage
Sending media
Pass a media field containing a Telegram file_id or a public URL. Use caption to add text beneath the media.
Supported types
| type | What it sends | Required fields |
|---|---|---|
text | Plain or formatted text message | text |
photo | Image | `media` (file_id or URL) |
video | Video file | media |
audio | Audio file | media |
document | Any file (PDF, ZIP, etc.) | media |
animation | GIF or silent MP4 | media |
voice | Voice message (OGG) | media |
video_note | Round video message | media |
sticker | Sticker | media |
location | Map pin | extra.latitude`, `extra.longitude |
contact | Phone contact card | extra.phone_number`, `extra.first_name |
poll | Poll with options | `extra.question`, `extra.options` (array, min 2) |
Targeting a language
Use the optional filter field to send only to users whose Telegram language matches a given code. This is useful for sending announcements in the right language.
Return value
Telegram send parameters
Every broadcast call accepts a top-level parseMode field and an extra object. Anything inside extra is forwarded directly to the Telegram Bot API, so you can use any parameter the API supports for that message type.
Parse mode
Control how Telegram renders the message text or caption. Pass parseMode at the top level — no need to nest it inside extra.
| Value | What it does |
|---|---|
'HTML' | Enables `<b>`, `<i>`, `<code>`, `<a href="...">`, `<pre>`, `<s>`, `<u>`, `<tg-spoiler>` tags. |
'MarkdownV2' | Enables **bold**, _italic_, `code`, [links](url), ||spoiler||. Special chars must be escaped with `\`. |
'Markdown' | Legacy Markdown — avoid for new code. Use MarkdownV2 instead. |
| `''` (empty) | Plain text, no formatting. Default. |
Extra Telegram parameters
Pass any additional Telegram Bot API field inside the extra object. Common ones:
| Parameter | Type | Applies to | Description |
|---|---|---|---|
disable_web_page_preview | boolean | text | Prevents Telegram from generating a link preview below the message. |
disable_notification | boolean | all types | Sends the message silently — users receive it with no notification sound. |
protect_content | boolean | all types | Prevents recipients from forwarding or saving the message. |
reply_markup | object | all types | Attach an inline keyboard or custom reply keyboard to the message. |
duration | number | audio, video, voice | Duration of the media in seconds. |
width` / `height | number | video, animation | Video or animation dimensions. |
supports_streaming | boolean | video | Pass `true` for videos suitable for streaming. |
thumbnail | string | video, audio, doc | `file_id` or URL of a custom thumbnail. |
Broadcast from another bot
broadcastAnotherBot works exactly like broadcast but targets a different bot that you own. Provide the target bot's botId and your NxCreate account apiKey.
This is useful when you run multiple bots and want one bot's logic to trigger a broadcast on behalf of another — for example, an admin bot kicking off an announcement through a channel-specific bot.
Basic usage
Sending media
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
botId | string | Yes | The NxCreate bot ID of the target bot (visible in the dashboard). |
apiKey | string | Yes | Your NxCreate account API key. Throws if omitted. |
type | string | No | Message type. Same values as `broadcast()`. Defaults to `'text'`. |
text | string | Cond | Required when `type` is `'text'`. |
media | string | Cond | Required for photo, video, audio, document, animation, voice, video_note, sticker. |
caption | string | No | Optional caption for media types. |
parseMode | string | No | `'HTML'` | `'MarkdownV2'` | `'Markdown'`. Applies to text and captions. |
filter | object | No | Scope the broadcast to users matching `{ lang: 'en' }`. Omit to target everyone. |
extra | object | No | Any additional Telegram Bot API params forwarded verbatim. |
botId must belong to your account. Always wrap calls in try/catch.Tracking a broadcast job
Because broadcast queues a background job, your bot code gets a jobId back immediately. Use broadcastStatus(jobId) and broadcastCancel(jobId) — both are injected globals available in every bot, just like broadcast itself.
Checking job status
Status fields
| Field | Type | Description |
|---|---|---|
jobId | string | Unique ID of this broadcast job. |
status | string | queued` → `running` → `done` / `failed` / `cancelled |
total | number | Total number of users targeted. |
sent | number | Messages successfully delivered so far. |
failed | number | Users skipped (blocked bot, deactivated account, etc.). |
createdAt | number | Unix timestamp (ms) when the job was queued. |
startedAt | number | Unix timestamp (ms) when sending began. 0 if still queued. |
finishedAt | number | Unix timestamp (ms) when the job completed. 0 if still running. |
Polling until done
For automated flows you can poll the status in a loop. Keep the interval at least 5 seconds to avoid hammering the service.
Cancelling a running broadcast
Transferring a bot
The botTransfer function copies this bot — its logic and all its sections — to another NxCreator account. The original bot is not affected. The recipient gets a new bot under their account that they can attach their own Telegram token to.
This is useful for building bot-as-a-product flows: a user pays or completes a step, and your bot automatically provisions a ready-to-use copy for them.
Basic usage
Transfer and auto-start
If you already have the recipient's Telegram bot token (for example, they submitted it via a form), you can attach it and start the bot immediately.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
recipientEmail | string | Yes | Email address of the NxCreator account to receive the bot. Throws an error if omitted. |
newBotToken | string | No | Telegram bot token to attach to the new bot on the recipient account. |
runNow | boolean | No | If true, starts the bot immediately after transfer. Requires `newBotToken`. |
Return value
recipientEmail is not provided, botTransfer throws an error with { ok: false, message: "recipientEmail is required" } on the error object. Always wrap calls in a try/catch.