How to detect when user clicks inline keyboard button in Telegram bot?

I’m working on a Telegram bot using python-telegram-bot library and I have a problem with button interactions.

I created an inline keyboard with a URL button that sends users to an external website. The issue is that I need to track when someone actually presses this button so I can trigger some actions in my code.

Here’s my current setup:

btn_text = 'Visit Site'
url_button = InlineKeyboardButton(btn_text, url='https://example.com', callback_data='user_clicked')
keyboard_layout = [[url_button]]
markup = InlineKeyboardMarkup(keyboard_layout)
bot.send_message(chat_id=user_id, text='Please click the button below to continue', reply_markup=markup)

Is there a way to capture this button press event? I want to execute some code when the user interacts with the button. Any help would be great!

Here’s another workaround that worked for me - use a webapp button instead of a URL button. Set web_app={'url': 'your_redirect_url'} and handle the webapp data callback. It’s a bit more complex but you get the tracking you need without losing the smooth user experience.

URL buttons in Telegram don’t trigger callbacks - they simply redirect users to the link without notifying your bot. When you set both url and callback_data, Telegram ignores the callback_data. I encountered this same issue when building a bot last year. The solution I implemented involved creating a redirect endpoint on my server. Instead of linking directly to the external site, I pointed the URL button to my server, logged the click, and then redirected the user to the actual destination using a 302 status. Hence, your button should look like this: url='https://yourserver.com/redirect?destination=https://example.com&user_id=123'. This redirect endpoint can handle the tracking, ensuring a reliable process for thousands of clicks in production.

URL buttons bypass your bot completely once clicked - that’s the core problem. I switched to regular callback buttons instead when I needed tracking. Drop the url parameter and just use callback_data='user_clicked'. Then handle it with a callback query handler that opens the URL programmatically or sends it as a follow-up message. Your handler would be @bot.callback_query_handler(func=lambda call: call.data == 'user_clicked') and you can run your tracking code inside before sending another message with the actual link. You’ll lose the seamless redirect but you’ll catch every interaction, which sounds like what you’re after.

This topic was automatically closed 4 days after the last reply. New replies are no longer allowed.