Skip to main content

Overview

Gogram provides a powerful event-driven architecture to handle updates from Telegram. You can listen to various event types and respond to them using handler functions. The recommended way to add handlers is using the client.On() method.

Basic Usage

Handling Messages

Handle NewMessage updates:
client.On("message", func(m *telegram.NewMessage) error {
    m.Reply("Hello from Gogram!")
    return nil
})

Handling Commands

client.On("cmd:start", func(m *telegram.NewMessage) error {
    m.Reply("Welcome! Use /help to see available commands.")
    return nil
})

// With filters
client.On("cmd:admin", func(m *telegram.NewMessage) error {
    m.Reply("Admin command executed")
    return nil
}, telegram.FilterPrivate)

Handling Callbacks

Handle CallbackQuery updates from inline button clicks:
client.On("callback", func(c *telegram.CallbackQuery) error {
    c.Answer("Button clicked!", &telegram.CallbackOptions{
        Alert: true,
    })
    return nil
})

Handling Inline Queries

Handle InlineQuery updates when users type @yourbot query:
client.On("inline", func(q *telegram.InlineQuery) error {
    builder := q.Builder()
    builder.Article("Result", "Description", "Text")
    q.Answer(builder.Results())
    return nil
})

Event Types

Message Updates

NewMessage

New incoming messages

EditMessage

Edited messages

DeleteMessage

Deleted messages

Album

Media groups/albums

Callback & Inline Updates

Other Updates

ParticipantUpdate

Chat participant changes

ActionMessage

Service messages

Raw Updates

Raw Telegram updates

Handling Different Update Types

New Messages

Handle NewMessage updates with full access to message data:
client.On("message", func(m *telegram.NewMessage) error {
    fmt.Printf("Received: %s\n", m.Text())
    
    // Reply to message
    m.Reply("Got your message!")
    
    // Access media
    if photo := m.Photo(); photo != nil {
        m.Reply("Nice photo!")
    }
    
    return nil
})

Edited Messages

client.On("edit", func(m *telegram.NewMessage) error {
    fmt.Printf("Message edited: %s\n", m.Text())
    return nil
})

Deleted Messages

client.On("delete", func(d *telegram.DeleteMessage) error {
    fmt.Printf("Message %d deleted\n", d.ID)
    return nil
})

Albums (Media Groups)

Handle Album updates for grouped media:
client.On("album", func(a *telegram.Album) error {
    fmt.Printf("Received album with %d items\n", len(a.Messages))
    
    // Process each item
    for i, msg := range a.Messages {
        fmt.Printf("Item %d: %s\n", i+1, msg.MediaType())
    }
    
    // Reply to first message
    a.Messages[0].Reply("Got your album!")
    
    return nil
})

Callback Queries

Handle CallbackQuery updates from inline button clicks:
client.On("callback", func(c *telegram.CallbackQuery) error {
    data := c.DataString()
    
    // Answer the callback (required)
    c.Answer("Button clicked!", &telegram.CallbackOptions{
		Alert: true,
	})
    
    // Edit the message
    c.Edit("You clicked: " + data)
    
    return nil
})

Inline Queries

Handle InlineQuery updates:
client.On("inline", func(q *telegram.InlineQuery) error {
    builder := q.Builder()
    
    // Add results
    builder.Article(
        "Result Title",
        "Description",
        "Message text when selected",
    )
    
    builder.Photo("https://example.com/photo.jpg")
    
    // Send results
    q.Answer(builder.Results())
    return nil
})

Chosen Inline Results

client.On("choseninline", func(s *telegram.InlineSend) error {
    fmt.Printf("User chose result: %s\n", s.ID)
    
    // Edit the sent message
    s.Edit("Thanks for choosing!")
    
    return nil
})

Participant Updates

