Python Selfbots and Webhooks in Discord Pt. 1

Creating custom Discord selfbots when Discord's webhooks aren't enough.

My Inspiration

Like most of the small projects I get ideas for, this one came to me when I was bored and wanted to know if I could send a friend a message on Discord or Slack using a simple device like a Raspberry Pi.

My friends often have tech troubles and since we usually communicate over Discord or Slack. I figured it would make my life a little bit easier if I can just have them run a script and it will automatically send the results back to me through our DMs to help troubleshoot their issues.


Webhooks

This is generally the go to option if you are okay with performing smaller requests and tasks. Webhooks are quite easy to set up, but hamper the amount of control you have over your bot. Methods that use the API are favored and abide by the TOS, so if you like to live safely then this is the option for you.

See the Userbots section for more info on Discords TOS.

For instructions on creating Webhooks you can find the docs below:

Python

import requests
import json

if __name__ == '__main__':

    wekbook_url = 'https://discordapp.com/api/webhooks/.../'

    data = {
        'text': 'A message sent with the power of Python in Discord.'
    }

    response = requests.post(wekbook_url, data=json.dumps(
        data), headers={'Content-Type': 'application/json'})

    print('Response: ' + str(response.text))
    print('Response code: ' + str(response.status_code))
Sending messages in Discord with Webhook
import requests
import json

if __name__ == '__main__':

    wekbook_url = 'https://hooks.slack.com/services/{API_GUID}'

    data = {
    	'icon_emoji' = ':ghost:',
        'text': 'A message sent with the power of Python in Slack.',
        'username': 'Python Bot',
        'icon_emoji': ':robot_face:'
    }

    response = requests.post(wekbook_url, data=json.dumps(
        data), headers={'Content-Type': 'application/json'})

    print('Response: ' + str(response.text))
    print('Response code: ' + str(response.status_code))
Sending messages in Slack with Webhooks

Userbots

This method is if you want more power over what your bot can do, for example with Slack you are unable to directly mention someone when using Webhooks. However a word of warning, you can be banned for using userbots as it is explicitly against the TOS (at least for Discord).

Terms of Service | Discord
Read about Discord’s Terms of Service.
API Reference

For Discord it is likely safer to strictly use the requests module, as Discord says you will be banned for logging in with your user account (through their module/api).

Which is why I will be using the selfbot repo Zenon.


Finding your Discord Auth token:

  1. Open the Discord App
  2. Press Ctrl+Shift+I (to open Chromium dev tools)
  3. Navigate to the Application Tab -> Storage -> Local Storage -> Discord.com
  4. In the filter bar type: "token" without quotes
  5. Press Ctrl+R (refresh Discord for the token to appear)
  6. Finally highlight to copy and retrieve your token.
Copy only the value, without quotes

Install dependencies

pip3 install requests, unidecode

Here we define a few functions allowing our bot to wait for a command in your chat channel of choice and respond with a custom message, that can optionally include their username (unicode formatted).

import requests
import random
import time
from unidecode import unidecode


token = "your-token-here"
discord = "https://discordapp.com/api/v6/"
chatid = 795743570995839018

def send_message(chatid, content, proxy=None): # it can also be use as a private message
    return requests.post(discord + "channels/" + str(chatid) + "/messages#", proxies=proxy, data={"content":str(content), "nonce":str(random.randint(10000000, 99999999))}, headers={"Authorization":token}).text
	
def get_message(chatid, proxy=None):
    res = requests.get(discord + "channels/" + str(chatid) + "/messages?limit=1", proxies=proxy, headers={"Authorization":token}).text
    try:
        content = res.split('"content": "')[1].split('"')[0]
    except IndexError as e:
        content = res.split('"message": "')[1].split('"')[0],res.split('"retry_after": ')[-1].split("\n")[0]
    return content

def get_author_id(chatid, proxy=None):
    res = requests.get(discord + "channels/" + str(chatid) + "/messages?limit=1", proxies=proxy, headers={"Authorization":token}).text
    return res.split('"author":')[1].split('"id": "')[1].split('"')[0]

if __name__ == "__main__":
    while True:
        time.sleep(0.05) # To not spam the server
        message = get_message(chatid)
        if message == "!yobot":
            send_message(chatid, f"How may I help you <@{get_author_id(chatid)}>?")
        elif message[0] == "You are being rate limited.":
            print(f"Waiting off the rate limit for {int(message[1])/1000}s")
            time.sleep(int(message[1])/1000)
Responding to chat messages with custom functions

Prebuilt request functions

If you prefer to use a repo that already has prebuilt functions the Zenon repo on GitHub has a decent amount of predefined function to get you started.

Please stay tuned for updates and part 2!