> ## Documentation Index
> Fetch the complete documentation index at: https://developers.reintersect.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Audience and lifecycle

> Show parts of a block to specific people, lock a block when it's done, reopen it, and remove it.

> Reintersect apps are in developer preview. Names and limits can still change before general
> release.

## Audience

Every render is shared by all viewers, but parts of a block can be limited to some of them with the
`audience` prop. Use it for organizer-only controls, a reviewer's private notes or admin actions.

```tsx theme={null}
<Block summary={`${props.title}: ${state.status}`}>
  <Header>{props.title}</Header>
  <ChoiceGroup input={inputs.rsvp} label="Coming?" labels={{ yes: "Yes", no: "No" }} />
  <Callout tone="info" title="Budget" audience={{ members: props.financeMemberIds }}>
    <Text>Approved up to {props.budget}.</Text>
  </Callout>
  <Actions>
    <Button type="link" label="Open the agenda" href={props.agendaUrl} />
    <Button
      label="Cancel event"
      action={actions.cancel}
      audience="creator"
      confirm={{ title: "Cancel this event?" }}
    />
  </Actions>
</Block>
```

| Audience | Who sees it |
| - | - |
| `"creator"` | The member who inserted the block: through the slash menu, by placing an agent's block, or by running your command or message action. Blocks your app inserts through the API have no creator, so `"creator"` falls back to `"admins"`. |
| `"admins"` | Owners and admins of the block's circle, plus workspace owners and admins. |
| `{ members: [...] }` | The listed member ids, at most 50. |

### Audience per button

Inside the block's root `Actions`, each `Button` and `Menu` takes its own `audience`. In the example,
everyone sees **Open the agenda** and only the creator sees **Cancel event**. The same pattern lets
one row show **Open** to everyone and **Merge** only to admins.

* Viewers see only the buttons their audience allows.
* The primary button comes from the buttons each viewer can see: it's the first visible one that
  isn't destructive. A viewer who can't see the first button gets the next one as primary.
* When every button in the row is hidden from a viewer, the row isn't drawn for them, and no empty
  gap is left behind.
* Labels stay unique across the whole row, hidden buttons included.

`<Actions audience>` hides the whole row instead. Buttons in a `Row` can't take an `audience`; put
it on the `Row`.

### Where audience can go

* Only one level deep. A part with an `audience` can't sit inside another part with an
  `audience`. To show admins a creator-only detail, give each its own sibling part. A button with an
  `audience` can't sit in an `Actions` row that has one.
* Never inside a form. Nothing inside a `Form` may carry `audience`. Put `audience` on the `Form`
  itself, so the whole form is either shown or hidden.
* On buttons and menus, only in the root `Actions`.

`reintersect check` reports each of these, and Reintersect rejects a render that breaks them.

### How Reintersect enforces audience

Enforcement happens on the server:

* When Reintersect stores a tree, it moves every node with an `audience` out of the shared tree into a
  separate slot, including single buttons in the `Actions` row. Members who don't pass the audience
  never receive that part, so it's absent from the data their browser loads.
* Actions inside a slot are checked against the same rule on the server. A member who doesn't pass
  can't run them, even with a crafted request.
* The shared agent text, notifications and search leave out restricted text. When an agent works for
  a member who passes the audience, that member's projection includes it.
* Counts for a `ChoiceGroup` inside a slot are visible only to members who pass it.
* Images inside a slot are served only to members who pass it.

Your app should still authorize sensitive actions itself with `actor`: audience decides what members
see, while your code decides what they may change in your system.

Your render output must not contain Reintersect's internal slot nodes; the validator rejects them.

## Final blocks

An action can lock a block by returning `final`:

```ts theme={null}
export const close = defineAction(
  "close",
  { state: z.object({ closed: z.boolean() }), destructive: true },
  () => ({
    state: { closed: true },
    final: { summary: "Closed: 7 going, 2 not going" },
  }),
);
```

When a block becomes final:

* Reintersect dims every button, input, menu and form in it and says the block is final, keeps the
  last tree, and stops calling your app for that block: no more actions, renders or refreshes.
* The `summary`, if you return one, replaces the block's summary.
* Viewer inputs stop accepting picks, and the last counts stay.
* Updates through the API fail with `ReintersectAppBlockFinalError`.

### Reopening

If the block type is `reopenable: true`, the member who inserted the block or an admin can reopen it
from the lock bar under the block. Reopening clears the final flag and renders the block again on the next view.
State isn't reset, so make your render handle the state your closing action left behind. Blocks
that aren't reopenable stay final.

## Removed blocks

When the post, reply or message holding a block is deleted, or a member deletes the block from the
editor, Reintersect marks the block removed and sends your app `block.removed`. Removed blocks no
longer render, accept actions or accept API updates.

## Stale blocks

With `staleAfter` set on the block type, Reintersect renders the block again when someone views it
after that many seconds (60 seconds to 30 days). If the render fails, the old tree stays and
Reintersect tries again on a later view. Final blocks are never refreshed.

## Blocks from development installs

Blocks created by a [development install](/concepts/apps-and-installs#install) show a "Dev" label
to everyone except the developer.
Actions on them reach the developer's machine through `reintersect dev`; while it isn't running,
actions fail with an "offline" error and the last tree stays.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.