A powerful TypeScript/Node.js application that extracts messages from Telegram and pushes them to Notion pages. This project combines the GramJS library for Telegram integration with the official Notion API to create a seamless message archiving solution.
- π Secure Authentication - Uses official Telegram API with session management
- π Message Extraction - Retrieve message history from any chat, group, or channel
- π₯ Chat Management - List dialogs, search chats, and manage conversations
- π Advanced Filtering - Filter by date, message type, chat type, and more
- π¨ Send Messages - Send text messages to users, groups, and channels (bonus feature)
- ποΈ Database Pages - Each message becomes a structured database page with rich properties
- π Advanced Querying - Filter, sort, and search messages using Notion's powerful database features
- π Batch Processing - Efficiently handle large message volumes with automatic batching
- π Analytics & Stats - Built-in statistics and insights about your message data
- π― Flexible Targeting - Extract from specific chats or all chats at once
- π TypeScript Support - Full TypeScript support with comprehensive type definitions
- βοΈ Configurable Options - Customize extraction behavior with detailed options
- π‘οΈ Error Handling - Robust error handling and retry mechanisms
- π Interactive CLI - User-friendly command-line interface for easy operation
- Node.js (version 16 or higher)
- A Telegram account with API credentials (API ID and API Hash)
- A Notion account with workspace access
- Set up your credentials (see Installation below)
- Run the interactive extractor:
npm run telegram-to-notion:dev
- Follow the prompts to extract messages from your chats to Notion!
For detailed setup instructions, see DATABASE_SETUP.md.
-
Clone or download this project
cd jimmyHungCcTracker -
Install dependencies
npm install
-
Build the TypeScript project
npm run build
-
Get Telegram API credentials
- Go to https://my.telegram.org/apps
- Log in with your Telegram account
- Create a new application
- Note down your
api_idandapi_hash
-
Set up environment variables
cp env.example .env
Edit the
.envfile with your credentials:# Telegram API credentials TELEGRAM_API_ID=your_api_id_here TELEGRAM_API_HASH=your_api_hash_here PHONE_NUMBER=+1234567890 SESSION_NAME=my_telegram_session # Notion API credentials (required for message extraction) NOTION_TOKEN=secret_your_integration_token_here NOTION_DATABASE_ID=your_notion_database_id_here
Important: For Notion setup, see the detailed guide: DATABASE_SETUP.md
The easiest way to get started is with the interactive CLI:
# Run the interactive message extractor
npm run telegram-to-notion:dev
# Or run different example modes
npm run telegram-to-notion:dev simple # Simple programmatic example
npm run telegram-to-notion:dev batch # Batch extraction exampleimport { TelegramToNotionService } from "./src/TelegramToNotionService.js";
const service = new TelegramToNotionService();
// Extract 50 messages from a specific chat
const result = await service.extractChatToNotion("username_or_chat_id", {
messageLimit: 50,
includeOutgoing: true,
includeMedia: false,
});
console.log(
`Extracted ${result.messageCount} messages from "${result.chatName}"`
);
await service.disconnect();import { TelegramToNotionService } from "./src/TelegramToNotionService.js";
const service = new TelegramToNotionService();
// Extract messages from multiple chats
const chatIds = ["chat1_username", "chat2_username", "group_name"];
const results = await service.extractMultipleChatsToNotion(chatIds, {
messageLimit: 30,
includeOutgoing: true,
dateFilter: {
from: new Date("2024-01-01"),
to: new Date(),
},
});
console.log(`Extracted ${results.length} chats`);
await service.disconnect();import { TelegramToNotionService } from "./src/TelegramToNotionService.js";
const service = new TelegramToNotionService();
// Extract messages from all user chats (not groups/channels)
const results = await service.extractAllChatsToNotion({
messageLimit: 20,
chatFilter: {
includeUsers: true,
includeGroups: false,
includeChannels: false,
},
});
console.log(`Extracted from ${results.length} user chats`);
await service.disconnect();If you prefer to use the Telegram and Notion clients separately:
import { TelegramClient, NotionClient } from "./src/index.js";
// Telegram client (existing functionality)
const telegramClient = new TelegramClient();
await telegramClient.connect();
const messages = await telegramClient.getMessages("username", 10);
console.log("Retrieved messages:", messages.length);
// Notion client (new functionality)
const notionClient = new NotionClient();
// Convert and push messages to Notion
const notionMessages = messages.map((msg) => ({
id: msg.id,
content: msg.message || "[No content]",
sender: msg.isOutgoing ? "You" : "Other User",
date: new Date(msg.date * 1000),
chatName: "Chat Name",
isOutgoing: msg.isOutgoing,
}));
await notionClient.addMessages(notionMessages);# Message extraction scripts
npm run telegram-to-notion # Compiled interactive extractor
npm run telegram-to-notion:dev # Development interactive extractor
# Basic Telegram examples (legacy)
npm run example # Basic Telegram client example
npm run example:dev # Development Telegram example
# Development scripts
npm run build # Build TypeScript to JavaScript
npm run dev # Run main index.ts in development
npm run clear-session # Clear saved Telegram sessionconst client = new TelegramClient();Connects to Telegram and authenticates the user.
const success = await client.connect();Disconnects from Telegram.
await client.disconnect();Gets information about the current user.
const userInfo = await client.getMe();
// Returns: { id, firstName, lastName, username, phone, isBot }Gets list of all chats (dialogs).
const dialogs = await client.getDialogs();
// Returns array of: { id, title, isUser, isGroup, isChannel, unreadCount }Gets messages from a specific chat.
const messages = await client.getMessages("username", 20);
// Returns array of: { id, message, date, fromId, sender, isOutgoing, media }Sends a message to a specific chat.
const result = await client.sendMessage("username", "Hello!");
// Returns: { id, message, date, chatId, success }Searches for chats and users by name.
const results = await client.searchChats("john");
// Returns: { chats: [...], users: [...] }Marks all messages in a chat as read.
await client.markAsRead("username");const service = new TelegramToNotionService();Extracts messages from a specific chat and pushes them to Notion.
const result = await service.extractChatToNotion("username", {
messageLimit: 50,
includeOutgoing: true,
includeMedia: false,
dateFilter: {
from: new Date("2024-01-01"),
to: new Date(),
},
});
// Returns: { chatName, chatId, messageCount, messages }Extracts messages from multiple chats.
const results = await service.extractMultipleChatsToNotion(
["chat1", "chat2"],
options
);
// Returns: Array of { chatName, chatId, messageCount, messages }Extracts messages from all available chats with filtering.
const results = await service.extractAllChatsToNotion({
messageLimit: 20,
chatFilter: {
includeUsers: true,
includeGroups: false,
includeChannels: false,
},
});Gets list of all available chats for extraction.
const chats = await service.getAvailableChats();
// Returns: Array of DialogInfo objectsconst notionClient = new NotionClient({
token: "your_token", // Optional if in env
pageId: "your_page_id", // Optional if in env
});Adds a single message to the Notion page.
await notionClient.addMessage({
id: 123,
content: "Hello world",
sender: "John Doe",
date: new Date(),
chatName: "My Chat",
isOutgoing: false,
});Adds multiple messages in batch.
await notionClient.addMessages(messagesArray);Tests the connection to Notion API.
const isConnected = await notionClient.testConnection();import { TelegramClient } from "./src/TelegramClient.js";
const client = new TelegramClient();
await client.connect();
const dialogs = await client.getDialogs();
for (const dialog of dialogs.slice(0, 5)) {
console.log(`\n=== ${dialog.title} ===`);
const messages = await client.getMessages(dialog.id, 3);
messages.forEach((msg) => {
const date = new Date(msg.date * 1000).toLocaleString();
console.log(`[${date}] ${msg.message || "[Media]"}`);
});
}
await client.disconnect();import { TelegramClient } from "./src/TelegramClient.js";
const client = new TelegramClient();
await client.connect();
const recipients = ["user1", "user2", "group_name"];
const message = "Hello everyone!";
for (const recipient of recipients) {
try {
await client.sendMessage(recipient, message);
console.log(`β
Message sent to ${recipient}`);
} catch (error) {
console.log(`β Failed to send to ${recipient}: ${error.message}`);
}
}
await client.disconnect();import { TelegramClient } from "./src/TelegramClient.js";
const client = new TelegramClient();
await client.connect();
// Simple polling approach (check every 30 seconds)
setInterval(async () => {
const dialogs = await client.getDialogs();
for (const dialog of dialogs) {
if (dialog.unreadCount > 0) {
console.log(`π¬ ${dialog.unreadCount} new messages in ${dialog.title}`);
const messages = await client.getMessages(dialog.id, dialog.unreadCount);
messages.forEach((msg) => {
if (!msg.isOutgoing) {
// Only show incoming messages
console.log(` π¨ ${msg.message || "[Media]"}`);
}
});
// Optionally mark as read
// await client.markAsRead(dialog.id);
}
}
}, 30000);The client includes comprehensive error handling. Here are common scenarios:
try {
await client.sendMessage("nonexistent_user", "Hello");
} catch (error) {
if (error.message.includes("USERNAME_NOT_OCCUPIED")) {
console.log("User not found");
} else if (error.message.includes("FLOOD_WAIT")) {
console.log("Rate limited, wait before sending more messages");
} else {
console.log("Other error:", error.message);
}
}The client automatically saves your session after the first login. The session string will be printed to the console. For production use, you can:
- Save the session string to a file
- Use it to initialize the client without re-authentication:
import { StringSession } from "gram-js/sessions/index.js";
const savedSession = "your_session_string_here";
const session = new StringSession(savedSession);
// Pass the session to TelegramClient constructor
// (Note: You'll need to modify the constructor to accept a session parameter)- π Never share your API credentials - Keep your
.envfile secure - π Protect your session string - It's equivalent to your login credentials
- π± Two-Factor Authentication - The client supports 2FA if enabled on your account
- π« Rate Limits - Respect Telegram's rate limits to avoid temporary bans
-
"Invalid phone number"
- Make sure to include the country code (e.g., +1234567890)
-
"API_ID_INVALID"
- Double-check your API ID and API Hash from my.telegram.org
-
"PHONE_CODE_INVALID"
- Enter the verification code exactly as received
-
Connection timeouts
- Check your internet connection
- Try using a VPN if Telegram is restricted in your region
-
"USER_DEACTIVATED"
- Your account may be limited or banned
To enable debug logging, set the environment variable:
DEBUG=gram* npm startThis client implements intelligent connection fallback to ensure reliable connections across different network environments.
- Protocol: Direct TCP connection to Telegram servers
- Port: 80 (HTTP port)
- Security: Encrypted via Telegram's MTProto protocol
- Best for: Corporate networks, restricted environments, hotel WiFi
- Protocol: WebSocket Secure over TLS
- Port: 443 (HTTPS port)
- Security: Double-encrypted (TLS + MTProto)
- Best for: Home networks, unrestricted environments
The client automatically tries connection methods in this order:
1. TCP without WSS (Port 80) β Most compatible
2. TCP with WSS (Port 443) β More secure but sometimes blocked
Example from logs:
Connecting to Telegram using TCP without WSS...
[INFO] - [Connecting to 149.154.167.91:80/TCPFull...]
β
Connection successful!
| Environment | Recommended | Reason |
|---|---|---|
| π’ Corporate Networks | TCP (no WSS) | WebSocket traffic often blocked by firewalls |
| π¨ Hotel/Airport WiFi | TCP (no WSS) | Captive portals may interfere with WSS |
| π Home WiFi | Either works | Usually no restrictions |
| π± Mobile Data | Either works | Carriers rarely block either method |
| π Restricted Countries | TCP (no WSS) | Less likely to be filtered or detected |
| π High-Security Networks | TCP (no WSS) | Simpler protocol, fewer inspection points |
Both connection methods provide the same level of security:
- Application-Level Encryption: Telegram's MTProto protocol encrypts all data end-to-end
- Server Authentication: Both methods verify server identity
- Perfect Forward Secrecy: Session keys are rotated regularly
The difference is only in the transport layer:
- TCP without WSS: MTProto encryption only
- TCP with WSS: TLS encryption + MTProto encryption (double-layered)
If you experience connection problems:
-
Clear your session and retry:
npm run clear-session npm run example
-
Check the connection logs for which method succeeded:
Connecting to Telegram using TCP without WSS... β This method [INFO] - [Connection to 149.154.167.91:80/TCPFull complete!] β Success! -
Network-specific issues:
- Corporate firewall: TCP without WSS usually works
- VPN interference: Try disconnecting VPN temporarily
- Proxy settings: Ensure proxy allows TCP connections on port 80
-
Manual connection method (if needed):
// Force specific connection type in your code const client = new TelegramClient({ // This will be implemented if needed connectionMethod: "tcp-no-wss", // or 'tcp-wss' });
Look for these log messages to confirm successful connection:
β
Success: "Connection to [IP]:80/TCPFull complete!"
β
Success: "Successfully connected to Telegram!"
β
Success: "Session saved to file"
β Failed: "WebSocket connection failed"
β Failed: "connection closed"
β Failed: "Not connected"Feel free to submit issues and pull requests to improve this project.
MIT License - see the LICENSE file for details.
This project is for educational purposes. Make sure to comply with Telegram's Terms of Service and respect user privacy when using this client.