Build a Telegram Bot to Automatically Extract Passport Data in Minutes
Telegram bots are incredibly powerful tools for internal operations. If you have field agents selling SIM cards, tour guides registering guests onto buses, or event staff securely checking IDs at the door, building them a dedicated iOS app is usually overkill.
Why not just tell them: "Take a photo of the passport and send it to our Telegram Bot."
In this tutorial, we'll build a simple Node.js Telegram bot that accepts a photo, passes it to the Passport OCR API, and instantly replies with the parsed Machine Readable Zone (MRZ) details.
Step 1: Get a Telegram Bot Token
First, we need to register the bot with Telegram.
- Open Telegram and search for
@BotFather. - Send the command
/newbot. - Choose a name for your bot (e.g., "Field Agent Scanner") and a username (e.g.,
FieldScannerOCRBot). - BotFather will give you a HTTP API Token. Save this string; we'll need it shortly.
Step 2: Set up the Node.js Project
Create a new directory and initialize a Node project:
mkdir passport-telegram-bot
cd passport-telegram-bot
npm init -yWe'll install the official node-telegram-bot-api library to handle the long-polling, and axios to make the HTTP request to the Passport OCR API. We'll also need form-data to submit the image binary.
npm install node-telegram-bot-api axios form-data dotenvCreate a .env file in the root directory:
TELEGRAM_BOT_TOKEN="your_token_from_botfather_here"Step 3: Write the Bot Logic
Create an index.js file with the following code.
The logic here is straightforward:
- Listen for images sent to the bot.
- If an image is received, download the highest resolution version from Telegram's servers.
- Stream that downloaded file directly to the Passport OCR API.
- Format the resulting JSON response into a readable message and send it back to the user.
require('dotenv').config();
const TelegramBot = require('node-telegram-bot-api');
const axios = require('axios');
const FormData = require('form-data');
// Replace the value below with the Telegram token you receive from @BotFather
const token = process.env.TELEGRAM_BOT_TOKEN;
// Create a bot that uses 'polling' to fetch new updates
const bot = new TelegramBot(token, { polling: true });
console.log("Bot is running. Send it a photo!");
bot.on('message', async (msg) => {
const chatId = msg.chat.id;
// We only care about messages containing photos
if (!msg.photo) {
if (msg.text === '/start') {
bot.sendMessage(chatId, "Welcome! Just send me a clear photo of a passport data page, and I'll extract the MRZ data.");
} else {
bot.sendMessage(chatId, "Please send a photo of a passport.");
}
return;
}
bot.sendMessage(chatId, "⏳ Processing image... Please wait.");
try {
// 1. Telegram sends an array of photos representing different resolutions.
// The last element is always the highest resolution.
const fileId = msg.photo[msg.photo.length - 1].file_id;
// 2. We use the bot API to get the download URL for the file
const fileUrl = await bot.getFileLink(fileId);
// 3. Download the file stream from Telegram
const imageResponse = await axios({
url: fileUrl,
method: 'GET',
responseType: 'stream'
});
// 4. Create a multi-part form and append the image stream
const form = new FormData();
form.append('image', imageResponse.data, 'passport.jpg');
// 5. Send it to the Passport OCR API
const ocrResponse = await axios.post('https://passport-ocr.com/v1/ocr', form, {
headers: {
...form.getHeaders()
// If you upgrade from the free tier, add your API key here:
// 'Authorization': 'Bearer YOUR_PASSPORT_OCR_KEY'
}
});
const body = ocrResponse.data;
if (!body.success) {
throw new Error(body.error || "Could not parse MRZ");
}
const { firstName, lastName, documentNumber, nationality, dateOfBirth, expirationDate } = body.data;
// 6. Format the reply
const reply = `
✅ *Extraction Successful!*
👤 *Name:* ${firstName} ${lastName}
📄 *Document No:* \`${documentNumber}\`
🌍 *Nationality:* ${nationality}
🎂 *DOB:* ${dateOfBirth}
⏳ *Expires:* ${expirationDate}
`;
// 7. Send the reply back to the user with Markdown formatting
bot.sendMessage(chatId, reply, { parse_mode: 'Markdown' });
} catch (error) {
console.error(error);
const errorMsg = error.response?.data?.error || error.message;
bot.sendMessage(chatId, `❌ Extraction failed: ${errorMsg}. Make sure the flash didn't cover the MRZ lines at the bottom.`);
}
});Step 4: Run the Bot!
It's time to test your creation.
node index.jsOpen your Telegram app, search for the bot username you created, and hit Start. Take a photo of a passport (or grab a sample image off Google) and send it into the chat.
Within seconds, you should receive a cleanly formatted message with the extracted passport details replacing the manual data entry process entirely.
Security Considerations
If you are using this in production, you must implement access controls. As written, anyone on Telegram who finds your bot's username can send a passport to it.
You should maintain a hardcoded array of allowed Telegram User IDs (msg.chat.id), and simply return early if the message originates from an unauthorized user:
const ALLOWED_USERS = [123456789, 987654321];
bot.on('message', async (msg) => {
if (!ALLOWED_USERS.includes(msg.chat.id)) {
bot.sendMessage(msg.chat.id, "Unauthorized user.");
return;
}
// ... continue processing
});Building internal automation tools doesn't have to be complicated. With just a few lines of Node.js and the ease of the Passport OCR API, you can drastically reduce the administrative burden on your field teams today.
Ready to extract passport data?
Try Passport OCR free — 10 requests per day, no signup required.