DEV Community

Nikita Zavada
Nikita Zavada

Posted on

How to Collect Telegram Media Groups in Node.js

When working with the Telegram Bot API, it is easy to expect that an album with multiple photos will arrive as a single event.

But Telegram works differently.

If a user sends an album of 3 photos, your bot doesn't receive one "post" object. Instead, it receives 3 separate updates in rapid succession:

Update #1 -> photo_1
Update #2 -> photo_2
Update #3 -> photo_3

instead of:

single_post -> [photo_1, photo_2, photo_3]
Enter fullscreen mode Exit fullscreen mode

The Headache: Why this is hard
Handling these updates manually forces you to deal with a lot of "plumbing" code that has nothing to do with your actual bot logic:

Duplicate database records: Accidentally creating 3 posts instead of 1.
Race conditions: Multiple updates hitting your server at the exact same time.
Buffering & Timeouts: Deciding how long to wait for the "next" photo before assuming the group is complete.
Ordering: Ensuring the photos stay in the order the user intended.
Typical "infrastructure" code usually starts looking like this mess:

const mediaGroups = new Map();
// buffering logic...
// sorting logic...
// duplicate prevention...
// cleanup jobs...
// timeout handling...
Enter fullscreen mode Exit fullscreen mode

At some point, you realize you are rewriting low-level infrastructure instead of building your actual features.

The Solution: telegram-media
I built telegram-media—a lightweight TypeScript library for Node.js that collects these scattered Telegram updates into a single, normalized object.

Installation

npm install telegram-media
Enter fullscreen mode Exit fullscreen mode

Usage Example
Here is how you can use it to collect media and save it to a database (like Prisma) using a Redis storage backend:

const collector = createTelegramMediaGroup({
  async onCollected(post) {
    // This only fires ONCE per media group
    await prisma.telegramPost.create({
      data: mapCollectedPostToPrismaInput(post),
    });
  },

  // Use Redis for distributed environments
  storage: createRedisMediaGroupStorage(redisClient),

  timeoutMs: 3000,

  supportedMediaTypes: ["photo", "video", "audio"],
});
Enter fullscreen mode Exit fullscreen mode

Why I Built This?
I ran into this problem while building a Telegram ingestion system for a personal project. At first, the logic seemed simple—just a small Set and a setTimeout.

Then the edge cases hit: distributed workers fighting over the same group, incomplete groups caused by network lag, and Redis synchronization issues. I extracted the logic into a standalone package so no one else has to solve this from scratch.

Key Features

  • Media Group Aggregation — Automatically groups related Telegram updates into a single normalized post.
  • Redis Support — Ready for production and distributed environments.
  • Duplicate Prevention — Handles Telegram retry updates safely.
  • Ordering — Preserves the original media sequence.
  • TypeScript — Fully typed for a better developer experience.

Explore

What do you think?
I'd love to hear how others are handling media groups. Do you use a custom buffer, or do you just process each image individually and update the record as you go?

Let me know in the comments!

Top comments (0)