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

# Accessibility and page weight: the strife-insights element

Turn on Studio's accessibility audit and page-weight check with the strife-insights element: the results in the live preview for every editor, and in Insights and the content list on teams with Content Insights. Where to place it in Astro, Next.js, Vue and Nuxt, .NET and plain HTML, and troubleshooting.

The `<strife-insights>` element lets Studio check your site's pages: an accessibility audit, and what each page weighs. The checks run while an editor has a page open in Studio's live preview, and the results go to two places:

* **The live preview**, for every editor: the preview's toolbar shows them while the editor works.
* **Insights and the content list**, on teams with Content Insights: Studio stores the results, so the accessibility audit shows in [Insights](https://strife.app/docs/user-guide/improving-content/insights), and both checks can be filtered on in the content list.

Your site turns both checks on with the one element, placed once in your layout's body:

```html
<strife-insights hidden></strife-insights>
```

The element renders nothing and needs no script of its own. Leave it out and neither check runs, so Insights gets no accessibility data either.

## How it works

* **The checks run in your page, and only in the preview.** The preview SDK (`@strifeapp/strife`) defines the element only when the page is framed, as it is in Studio's preview, so your visitors get an empty tag. It runs the accessibility audit with [axe-core](https://github.com/dequelabs/axe-core), which it downloads only when Studio asks for an audit, so visitors never load it. It weighs the page's images and embeds from the browser's own measurements.
* **Only Studio's new interface shows them.** It asks for the audit when it connects to the page. The legacy interface never asks, and shows neither check.
* **Only on the page the editor opened.** If your site's client-side router swaps in another page inside the preview, the checks don't run there: that page's result would be shown, and stored, as the page being edited.
* **The page sends nothing anywhere itself.** It hands the results to Studio. On teams with Content Insights, Studio stores them per page and language, for Insights and the content list's Accessibility and Performance filters. The data comes from editing, not from your visitors.

## Requirements

* **`@strifeapp/strife` 1.23.0 or later** on the page. A site that loads it from a CDN without a version, such as `https://unpkg.com/@strifeapp/strife`, already runs the latest. With npm, update it: `npm install @strifeapp/strife@latest`.
* **On Astro, `@strifeapp/astro` 1.10.0 or later.** See the Astro tab below.
* **Studio's new interface** for the editor.
* **Content Insights on the team**, to store the results. Without it, editors still see them in the preview.

## Add the element

Put the element in the layout every page uses, inside `<body>`. Never put it in `<head>`: the browser ends the head at an element it doesn't know and moves everything after it into the body. `hidden` keeps the empty element out of your layout (in a grid or flex body it would take a track and a gap); the SDK still finds it. A layout rendered on the client, or inside a shadow root, works too: the checks start when the element connects.

**Astro**

```astro title="src/layouts/Layout.astro"
---
import LivePreview from '@strifeapp/astro/LivePreview.astro';
---
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <LivePreview />
  </head>
  <body>
    <slot />
    <strife-insights hidden></strife-insights>
  </body>
</html>
```

`<LivePreview />` loads the preview SDK only in Studio's preview. Use `@strifeapp/astro` 1.10.0 or later, and if your `package.json` lists `@strifeapp/strife` as well, raise it to 1.23.0 or later too. If the layout has `<Insights />`, remove it (see [Coming from the Insights component](#coming-from-the-insights-component)).

**Next.js**

```tsx title="src/app/layout.tsx"
import type { ReactNode } from 'react';

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <strife-insights hidden></strife-insights>
      </body>
    </html>
  );
}
```

Load the preview SDK as in the [Next.js tutorial](https://strife.app/docs/tutorials/next.js.md). It loads the SDK on every page, so read [Security](#security) below.

TypeScript doesn't know the tag and reports `Property 'strife-insights' does not exist on type 'JSX.IntrinsicElements'`. Declare it once, in a file your `tsconfig.json` includes:

```ts title="strife-elements.d.ts"
import type { DetailedHTMLProps, HTMLAttributes } from 'react';

declare module 'react' {
  namespace JSX {
    interface IntrinsicElements {
      'strife-insights': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
    }
  }
}
```

Keep the `import` line: without it, the file replaces React's types instead of adding to them. This works with the types for React 18 and 19. In JavaScript you need none of it.

**Vue and Nuxt**

Put the element in the component every page renders in, such as `app.vue` in Nuxt or `App.vue` in Vue:

```vue title="app.vue"
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
  <strife-insights hidden></strife-insights>
</template>
```

Vue first tries to resolve the tag as a component and warns `Failed to resolve component: strife-insights`. Tell its compiler that the tag is a custom element:

```ts title="nuxt.config.ts"
export default defineNuxtConfig({
  vue: {
    compilerOptions: {
      isCustomElement: (tag) => tag.startsWith('strife-'),
    },
  },
});
```

With Vue and Vite, the same option goes to the Vue plugin in `vite.config.ts`: `vue({ template: { compilerOptions: { isCustomElement: (tag) => tag.startsWith('strife-') } } })`.

**.NET**

```cshtml title="Views/Shared/_Layout.cshtml"
<body>
    @RenderBody()
    <strife-insights hidden></strife-insights>
</body>
```

The layout loads the preview SDK as in [Setup Real time preview](https://strife.app/docs/tutorials/getting-started/dotnet.md#5-setup-real-time-preview) in the .NET tutorial.

**HTML**

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <script type="module" src="https://unpkg.com/@strifeapp/strife"></script>
  </head>
  <body>
    …
    <strife-insights hidden></strife-insights>
  </body>
</html>
```

An address without a version always loads the latest SDK.

In any other framework the element is plain HTML. If its compiler rejects elements it doesn't know, tell it that `strife-insights` is a custom element: in Angular, add `CUSTOM_ELEMENTS_SCHEMA` to the component's `schemas`.

## Coming from the Insights component

In `@strifeapp/astro` 1.9, `<Insights />` in the head ran the accessibility audit. From 1.10.0 it renders nothing, and the SDK runs the audit itself from 1.23.0. An Astro site that still has `<Insights />` from `@strifeapp/astro` 1.9.0 or earlier gets neither check once it picks up `@strifeapp/strife` 1.23.0. Update `@strifeapp/astro` to 1.10.0 or later, remove `<Insights />` and add the element.

## Security

The element is not a security boundary: the SDK runs the checks for whatever page frames it and asks, and the audit's result includes short HTML excerpts of the page. If your site loads the SDK for every visitor and renders anything visitor-specific, load it only on preview requests (as `<LivePreview />` does on Astro), or limit who may frame your pages with `Content-Security-Policy: frame-ancestors`.

## What editors see

* **Accessibility:** a button in the preview's toolbar with the number of failing rules. It lists every rule by impact, with the failing elements: hovering one outlines it in the preview, and clicking one opens the field it renders. The audit runs once the page has connected, 1.5 s after the editor's last edit, and on the rerun button.
* **Page weight:** the page's level (Poor, Needs improvement or Great) in its own tool, with the findings split into **Your content** and **Template and code**. Only content findings set the level.
* **Stored results**, on teams with Content Insights: the accessibility audit in [Insights](https://strife.app/docs/user-guide/improving-content/insights), and both checks as the content list's **Accessibility** and **Performance** filters. A page edited since its last check shows as unchecked until it is opened in the preview again.

[Live preview](https://strife.app/docs/reference/live-preview.md#accessibility-in-the-preview) has the details of both checks: how a finding is tied to a field, what the page-weight check measures and where the sizes come from.

## Troubleshooting

* **No accessibility or page-weight button in the preview:**
  * Check that `<strife-insights>` is in the `<body>` of the page in the preview frame. Your browser's developer tools show the frame's elements.
  * Check the SDK's version: `npm ls @strifeapp/strife` lists the installed versions, and the page needs 1.23.0 or later.
  * On Astro, check that `@strifeapp/astro` is 1.10.0 or later.
  * Check that the editor uses Studio's new interface.
* **Vue or Nuxt warns `Failed to resolve component: strife-insights`:** set `isCustomElement` as in the Vue and Nuxt tab.
* **TypeScript reports `Property 'strife-insights' does not exist on type 'JSX.IntrinsicElements'`:** add the declaration from the Next.js tab.
* **The results show in the preview, but not in Insights or the content list's filters:** the team doesn't have Content Insights.
* **Insights says "No accessibility data yet for this page":** the page hasn't been checked yet. Open it in the live preview once, after the element is in place.
* **Image sizes marked ≈:** the image comes from another origin without a `Timing-Allow-Origin` header, so its size is estimated. See [Performance in the preview](https://strife.app/docs/reference/live-preview.md#performance-in-the-preview).