client.On("participant", func(p *telegram.ParticipantUpdate) error {
    if p.IsJoined() {
        fmt.Printf("User %d joined chat %d\n", p.UserID, p.ChatID)
    } else if p.IsLeft() {
        fmt.Printf("User %d left chat %d\n", p.UserID, p.ChatID)
    }
    return nil
})

Action Messages

Handle service messages (user joined, pinned message, etc.):
client.On("action", func(m *telegram.NewMessage) error {
    // Handle service messages
    return nil
})

Raw Updates

Handle raw Telegram updates for advanced use cases:
client.On("raw", func(update telegram.Update, client *telegram.Client) error {
    switch u := update.(type) {
    case *telegram.UpdateNewMessage:
        // Handle raw message update
    case *telegram.UpdateEditMessage:
        // Handle raw edit update
    default:
        fmt.Printf("Unhandled update type: %T\n", u)
    }
    return nil
})

Available Events

client.On("message", func(m *telegram.NewMessage) error {
    // Handle any message
    return nil
})

Filtering Updates

Apply filters to handle specific updates:
import "github.com/amarnathcjd/gogram/telegram"

client.On("message", handler, telegram.FilterPrivate)
client.On("message", handler, telegram.FilterGroup)
client.On("message", handler, telegram.FilterPhoto)
client.On("message", handler, 
    telegram.FilterAnd(telegram.FilterPrivate, telegram.FilterPhoto))
// or 
client.On("message", handler, telegram.FilterPrivate, telegram.FilterPhoto)

Custom Filters

Create custom filter functions:
adminOnly := filters.FilterFunc(func(m *telegram.NewMessage) bool {
    return m.SenderID == 123456789
})

client.On("message", handler, adminOnly)

Pattern Matching

Command Patterns

// Basic command
client.On("cmd:start", handler)

// Multiple commands with same handler
client.On("cmd:help", handler)
client.On("cmd:about", handler)

// Command with regex
client.On("cmd:set.*", handler)

String Patterns

// Exact match
client.On("message:hello", func(m *telegram.NewMessage) error {
    m.Reply("Hi there!")
    return nil
})

// Regex pattern
client.On("message:^(hi|hello|hey)", func(m *telegram.NewMessage) error {
    m.Reply("Hey!")
    return nil
})

Callback Patterns

// Match callback data
client.On("callback:button_1", func(c *telegram.CallbackQuery) error {
    dt := c.DataString()
    // Handle button_1 callback
    return nil
})

// Regex pattern for button groups
client.On("callback:^btn_.*", handler)

Handler Groups

Handler groups control the order and flow of handler execution. By default, handlers run in Group 0 concurrently.

How Groups Work

  • Conversation Group (-1): Runs first, sequentially, used internally for conversations
  • Group 0 (default): Execute concurrently (parallel)
  • Positive Groups (1, 2, 3…): Execute in order, sequentially

Setting Groups

// Default group (0) - runs concurrently
client.On("message", func(m *telegram.NewMessage) error {
    fmt.Println("This runs in parallel")
    return nil
})

// Conversation group (-1) - runs first
client.On("message", func(m *telegram.NewMessage) error {
    fmt.Println("This runs first")
    return nil
}).SetGroup(telegram.ConversationGroup)

// Custom group (1) - runs sequentially after group -1
handle.SetGroup(1)

// Another custom group (2) - runs after group 1
anotherHandle := client.On("message", func(m *telegram.NewMessage) error {
    fmt.Println("This runs after group 1")
    return nil
})
anotherHandle.SetGroup(2)

Handler Priority

Within the same group, handlers execute based on priority (higher = first):
handle1 := client.On("message", handler1)
handle1.SetPriority(10) // Runs first

handle2 := client.On("message", handler2)
handle2.SetPriority(5) // Runs second

handle3 := client.On("message", handler3)
// Priority 0 (default) - runs last

Stopping Propagation

