pythonaiogram

How to send a bot a command via url?


I'm trying to send the bot a command with arguments via url I've seen solutions like this: https://t.me/_bot?start=my_data, but it doesn't work for me and just follows the link to the bot. Please write how to correctly generate the url for my task, and whether an additional handler is needed for this in the code


Solution

  • For t.me/<bot> you can use only some values - like start=, game=

    See doc: Deep links - Bot links


    If you use start=params then it switches to your bot
    and it executes command /start params
    and it shows button START which user has to click.

    If you use empty start= or start then it switches to your bot
    but it doesn't executes command /start.

    So you may need to put all information after start= like

    https://t.me/mybot?start=getreward-id_reward
    

    and in command start you can use - to split getreward-id_reward

    But... there is another problem. It allows only for some chars in parameters - for example it doesn't allow for + or space - so it may need to convert data to string base64

    (BTW: base64 allows to use + but telegram may have problem with + so it may need to use urlsafe_b64encode() instead of popular b64encode())

    import base64
    
    text = '++ hello world ++'
    text_base64 = base64.urlsafe_b64encode(text.encode('utf-8')).decode('utf-8')
    
    print(f'https://t.me/mybot?start={text_base64}')
    

    and later

    async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
        #print('text:', update.message.text)   # /start something
        #print('args:', context.args)          # ['something']
    
        text_base64 = context.args[0]
        text = base64.urlsafe_b64decode(text_base64.encode('utf-8')).decode('utf-8')
    
        print('text:', text)    
    
        await context.bot.send_message(chat_id=update.effective_chat.id, text=f"start params: {text}")
    

    If you want to send something more complex (like list or dict) then you may use json

    import base64
    import json
    
    data = {'method': 'xyz', 'id': 1234}
    text_json = json.dumps(data)
    text_base64 = base64.urlsafe_b64encode(text_json.encode('utf-8')).decode('utf-8')
    
    print(f'https://t.me/furasbot?start={text_base64}')
    

    and later

    async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
        #print('text:', update.message.text)   # /start something
        #print('args:', context.args)          # ['something']
    
        text_base64 = context.args[0]
        text_json = base64.urlsafe_b64decode(text_base64.encode('utf-8')).decode('utf-8')
        data = json.loads(text_json)
        
        print('data:', data)   
        print('keys:', data.keys())   
        print('method:', data['method'])   
        print('    id:', data['id'])   
     
        await context.bot.send_message(chat_id=update.effective_chat.id, text=f"start method: {data['method'}, id: {data['id']")
    

    EDIT:

    Minimal working code for tests (with python-telegram-bot):

    import os
    import logging
    from telegram import Update
    from telegram.ext import filters, ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler
    import base64
    import json
    
    def generate_link(text=None, data=None, b64=True, botname='<bot_name>'):
            
        if text:
            if b64:
                output = base64.urlsafe_b64encode(text.encode('utf-8')).decode('utf-8')
            else:
                output = text
            print(f'text: https://t.me/{botname}?start={output}')
            
        if data:
            text = json.dumps(data)
            output = base64.urlsafe_b64encode(text.encode('utf-8')).decode('utf-8')
    
            print(f'data: https://t.me/{botname}?start={output}')
    
    generate_link(botname='furasbot', text='hello-world', b64=False)
    generate_link(botname='furasbot', text='hello world')
    generate_link(botname='furasbot', data={'method': 'xyz', 'id': 1234})
    
    # ----------------------------------
    
    logging.basicConfig(
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        level=logging.INFO
    )
    
    async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
        print('text:', update.message.text)   # /start something
        print('args:', context.args)          # ['something']
        #text = str(context.args)
        
        text_base64 = context.args[0]
        
        try:
            text = base64.urlsafe_b64decode(text_base64.encode('utf-8')).decode('utf-8')
        except Exception as e:   # binascii.Error: Incorrect padding
            print('Exception:', e)
            text = text_base64
            
        try:
            data = json.loads(text)
        except Exception as e:   # json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
            print('Exception:', e)
            data = dict()
            
        print('text:', text)    
        print('data:', data)
        print('keys:', data.keys())
        for key, val in data.items():
            print(f'> {key} = {val}')
        
        await context.bot.send_message(chat_id=update.effective_chat.id, text=f"start params: {text}")
    
    if __name__ == '__main__':
        TOKEN = os.getenv('TELEGRAM_TOKEN')
        application = ApplicationBuilder().token(TOKEN).build()
        
        start_handler = CommandHandler('start', start)
        application.add_handler(start_handler)
        
        application.run_polling() 
    

    Some links:

    https://t.me/<bot_name>?start=hello-world
    https://t.me/<bot_name>?start=aGVsbG8gd29ybGQ=
    https://t.me/<bot_name>?start=eyJtZXRob2QiOiAieHl6IiwgImlkIjogMTIzNH0=