Slack Bot Icon and Name Per Message: icon_emoji, icon_url and username, Tested
icon_emoji, icon_url and username only work with the chat:write.customize scope, and Slack ignores them silently without it. We tested every case on 2 October 2026, plus webhooks and the app icon upload limits.
On this page
To give one Slack bot message its own name and icon, pass username plus icon_emoji or icon_url to chat.postMessage. The bot token needs the chat:write.customize scope, and you have to reinstall the app after adding it. Without that scope Slack posts the message anyway and drops the overrides, with no error and no warning. To change the bot's icon everywhere, upload an app icon on the app's Basic Information page instead: it must be a square between 512 and 2000 pixels.
We tested each case on 2 October 2026 with a throwaway app in a test workspace, reading back every response. Here is what the overrides look like when they work:
Without chat:write.customize nothing changes
Our first install had chat:write but not chat:write.customize. We sent six messages: no override, username only, icon_emoji with a custom emoji, icon_emoji with a standard emoji, icon_url, and all three together.
curl -s https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer $SLACK_BOT_TOKEN" \
-d channel=C0C6ZRH1Z8Q \
-d text="no customize: all three" \
-d username="Deploy Bot" \
-d icon_emoji=":rocket:" \
-d icon_url="https://example.com/icon.png"
All six returned "ok": true with no warning. The returned message has no username or icons field and still carries the bot user (trimmed):
{
"user": "U0C65AARWAW",
"type": "message",
"bot_id": "B0C63G345V4",
"app_id": "A0C5Z82NNGK",
"text": "no customize: all three",
"bot_profile": {
"name": "w2-lab-1002",
"icons": {"image_48": "https://a.slack-edge.com/80588/img/plugins/app/bot_48.png"}
}
}
Adding the scope to the app settings (we did it with apps.manifest.update) was not enough. A message sent right after, before reinstalling, was still plain. After we reinstalled through OAuth, the overrides worked. The bot token string did not change on reinstall; only its scopes did, so you do not have to swap tokens in your config.
If icon_emoji is not working, check the x-oauth-scopes response header of any API call made with the token. Ours read ...,app_mentions:read,incoming-webhook before the reinstall and ...,incoming-webhook,chat:write.customize after it.
What each override did, with the scope
| What we sent | ok | What Slack stored and showed |
|---|---|---|
username=Deploy Bot | true | Name "Deploy Bot", default icon |
icon_emoji=:squirrel: (custom emoji) | true | The custom emoji as the avatar |
icon_emoji=:shipit: (an alias) | true | Stored as :shipit: |
icon_emoji=rocket (no colons) | true | Stored as rocket, worked the same |
icon_emoji=:no_such_emoji_w2: | true | No error. The avatar is the literal text of the name |
icon_url to a 512 px PNG | true | Slack copied it to its own storage: icons.image_48 on slack-files2/bot_icons/... |
icon_url to a URL that returns 404 | true | icons empty, default icon |
icon_emoji and icon_url together | true | The emoji won, the URL was dropped |
username of 81 characters | true | Cut to 50 characters, "warnings": ["username_too_long"] |
Two side effects to know about. With the scope, every message that uses an override becomes "subtype": "bot_message" with no user field, and when you set an icon but no username, the name becomes the app name (w2-lab-1002) instead of the bot user's display name (w2-lab-bot). To change those two names for good, edit the app; our Slack app name change test found that a bot name saved through App Home never reached Slack, while the manifest change showed in about 20 seconds. Code that filters messages by user will miss them, so match on bot_id or app_id. The response for an icon_url post:
{
"subtype": "bot_message",
"text": "customize: icon_url",
"username": "w2-lab-1002",
"icons": {
"image_48": "https://s3-us-west-2.amazonaws.com/slack-files2/bot_icons/2026-10-01/12194188672711_48.png"
},
"type": "message",
"bot_id": "B0C63G345V4",
"app_id": "A0C5Z82NNGK"
}
A custom emoji is the cheapest way to get a recognisable per-message icon. You can draw one in our Slack emoji maker; if it then shows as text, custom emoji not showing covers the upload side.
Never appear "away" on Slack again
Cloud-based. No downloads. Works 24/7 even when your laptop is off.
Incoming webhooks ignore all of it
We posted to the app's incoming webhook with username, icon_emoji, icon_url and channel, one at a time. Each request returned HTTP 200 ok, and each message came out with the app's own name and icon in the webhook's channel. The channel override was ignored too: the message went to the channel picked at install, not the one we named. We repeated it after adding chat:write.customize, with the old webhook URL and with the new one the reinstall created. Same result. To set a name or icon per message, post with chat.postMessage and a bot token instead; how to create a Slack webhook covers what the webhook itself can do.
Change the bot icon everywhere
Upload an app icon under Basic Information, Display Information. We tried four files:
| File | Result |
|---|---|
| 400 x 400 PNG | Refused |
| 600 x 300 PNG | Refused |
| 2100 x 2100 PNG | Refused |
| 512 x 512 PNG | Accepted and saved at once, no Save Changes needed |
Each refused file showed the same line in orange:
After the upload, bots.info returned the new icon in three sizes, image_36, image_48 and image_72, on avatars.slack-edge.com. The new icon also replaced the old one on messages the bot had already posted:
Messages sent with icon_emoji or icon_url kept their own icons. To find the bot's IDs for these calls, see Slack bot user ID.
FAQ
Can I set a bot icon with the app manifest?
No. We added an icon field to display_information and apps.manifest.validate refused it with invalid_manifest: "invalid additional property: icon". The manifest takes background_color, but the icon itself has to be uploaded on Basic Information.
Stop Jiggling Your Mouse.
Join hundreds of remote workers who never worry about their Slack status. Set it up once, stay green forever.
Related Articles
How to See All Your DMs in Slack, Including the Hidden Ones
The DMs tab lists your direct messages with people. App DMs, Slackbot and DMs with deleted accounts sit elsewhere. We compared the tab with the full list the Slack API returned.
Slack Images Not Showing? 5 Causes We Reproduced
We uploaded images to a Slack test channel and then switched each image setting off, ran /collapse, and posted from a bot that was not in the channel. Five causes, each reproduced.
How to Message Yourself on Slack (and What It Notifies)
Your own name under Direct messages opens a private DM with yourself. We sent it a note, a file, a scheduled message and a reminder, and checked which ones raised a badge.