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

# Pages and slots

> Every host page a contribution can render on, and the slots, charts and tables each one has.

This is the reference for the values a contribution names: a widget names a page and a slot on
it, a tab names a page, a series names a chart, a row action names a table, and a banner names a
page. A key outside these lists fails the manifest schema, and so does a widget whose slot is not
on the page it names.

```bash theme={null}
tappify extension add widget --page analytics --slot kpi-row
```

Leave the flags off and the command offers the slots that belong to the page you picked, so a
mismatch is not possible interactively. The live values are also served at
`https://api.tappify.ai/api/v1/extensions/registry`.

## Pages

| Key           | Owners read | Route                       | Slots                               | Charts                            | Tabs | Banners |
| ------------- | ----------- | --------------------------- | ----------------------------------- | --------------------------------- | ---- | ------- |
| `overview`    | Home        | `/projects/:id/overview`    | `kpi-row`, `insights`, `sidebar`    | `installs-activity`               | yes  | yes     |
| `analytics`   | Analytics   | `/projects/:id/analytics`   | `kpi-row`, `below-chart`, `sidebar` | `installs-activity`, `conversion` | yes  | yes     |
| `deployments` | Deployments | `/projects/:id/deployments` | `sidebar`, `below-list`             | `release-cadence`                 | yes  | no      |
| `ai_chat`     | Assistant   | `chat`                      | none                                | none                              | no   | no      |

The Tabs and Banners columns are host anchors, not schema rules: a tab on `ai_chat` or a banner on
`deployments` validates, passes `doctor`, publishes and renders nothing. Check them here before
you build against a page.

`ai_chat` is a page key only for assistant contributions. Nothing renders into it as a widget or
a tab, and the assistant draws its own cards from what your tools return. Of the three pages the
Tabs column marks, the anchor is live on Analytics and Deployments; Home accepts tab
contributions and does not draw them yet.

## Slots

Every slot is the same grid, so a size that works in one works in all of them.

| Slot          | Where it is                            | Pages that have it                     |
| ------------- | -------------------------------------- | -------------------------------------- |
| `kpi-row`     | Across the top, above the main content | `overview`, `analytics`                |
| `insights`    | After the release list on Home         | `overview`                             |
| `sidebar`     | After the page's own content           | `overview`, `analytics`, `deployments` |
| `below-chart` | Under the main chart on Analytics      | `analytics`                            |
| `below-list`  | Under the release list on Deployments  | `deployments`                          |

On Analytics, `kpi-row` and `below-chart` are on the Overview tab, and `sidebar` is under the
page whichever tab is open.

A slot lays its widgets out on a grid of columns at least 240 pixels wide and rows at least 132
pixels tall, with a 12-pixel gap. A widget's `size` is how many cells it takes:

| `size` | Cells                 |
| ------ | --------------------- |
| `1x1`  | one column, one row   |
| `2x1`  | two columns, one row  |
| `2x2`  | two columns, two rows |

The column count comes from the width of the page, so a `2x1` widget is one column wide on a
narrow window. Every widget has to be readable at 320 pixels whatever size it declares. Size
against your own mount with container queries — see
[Style with host tokens](/extensions/build/style-with-host-tokens).

The host draws the card around your mount: the vendor tile, your `title`, and an Expand button
when you set `expandable`. You render the body.

## Charts

A series contribution names one of three charts, and each chart lives on one page:

| Chart               | Page                       |
| ------------------- | -------------------------- |
| `installs-activity` | `overview` and `analytics` |
| `conversion`        | `analytics`                |
| `release-cadence`   | `deployments`              |

<Note>
  The host draws a series on the chart it names, with the vendor in the legend, and a marker's
  glyph on that chart's time axis. Where the page has no host chart under that key, the vendor
  lines and markers are drawn in a card of their own on the same page. See
  [Add a connector](/extensions/build/add-a-connector).
</Note>

## Tables

A row action names one of these. Your component mounts in the expand panel with that row as
`tap.context`, opened from the row's own menu with your vendor tile beside the title.

| Table                  | Owners read | Rows are                               |
| ---------------------- | ----------- | -------------------------------------- |
| `analytics.keywords`   | Keywords    | Tracked keywords with their positions  |
| `analytics.reviews`    | Reviews     | Store reviews with ratings and replies |
| `deployments.releases` | Releases    | Releases of the owner's app            |
| `deployments.builds`   | Builds      | Builds behind those releases           |

## The filters a page publishes

`tap.filters` carries `range`, `platform` and `country`, and every mount of your install reads
the same values. The range control on the Analytics Overview tab is the only one wired to them
today: it publishes `7d`, `30d`, `90d` or `1y`, and `range.preset` carries that value for every
preset but `1y`. Elsewhere `range` holds the last value Analytics set, and `platform` and
`country` hold their defaults. Read them through `useTapFilters` and pass `range` straight into
a query — see [Follow the page's filters](/extensions/build/follow-the-filters).

## Banners and pages of your own

Banner anchors sit at the top of `overview` and `analytics`. A banner's content comes from a
webhook you declare with `as: "banner"`, which is delivered with the connector work, so a banner
contribution renders nothing yet.

A page of your own gets its own route at `/projects/:id/ext/:extensionId/:pageId`.
`tap.params.pageId` is the page you declared, `tap.params.path` is everything after it, and each
segment of that path is also its own numbered entry — `"funnels/123"` arrives as
`{ pageId: "explore", path: "funnels/123", "0": "funnels", "1": "123" }`. With `nav: true` the
page also gets an entry in the project navigation carrying your vendor tile.

## Categories

`category` places you in the Tap Store's filter. One of eighteen: `market_data`,
`subscriptions`, `product_analytics`, `crashes`, `attribution`, `experiments`, `messaging`,
`session_replay`, `localization`, `design`, `ci_cd`, `trackers`, `support`, `chat`,
`ad_monetization`, `warehouse`, `compliance`, `additional_stores`.

<Card title="Scopes" icon="key" href="/extensions/reference/scopes">
  Rendering anything on these pages needs `ui:render`.
</Card>
