{"id":49763230,"url":"https://github.com/Ambro17/slackify","last_synced_at":"2026-05-11T10:01:36.183Z","repository":{"id":57468228,"uuid":"258388484","full_name":"Ambro17/slackify","owner":"Ambro17","description":"Slackify: Lightweight framework to quickly develop modern Slack bots 🚀","archived":false,"fork":false,"pushed_at":"2020-10-03T16:27:24.000Z","size":6227,"stargazers_count":120,"open_issues_count":4,"forks_count":10,"subscribers_count":5,"default_branch":"master","last_synced_at":"2026-03-05T03:12:26.056Z","etag":null,"topics":["bot","flask","framework","modern-slack-bots","python","slack","slack-events","slack-modals","slackapi","slackify"],"latest_commit_sha":null,"homepage":"https://ambro17.github.io/slackify/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ambro17.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null}},"created_at":"2020-04-24T02:51:45.000Z","updated_at":"2026-02-08T13:31:18.000Z","dependencies_parsed_at":"2022-09-19T08:20:49.028Z","dependency_job_id":null,"html_url":"https://github.com/Ambro17/slackify","commit_stats":null,"previous_names":["ambro17/flask-slack"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/Ambro17/slackify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ambro17%2Fslackify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ambro17%2Fslackify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ambro17%2Fslackify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ambro17%2Fslackify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ambro17","download_url":"https://codeload.github.com/Ambro17/slackify/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ambro17%2Fslackify/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32889972,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-10T13:40:02.631Z","status":"online","status_checked_at":"2026-05-11T02:00:05.975Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot","flask","framework","modern-slack-bots","python","slack","slack-events","slack-modals","slackapi","slackify"],"created_at":"2026-05-11T10:00:44.115Z","updated_at":"2026-05-11T10:01:36.178Z","avatar_url":"https://github.com/Ambro17.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/Ambro17/slackify/master/docs/logopro.svg\" title=\"Logo\"\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003cimg alt=\"Build\" src=\"https://github.com/Ambro17/flask-slack/workflows/Build%20\u0026%20Test/badge.svg\"\u003e\n    \u003ca href=\"https://codecov.io/gh/Ambro17/slackify\"\u003e\n        \u003cimg alt=\"Codecov\" src=\"https://codecov.io/gh/Ambro17/flask-slack/branch/master/graph/badge.svg\"\u003e\n    \u003c/a\u003e\n    \u003cimg alt=\"pre-commit\" src=\"https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white\"\u003e\n\u003c/p\u003e\n\n# Slackify\n`Slackify` is a lightweight framework that lets you quickly develop modern Slack bots focusing in **what you want** instead of struggling with *how to do it*\n\n## Installation\n`python3 -m pip install slackify`\n\n_Requires python3.6+_\n\n## Documentation\nYou can read `Slackify` docs [here](https://ambro17.github.io/slackify/)\n\n## Quickstart\n**1. 1-Click Deploy**\n\n[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Ambro17/slackify/tree/master)\n\n\u003e The server will listen at `\u003cheroku_url\u003e/` for commands/actions and `\u003cheroku_url\u003e/slack/events` for slack events\n\n\u003e This setup uses flask builtin server which is NOT suited for production. Replace it by gunicorn or similar when ready to ship\n\n\n**2. Manual deploy**\n\nCreate a file named `quickstart.py` with the following content and then run `python quickstart.py`\n```python\nfrom time import sleep\nfrom flask import Flask\nfrom slackify import (\n    Slackify,\n    async_task,\n    reply_text\n)\n\napp = Flask(__name__)\nslackify = Slackify(app=app)\n\n\n@slackify.command\ndef hello():\n    my_background_job()\n    return reply_text('Hello from Slack!')\n\n\n@async_task\ndef my_background_job():\n    \"\"\"My long background job\"\"\"\n    sleep(15)\n    return\n\nif __name__ == '__main__':\n    app.run(host='0.0.0.0', port=5000)\n```\n\nNow the server is already running, but we need to make it reachable by slack.\nTo do so follow these steps:\n\n0. [Create a slack app](https://api.slack.com/apps?new_app=1)\n1. Download [ngrok*](https://ngrok.com/download) and run `ngrok http 5000` to create a https proxy to localhost\n2. [Create a slash command](https://api.slack.com/apps) and set the url to ngrok's https url of step `#1`\n3. Write `/hello` to your new slack bot and let the magic begin ✨\n\n\u003e*This is a development setup so you can quickly see your code changes in slack without the need to redeploy your whole site.\n\u003e Once your bot is ready for production you should update your commands url to a permanent one.\n\u003e [Heroku](https://duckduckgo.com/?q=flask+on+heroku\u0026t=brave\u0026ia=web) might be a good choice if you are just getting started as it has a generous free tier.\n\n### Features\n\n- **Slash Commands**. [Quickstart](https://github.com/Ambro17/slackify/blob/master/examples/commands.py)\n- **Global and Message Shortcuts**. [Quickstart](https://github.com/Ambro17/slackify/blob/master/examples/shortcuts.py)\n- **Interactive Actions**. [Quickstart](https://github.com/Ambro17/slackify/blob/master/examples/actions.py)\n- **Modals (a.k.a views)**. [Quickstart](https://github.com/Ambro17/slackify/blob/master/examples/views.py)\n- **Event Hooks**. [Quickstart](https://github.com/Ambro17/slackify/blob/master/examples/events.py)\n\n## Full example\nIf you want a full stack example showcasing all functionality. It includes:\n- A hello command that shows interactive buttons\n- Callbacks for each interactive button click\n- A register command that opens a new slack modal\n- A callback on modal form submission\n- A shortcut to roll a dice and get a random number\n- An event handler that echoes reactions to messages.\n- A greeting whenever someone says `hello` in a channel where the bot is present.\n\u003eRemember to `export BOT_TOKEN=xoxb-your-bot-secret` to enable slack api calls.\n\n\n```python\nimport json\nimport os\nimport random\n\nfrom flask import Flask\nfrom slackify import (\n    ACK, OK, Slackify, async_task, block_reply,\n    request, respond, text_block, Slack\n)\n\napp = Flask(__name__)\nslackify = Slackify(app=app)\ncli = Slack(os.getenv('BOT_TOKEN'))\n\n\n@slackify.command\ndef hello():\n    \"\"\"Send hello message with question and yes no buttons\"\"\"\n    YES = 'yes'\n    NO = 'no'\n    yes_no_buttons_block = {\n        \"type\": \"actions\",\n        \"elements\": [\n            {\n                \"type\": \"button\",\n                \"text\": {\n                    \"type\": \"plain_text\",\n                    \"emoji\": True,\n                    \"text\": \"Yes\"\n                },\n                \"style\": \"primary\",\n                \"value\": \"i_like_bots\",\n                \"action_id\": YES\n            },\n            {\n                \"type\": \"button\",\n                \"text\": {\n                    \"type\": \"plain_text\",\n                    \"emoji\": True,\n                    \"text\": \"No\"\n                },\n                \"style\": \"danger\",\n                \"value\": \"i_dont_like_bots\",\n                \"action_id\": NO\n            }\n        ]\n    }\n    blocks = [\n        text_block('Do you like Bots?'),\n        yes_no_buttons_block\n    ]\n    return block_reply(blocks)\n\n\n@slackify.action(\"yes\")\ndef yes(payload):\n    \"\"\"Run this if a user clicks yes on the message above\"\"\"\n    text_blok = text_block('Super! I do too :thumbsup:')\n    respond(payload['response_url'], {'blocks': [text_blok]})\n    return OK\n\n\n@slackify.action(\"no\")\ndef no(payload):\n    \"\"\"Run this if a user clicks no on the message above\"\"\"\n    text_blok = text_block('Boo! You are so boring :thumbsdown:')\n    respond(payload['response_url'], {'blocks': [text_blok]})\n    return OK\n\n\n@slackify.command\ndef register():\n    \"\"\"Open a registration popup that asks for username and password.\"\"\"\n    username_input_block = {\n        \"type\": \"input\",\n        \"block_id\": \"username_block\",\n        \"element\": {\n            \"type\": \"plain_text_input\",\n            \"placeholder\": {\n                \"type\": \"plain_text\",\n                \"text\": \"Enter your username\"\n            },\n            \"action_id\": \"username_value\"\n        },\n        \"label\": {\n            \"type\": \"plain_text\",\n            \"text\": \"👤 Username\",\n            \"emoji\": True\n        }\n    }\n    password_input_block = {\n        \"type\": \"input\",\n        \"block_id\": \"password_block\",\n        \"element\": {\n            \"type\": \"plain_text_input\",\n            \"placeholder\": {\n                \"type\": \"plain_text\",\n                \"text\": \"Enter your password\"\n            },\n            \"action_id\": \"password_value\"\n        },\n        \"label\": {\n            \"type\": \"plain_text\",\n            \"text\": \"🔑 Password\",\n            \"emoji\": True\n        }\n    }\n    modal_blocks = [\n        username_input_block,\n        password_input_block,\n    ]\n    callback_id = 'registration_form'\n    registration_form = {\n        \"type\": \"modal\",\n        \"callback_id\": callback_id,\n        \"title\": {\n            \"type\": \"plain_text\",\n            \"text\": \"My First Modal\",\n            \"emoji\": True\n        },\n        \"submit\": {\n            \"type\": \"plain_text\",\n            \"text\": \"Register\",\n            \"emoji\": True\n        },\n        \"close\": {\n            \"type\": \"plain_text\",\n            \"text\": \"Cancel\",\n            \"emoji\": True\n        },\n        \"blocks\": modal_blocks\n    }\n    cli.views_open(\n        trigger_id=request.form['trigger_id'],\n        view=registration_form\n    )\n    return OK\n\n\n@slackify.view(\"registration_form\")\ndef register_callback(payload):\n    \"\"\"Handle registration form submission.\"\"\"\n    response = payload['view']['state']['values']\n    text_blok = text_block(\n        ':heavy_check_mark: You are now registered.\\n\n        f'Form payload:\\n```{response}```'\n    )\n    send_message(cli, [text_blok], payload['user']['id'])\n    return ACK\n\n\n@async_task\ndef send_message(cli, blocks, user_id):\n    return cli.chat_postMessage(channel=user_id, user_id=user_id, blocks=blocks)\n\n\n@slackify.shortcut('dice_roll')\ndef dice_roll(payload):\n    \"\"\"Roll a virtual dice to give a pseudo-random number\"\"\"\n    dice_value = random.randint(1, 6)\n    msg = f'🎲 {dice_value}'\n    send_message(\n        cli,\n        blocks=[text_block(msg)],\n        user_id=payload['user']['id']\n    )\n    return ACK\n\n\n@slackify.event('reaction_added')\ndef echo_reaction(payload):\n    \"\"\"Adds the same reaction as the user\"\"\"\n    event = payload['event']\n    reaction = event['reaction']\n    cli.reactions_add(\n        name=reaction,\n        channel=event['item']['channel'],\n        timestamp=event['item']['ts']\n    )\n\n\n@slackify.message('hello')\ndef say_hi(payload):\n    event = payload['event']\n    cli.chat_postMessage(\n        channel=event['channel'],\n        text='Hi! 👋'\n    )\n```\n\n\n## Dependency Injection\nAs you add more and more commands you will find yourself parsing slack's request over and over again.\n\nSlackify offers shortcut for this using dependency injection.\n```python\n@slackify.command\ndef hello(command, command_args, response_url):\n    return reply_text(\n        f\"You called `{command} {command_args}`. Use {response_url} for delayed responses\"\n    )\n```\n\nYour view function will now receive the slash command, the arguments and the response_url upon invocation. Pretty cool, right?\n\nIf you are a user of pytest, this idea is similar to pytest fixtures\n\nSee [examples/injection.py](examples/injection.py) for the full example\n\n\n## Blueprint Support\nIf you already have a Flask app, you can attach\nflask functionality _slackifying_ your blueprint\n```python\n# slack_blueprint.py\nfrom slackify import Slackify, reply_text, Blueprint\n\nbp = Blueprint('slackify_bp', __name__, url_prefix='/slack')\nslackify = Slackify(app=bp)\n\n\n@slackify.command\ndef hello():\n    return reply_text('Hello from a blueprint')\n\n\n# app.py\nfrom flask import Flask\nfrom slack_blueprint import bp\n\ndef create_app():\n    app = Flask(__name__)\n    app.register_blueprint(bp)\n    return app\n\n```\n\u003e Note: You must import Blueprint from slackify instead of flask to get it working\n\n## Dependencies\nThis projects uses `Flask` as the web server and `slackclient` (_The official python slack client_) as slack's API wrapper. It also uses `pyee` for async handling of events\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAmbro17%2Fslackify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAmbro17%2Fslackify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAmbro17%2Fslackify/lists"}