Back to Blog
Guide

Slack App Home Tab: views.publish, Events and Errors, Tested

We built a Slack App Home tab with views.publish in a test workspace and recorded the app_home_opened payload, every error a bad view returned, and what users see when the Messages tab is off or read-only.

Slack Green Team
October 1, 2026
October 7, 2026
4 min read
Share:
slack api
developers
block kit

To show a Slack App Home tab, turn on the Home tab in your app settings, then call views.publish with a bot token, the user_id of the person, and a view whose type is home. Slack stores one Home view per user, and the user sees it the next time they open your app. We built one on 1 October 2026 in our own test workspace and recorded every response below.

Slack web app showing the sglabw1 app with the Home tab selected: a "Team dashboard" header, "Open tickets: 4", "On call: @sieun", a green Refresh button and the context line "Published with views.publish"

Turn on the Home tab

In the app manifest the switch sits under features.app_home:

features:
  app_home:
    home_tab_enabled: true
    messages_tab_enabled: true
    messages_tab_read_only_enabled: false
  bot_user:
    display_name: sglabw1
settings:
  event_subscriptions:
    bot_events:
      - app_home_opened

The same switches are on the App Home page of your app settings. The app_home_opened event needs no extra scope. If you build the app from a manifest, our Slack app manifest guide has a full file that we installed.

Publish a view with views.publish

This is the script we ran, with slack_sdk:

import os
from slack_sdk import WebClient

client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])

view = {
    "type": "home",
    "blocks": [
        {"type": "header", "text": {"type": "plain_text", "text": "Team dashboard"}},
        {"type": "section", "text": {"type": "mrkdwn", "text": "*Open tickets:* 4\n*On call:* <@U0B7L4YK420>"}},
        {"type": "divider"},
        {"type": "actions", "elements": [
            {"type": "button", "text": {"type": "plain_text", "text": "Refresh"},
             "action_id": "refresh_home", "style": "primary"}]},
        {"type": "context", "elements": [{"type": "mrkdwn", "text": "Published with views.publish"}]},
    ],
}

resp = client.views_publish(user_id="U0B7L4YK420", view=view)
print(resp["ok"], resp["view"]["id"], resp["view"]["hash"])

Output:

True V0C5YL86W9F 1790839317.uuOv5mY7

The screenshot at the top is that view in Slack web. We published it before the user had ever opened the app, and it was there on the first open, so you do not have to wait for app_home_opened before the first publish.

Three details from the same run:

  • • A user token (xoxp-) returns {"ok": false, "error": "not_allowed_token_type"}. Only the bot token can publish a Home view.
  • • Sending JSON with a plain Content-Type: application/json header worked but added "warning": "missing_charset" to every response. application/json; charset=utf-8 removed it. slack_sdk sets the header for you; in Postman you set it yourself, as in our Postman collection.
  • • A form-encoded call with view as a JSON string also returned ok: true.

The app_home_opened event

Slack sent this to our Events API Request URL when we opened the app. We trimmed the view object to five of its fields; the full payload repeats the whole view we had published.

{
  "type": "event_callback",
  "event": {
    "type": "app_home_opened",
    "user": "U0B7L4YK420",
    "channel": "D0C5UMYKNKG",
    "tab": "home",
    "view": {
      "id": "V0C5YL86W9F",
      "type": "home",
      "hash": "1790838694.plCBUVng",
      "root_view_id": "V0C5YL86W9F",
      "app_id": "A0C5WFY5P7C"
    },
    "event_ts": "1790838702.833620"
  },
  "event_id": "Ev0C5YL9BAMP",
  "event_time": 1790838702
}

Opening the Messages tab sends the same event with "tab": "messages" and no view key:

{
  "type": "app_home_opened",
  "user": "U0B7L4YK420",
  "channel": "D0C5UMYKNKG",
  "tab": "messages",
  "event_ts": "1790838745.267589"
}

The view.hash field is useful. Pass it back as hash in your next views.publish, and Slack rejects the update if the view changed in between. We sent a stale hash and got {"ok": false, "error": "hash_conflict"}. Modals follow the same rule with views.update, and there the error also returns the current view, as our modal test shows.

Never appear "away" on Slack again

Cloud-based. No downloads. Works 24/7 even when your laptop is off.

Errors from a bad view

Every one of these came back with "error": "invalid_arguments" and the detail in response_metadata.messages. Each list started with [ERROR] failed to match all allowed schemas [json-pointer:/view]; the table shows the line after it:

What we sentresponse_metadata.messages
A view with "type": "modal"[ERROR] unsupported type: modal [json-pointer:/view/type]
A view with no type[ERROR] missing required field: type [json-pointer:/view]
101 blocks[ERROR] no more than 100 items allowed [json-pointer:/view/blocks]
A header with 151 characters[ERROR] must be less than 151 characters [json-pointer:/view/blocks/0/text/text]
A section with 3,001 characters[ERROR] must be less than 3001 characters [json-pointer:/view/blocks/0/text/text]

A wrong user ID gives the same error code. user_id=U00000000 and user_id=U0123456789 (well-formed, no such user) both returned:

{"ok": false, "error": "invalid_arguments", "response_metadata": {"messages": ["[ERROR] invalid `user_id`"], "warnings": ["missing_charset"]}}

A view with exactly 100 blocks published fine. The json-pointer tells you which block broke the view; in a long view, count from zero. For the same limits in messages, see invalid_blocks and Block Kit limits.

Turn off the Messages tab

With messages_tab_enabled: false the Messages tab disappears and the app shows only Home and About:

The sglabw1 app header in Slack with only two tabs, Home and About, after messages_tab_enabled was set to false

While it was off, chat.postMessage from the bot to the user returned {"ok": false, "error": "messages_tab_disabled"}, whether we passed the user ID or the DM channel ID. So a Home-only app cannot DM its users.

With messages_tab_enabled: true and messages_tab_read_only_enabled: true, the bot can still post, but the user gets no composer:

The app's Messages tab with a bot message and, in place of the message box, the line "Sending messages to this app has been turned off."

The user token in the same read-only DM got {"ok": false, "error": "restricted_action_read_only_channel"}. Both changes took effect after a page reload, with no reinstall.

FAQ

Can I publish one Home view for every user at once?

No. views.publish takes one user_id per call. To change the tab for everyone, call it once per user, within the method's rate limit.

Does adding an AI assistant change the App Home?

Yes. When we added features.assistant_view to the manifest, the tabs became Home, Chat, History and About, and the app got an AGENT label. With agent_view the DM kept its Messages tab, and the thread status calls behaved as in our agents.sessions.setStatus test. The events each feature sends are compared in Slack agent_view vs assistant_view.

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