> From the [Strife developer docs](https://strife.app/docs/how-to-guides/open-in-strife-toolbar). Every page is listed in [llms.txt](https://strife.app/docs/llms.txt).

# Open in Strife: a toolbar on your site

Editors who browse your public site can open the page they are looking at in Strife. `@strifeapp/strife` ships a small toolbar for that: a small island at the right edge of the page that unfolds to **Redigera i Strife** (or *Edit in Strife*) and a **×**, rendered only in browsers that have been *connected* to Strife. Visitors never see it. Nothing runs on your server.

## How it works

* **Connecting happens once per browser.** An editor opens a page of the site from Studio with the play button. The new tab still knows the window that opened it, so the toolbar script offers it a connection (`postMessage`), Studio answers, and the script sets a first-party cookie, `strife-toolbar=1`, for 30 days. Nothing travels in the address. A page opened any other way, from a bookmark or the address bar, has no one to ask and stays as it is.
* **The cookie carries no privileges.** It only decides whether the toolbar renders. Opening Strife goes through Strife's own login and the editor's team membership.
* **Clicking the toolbar** opens `api.strife.app/toolbar/open` in a new tab, which lands in Studio on the document behind the page. If nothing on the team owns the page, Studio opens on the team's content list.
* **The ×** removes the cookie from that browser. Opening a page from Studio again connects it again.
* **Nothing reaches your server.** The handshake happens between the two browser tabs, so access logs, caches and analytics never see a marker. A site without the toolbar never answers Studio, so nothing happens there at all. Studio's preview iframe never connects and never shows the toolbar.

## Requirements

* `@strifeapp/strife` 1.11.1 or later.
* The team's registered site domains must include every host the site is served on (for example both `golf.se` and `www.golf.se`): the page's host is how Strife finds the team, and how it resolves a bare page URL. Only a page that passes both `team` and `document-id` needs no registered host.

## Add the element

Put the element in your layout and import the module once. The decision to render is made in the browser, so this is safe on cached and static pages. Import the module unconditionally and early, not behind a consent manager's auto-blocking: Studio waits about a minute for the page to answer, and a module that only runs after a consent click misses it.

```astro
---
// src/layouts/Layout.astro
const { pageData } = Astro.locals;
---
<strife-toolbar document-id={pageData?.docId}></strife-toolbar>
<script>
  import '@strifeapp/strife/toolbar-element';
</script>
```

| Attribute     | Required | Meaning                                                                                                                                                                                                                                                   |
| ------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `team`        | no       | The team id. Without it, Strife resolves the team from the page's host among the editor's own teams. Pass it to skip the host lookup; together with `document-id` the host need not be registered at all.                                                                                     |
| `document-id` | no       | The Strife content document id of the page, the one Studio shows in the editor URL. In `Content/ByUrl*` index rows that is usually the `docId` field, not the row's own `id`. Preferred: Strife opens exactly that document, which also covers virtual sub-pages. Without it, Strife resolves the page URL through the content index. |
| `api`         | no       | The Strife API origin. Defaults to `https://api.strife.app`.                                                                                                                                                                                              |
| `lang`        | no       | Language of the toolbar's labels. Defaults to the page's `<html lang>`: Swedish for `sv`, English for everything else.                                                                                                                                  |

The element renders only when the cookie is present, the page is top-level (not framed) and the URL does not carry `?token=`. Collapsed it is a small tab on the right edge with the Strife mark; hovering, focusing or tapping it unfolds two icon actions with tooltips, **edit in Strife** and **hide**. The tooltips use native Interest Invokers (`interestfor` + `popover="hint"`) in Chrome and Edge 142+, and a built-in fallback elsewhere. Style it from outside with `strife-toolbar::part(island)`, `::part(mark)`, `::part(edit)`, `::part(hide)` and `::part(tooltip)`, or move it with a rule on `strife-toolbar` itself (it is `position: fixed`, vertically centred on the right edge by default).

## Cookies and consent

`strife-toolbar` is a first-party, host-only cookie holding the value `1`, set by the toolbar script after the editor arrived from Strife. Classify it as a necessary/functional cookie in your consent tool.

## Limitations

* The handshake is not signed. Any page that opens your site with `window.open` can make the toolbar appear in that browser; the button only leads to Strife's login, so nothing is exposed.
* Safari caps script-set cookies to seven days of Safari use without a visit to the site. An editor who browses the site weekly keeps the connection; otherwise she opens the page from Studio again.
* Multi-language sites open in the editor's current locale, not necessarily the locale of the page.

## Troubleshooting

* **The toolbar never appears after opening the page from Studio**: the page must be top-level (not framed), the address must not carry `?token=`, and the tab must still know its opener. A site that sends `Cross-Origin-Opener-Policy` (`same-origin` or `same-origin-allow-popups`), or a script that clears `window.opener` before the toolbar module runs, severs the connection; so does closing the Studio tab before the page has loaded. After a play, `document.cookie` should contain `strife-toolbar=1`.
* **Clicking lands on the content list instead of the document**: pass `document-id`, or register the host the site is served on for the team.
* **`None of your teams is registered for …`**: the editor is not a member of a team that has this host registered. Register the host, or pass `team` together with `document-id`.
