Back to Blog
Guide

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.

Slack Green Team
October 2, 2026
October 6, 2026
4 min read
Share:
slack api
developers
bots

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:

Five bot messages in Slack: the default bot name and icon, then Deploy Bot with a rocket emoji, Build Status with a green W2 image from icon_url, Squirrel Ops with a custom emoji, and Missing Emoji whose avatar is the literal text :no_such_emoji_w2:

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 sentokWhat Slack stored and showed
username=Deploy BottrueName "Deploy Bot", default icon
icon_emoji=:squirrel: (custom emoji)trueThe custom emoji as the avatar
icon_emoji=:shipit: (an alias)trueStored as :shipit:
icon_emoji=rocket (no colons)trueStored as rocket, worked the same
icon_emoji=:no_such_emoji_w2:trueNo error. The avatar is the literal text of the name
icon_url to a 512 px PNGtrueSlack copied it to its own storage: icons.image_48 on slack-files2/bot_icons/...
icon_url to a URL that returns 404trueicons empty, default icon
icon_emoji and icon_url togethertrueThe emoji won, the URL was dropped
username of 81 characterstrueCut 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:

FileResult
400 x 400 PNGRefused
600 x 300 PNGRefused
2100 x 2100 PNGRefused
512 x 512 PNGAccepted and saved at once, no Save Changes needed

Each refused file showed the same line in orange:

Slack app Display Information with the error: Icons must be squares between 512px by 512px and 2000px by 2000px, please!

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:

The same bot message before and after the app icon upload: the default grey person icon became the green app icon

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.

Always Active

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

Guide

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 Green Team
Guide

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.

Slack Green Team
Guide

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.

Slack Green Team