Skip to main content
Many methods in Gogram return interface types that can have multiple implementations. You need to use type assertions or type switches to access the concrete type.

Example 1: AttachMenuBots

The AttachMenuBots interface has two possible implementations:
result, err := client.MessagesGetAttachMenuBots(ctx, &telegram.MessagesGetAttachMenuBotsParams{
    Hash: 0,
})
if err != nil {
    log.Fatal(err)
}

// Type switch to handle different implementations
switch bots := result.(type) {
case *telegram.AttachMenuBotsObj:
    fmt.Printf("Hash: %d\n", bots.Hash)
    fmt.Printf("Found %d bots\n", len(bots.Bots))
    for _, bot := range bots.Bots {
        fmt.Printf("Bot: %v\n", bot)
    }
    
case *telegram.AttachMenuBotsNotModified:
    fmt.Println("Bot list hasn't changed")
    
default:
    fmt.Printf("Unexpected type: %T\n", result)
}

Example 2: MessagesMessages

The MessagesMessages interface has four possible implementations:
messages, err := client.MessagesGetHistory(ctx, &telegram.MessagesGetHistoryParams{
    Peer:  peer,
    Limit: 100,
})
if err != nil {
    log.Fatal(err)
}

// Type switch to handle different implementations
switch m := messages.(type) {
case *telegram.MessagesMessagesObj:
    fmt.Printf("Total messages: %d\n", len(m.Messages))
    for _, msg := range m.Messages {
        fmt.Printf("Message: %v\n", msg)
    }
    
case *telegram.MessagesMessagesSlice:
    fmt.Printf("Total count: %d\n", m.Count)
    fmt.Printf("Loaded %d messages\n", len(m.Messages))
    if m.Inexact {
        fmt.Println("Results may be inexact")
    }
    
case *telegram.MessagesChannelMessages:
    fmt.Printf("Channel messages - Total: %d\n", m.Count)
    fmt.Printf("PTS: %d\n", m.Pts)
    fmt.Printf("Offset: %d\n", m.OffsetIDOffset)
    
case *telegram.MessagesMessagesNotModified:
    fmt.Printf("No new messages (count: %d)\n", m.Count)
    
default:
    fmt.Printf("Unexpected type: %T\n", messages)
}
Use type switches (switch v := result.(type)) when you need to handle multiple possible implementations. Use type assertions (result.(*ConcreteType)) only when you’re certain of the type.
This happens when Telegram assumes you already have the access hash for a peer and sends incomplete data. Enable caching to prevent this:
client, err := telegram.NewClient(telegram.ClientConfig{
    AppID:   6,
    AppHash: "your_app_hash",
    // Cache is enabled by default
})
See the Cache documentation for more details.
Go 1.18 or higher is required for generics support.
YES - Gogram is stable and being used in production by many projects.
  • Goroutines: ~10 - 12 goroutines
  • Memory: 10-20 MB RAM usage
Join the Telegram Support Group for help, questions, and discussions.
Gogram supports the following proxy types:
  • SOCKS5
  • SOCKS4
  • HTTP/HTTPS
  • MTProto (FakeTLS, Obfuscated, Classic)
For more details, see the Proxy documentation.
Gogram is tested and works on:
  • Linux
  • Windows
  • macOS
  • ARM (Raspberry Pi, etc.)
  • WebAssembly (WASM) - Use WebSocket connections
To run multiple clients simultaneously, you must provide a unique SessionName for each client configuration. This ensures they don’t overwrite each other’s session files.
// Client 1
client1, _ := telegram.NewClient(telegram.ClientConfig{
    SessionName: "bot_1",
    AppID:       12345,
    AppHash:     "abc",
})

// Client 2
client2, _ := telegram.NewClient(telegram.ClientConfig{
    SessionName: "bot_2",
    AppID:       12345,
    AppHash:     "abc",
})
This will create bot_1.session and bot_2.session respectively.
If you are coming from other MTProto libraries (like Telethon, Pyrogram, or GramJS), here are some key differences:
  1. Native Go Concurrency: Gogram uses Goroutines heavily. Handlers run concurrently by default (Group 0).
  2. Builder Pattern: We use builders for almost everything (Handlers, Keyboards, Inline Results) to provide type safety and discoverability.
  3. Strict Typing: Unlike dynamic languages (Python/JS), you must handle type assertions for interfaces (switch v := media.(type)).
  4. No await: All API calls are synchronous-blocking (but efficient). Wrap them in goroutines if you need non-blocking behavior.