---
outline: [2, 3, 4]
---
# Widget
Cap's client-side widget handles requesting, solving and displaying challenges using a native web component and rust-flavoured WASM. It also includes the [programmatic mode](./programmatic).
## Installation
::: code-group
```sh [pnpm]
pnpm add @cap.js/widget
```
```sh [npm]
npm i @cap.js/widget
```
```sh [bun]
bun add @cap.js/widget
```
```html [cdn]
```
:::
## Usage
The widget requires a `data-cap-api-endpoint` pointing at your Cap deployment. For Standalone instances, this is:
```
https:////
```
### Vanilla
```html
```
::: tip
When the widget lives inside a `
);
}
```
::: tip
We recommend using React 19 or later as it improves custom element event handling
:::
### Vue
```vue
```
If you're getting an unknown-component warning, add this to your `vite.config.js`:
```js
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: { isCustomElement: (tag) => tag.startsWith("cap-") },
},
}),
],
});
```
### Svelte 5
```svelte
```
### SolidJS
```jsx
import "@cap.js/widget";
export default function ContactForm() {
return (
);
}
```
### Astro
```astro
---
// ContactForm.astro
---
```
If you're rendering a React/Vue/Svelte component inside Astro, follow that framework's guide above and add `client:load` to the component.
### Preact
```jsx
import "@cap.js/widget";
export default function ContactForm() {
return (
);
}
```
### Qwik
```tsx
import { component$ } from "@builder.io/qwik";
import "@cap.js/widget";
export default component$(() => {
return (
);
});
```
## Programmatic mode
If you don't want a visible widget, for example when protecting a background action like a post submission, use the [programmatic mode](./programmatic):
```js
import Cap from "@cap.js/widget";
const cap = new Cap({
apiEndpoint: "https:////",
});
const { token } = await cap.solve();
```
## Events
All events are dispatched as CustomEvent.
| Event | When it fires | Detail |
| ---------- | ------------------------------ | ---------------------- |
| `solve` | Challenge solved successfully | `{ token: string }` |
| `progress` | Progress update during solving | `{ progress: number }` |
| `error` | An error occurred | `{ message: string }` |
| `reset` | Widget reset to initial state | `{}` |
## Options
You can also specify a custom fetch function with `window.CAP_CUSTOM_FETCH`:
```js
window.CAP_CUSTOM_FETCH = (url, params) => fetch(url, params);
```
You can also set a custom WASM url (for example the Standalone asset server's) with `window.CAP_CUSTOM_WASM_URL` or set a nonce for the CSS with `window.CAP_CSS_NONCE`
### Attributes
| Attribute | Description |
| ------------------------------ | ----------------------------------------------------------------------------- |
| `data-cap-api-endpoint` | **Required.** Your Cap endpoint: `https:////` |
| `data-cap-worker-count` | Number of solver workers (defaults to `navigator.hardwareConcurrency \|\| 8`) |
| `data-cap-hidden-field-name` | Name of the hidden token input in a `