Return telegram.EndGroup to stop handler execution in the current group:
client.On("cmd:admin", func(m *telegram.NewMessage) error {
    if m.SenderID() != adminID {
        m.Reply("Access denied")
        return telegram.EndGroup // Stop other handlers
    }
    return nil
})

Pattern Matching

String Patterns

client.On("message:hello", func(m *telegram.NewMessage) error {
    m.Reply("Hi there!")
    return nil
})
client.On("message:^(hi|hello|hey)", func(m *telegram.NewMessage) error {
    m.Reply("Hey!") // works for hi, hello, hey
    return nil
})

Command Patterns

client.On("cmd:start", handler)
client.On("cmd:set.*", handler)

Callback Patterns

// Match callback data
client.On("callback:button_1", func(c *telegram.CallbackQuery) error {
    dt := c.DataString()
    // Handle button_1 callback
    return nil
})

client.On("callback:^btn_.*", handler)

Removing Handlers

handle := client.On("message", handler)

// Later, remove the handler
client.RemoveHandle(handle)

Advanced Patterns

Using Conversations

Use the built-in conversation feature from NewMessage: More details here.
client.On("cmd:register", func(m *telegram.NewMessage) error {
    resp, err := m.Ask("What's your email?")
    if err != nil {
        return err
    }

    fmt.Printf("User email: %s\n", resp.Text())
    return nil
})

Alternative Handler Methods

While client.On() is recommended, you can also use specific methods:
client.AddMessageHandler(pattern, handler, filters...)
client.AddCommandHandler("start", handler, filters...)
client.AddCallbackHandler(pattern, handler, filters...)
client.AddInlineCallbackHandler(pattern, handler)
client.AddInlineHandler(pattern, handler)
client.AddInlineSendHandler(handler)
client.AddEditHandler(pattern, handler, filters...)
client.AddActionHandler(handler)
client.AddParticipantHandler(handler)
client.AddJoinRequestHandler(handler)
client.AddDeleteHandler(pattern, handler)
client.AddAlbumHandler(handler)
client.AddRawHandler(updateType, handler)

Complete Example

package main

import (
    "github.com/amarnathcjd/gogram/telegram"
)

func main() {
    client, _ := telegram.NewClient(telegram.ClientConfig{
        AppID: 6, AppHash: "app_hash",
    })
    
    client.LoginBot("bot_token")
    
    // Message handler with group and priority
    client.On("message", func(m *telegram.NewMessage) error {
        m.Reply("Processing message...")
        return nil
    }, telegram.FilterPrivate).SetGroup(1).SetPriority(5)
    
    // Command handler
    client.On("cmd:start", func(m *telegram.NewMessage) error {
        m.Reply("Welcome! 👋")
        return nil
    })
    
    // Callback handler with pattern
    client.On("callback:btn_.*", func(c *telegram.CallbackQuery) error {
        c.Answer("Button clicked!")
        return nil
    })
    
    // Inline query handler
    client.On("inline", func(q *telegram.InlineQuery) error {
        results := []telegram.InputBotInlineResult{
            // ... inline results
        }
        q.Answer(results)
        return nil
    })
    
    client.On("album", func(a *telegram.Album) error {
        a.Messages[0].Reply("Received album with %d items", len(a.Messages))
        return nil
    })
    
    client.Idle()
}

Best Practices

Use client.On()

Recommended method for adding handlers - clean and simple

Return Errors

Always return errors from handlers for proper error handling

Use Filters

Filter updates early to avoid unnecessary processing with filters

Handle Errors

Check errors and handle them gracefully - see Error Handling

Use Groups Wisely

Use groups for sequential processing, default group for parallel

Stop Propagation

Return EndGroup when you want to stop further handlers

Set Priorities

Use priorities within groups to control execution order

Close Conversations

Always defer conv.Close() when using manual conversations

Check Context

Verify message context (chat type, sender, etc.) before processing

Avoid Blocking

Don’t block handlers with long operations - use goroutines

Next Steps