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

# JavaScript API

> Identify users, open the widget from your own UI, and react to submissions.

Once the script loads, the widget exposes one global function:

```js theme={null}
window.produck(command, ...args)
```

Everything here is optional — the widget works fully with just the script tag.

| Command    | Arguments                                         | What it does                                                                         |
| ---------- | ------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `identify` | `{ userId?, email?, name? }` · `{ jwt }` · `null` | Attach the current user's identity to their feedback (or `null` to clear on logout). |
| `trigger`  | —                                                 | Open the widget from your own UI.                                                    |
| `config`   | `{ launcher?, confirmation? }`                    | Choose who owns the injected launcher and confirmation UI.                           |
| `on`       | `eventName, callback`                             | Listen for `submit`, `submit_error`, or `close`.                                     |
| `destroy`  | —                                                 | Remove the widget and its listeners from the page.                                   |

## Identify your users

Tell Produck who's giving feedback so each submission ties back to a real user instead of
being anonymous. Call `identify` once you know who they are — typically right after login.

```js theme={null}
window.produck("identify", {
  userId: "user_123",
  email: "ada@example.com",
  name: "Ada Lovelace",
});
```

All three fields are optional — send whatever you have.

### Pass a login token (JWT)

Already holding the user's session token? Hand it over and we read the standard `sub` /
`email` / `name` claims for you — one line for Supabase, Auth0, Clerk, Firebase, or Cognito:

```js theme={null}
window.produck("identify", { jwt: session.access_token });
```

We only read the claims (the signature is not verified), so this labels feedback inside your
own project — it is not an authentication check.

### Server-rendered pages (no JavaScript)

If your backend already knows the user at render time, set `data-user-*` on the script tag and
skip `identify` entirely. `data-user-jwt` works the same way if you'd rather pass a token:

```html theme={null}
<script src="https://tryproduck.com/sdk/v1.js" data-project="pk_live_YOUR_KEY"
        data-user-id="user_123" data-user-email="ada@example.com" data-user-name="Ada Lovelace" defer></script>
```

### Clear identity on logout

```js theme={null}
window.produck("identify", null);
```

If you need to identify a user before the script finishes loading, queue the call first.
The widget replays anything queued the moment it boots, so nothing is lost:

```html theme={null}
<script>
  window.produck = window.produck || function () {
    (window.produck.q = window.produck.q || []).push(arguments);
  };
  window.produck("identify", { userId: "user_123" });
</script>

<script src="https://tryproduck.com/sdk/v1.js" data-project="pk_live_YOUR_KEY" defer></script>
```

## Open the widget from your own UI

Wire up your own "Give feedback" button with `trigger`:

```js theme={null}
document.querySelector("#feedback-button").addEventListener("click", () => {
  window.produck("trigger");
});
```

## Listen for events

React when a user submits or dismisses the widget — for example, to show a thank-you toast.

```js theme={null}
window.produck("on", "submit", () => {
  showToast("Thanks for the feedback!");
});

window.produck("on", "close", () => {
  // the widget surface closed
});
```

| Event          | Fires when                                                                                                                     |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `submit`       | Feedback is successfully submitted. May fire after `close` when a failed submission is retried.                                |
| `submit_error` | A submission fails. Payload: `{ error, retry }` — call `retry()` to resubmit the same feedback (re-fires `submit` on success). |
| `close`        | The widget surface closes — after a submit, a cancel, or a failed submit.                                                      |

## Bring your own UI

The widget injects two surfaces you can take over. Each is an ownership setting, not a boolean,
so it stays meaningful as more options arrive:

| Surface        | Values             | Default                                       |
| -------------- | ------------------ | --------------------------------------------- |
| `launcher`     | `droplet` · `none` | `droplet` (the floating duck button)          |
| `confirmation` | `toast` · `none`   | `toast` (the post-submit success/error toast) |

Set `none` on a surface to suppress the built-in version and render your own. Turning a surface
off never removes capability — `trigger`, `submit`, and `submit_error` keep working.

```js theme={null}
produck("config", { launcher: "none", confirmation: "none" });

// your launcher
document.querySelector("#feedback-button").addEventListener("click", () => produck("trigger"));

// your confirmation
produck("on", "submit", () => myToast.success("Thanks!"));
produck("on", "submit_error", ({ error, retry }) => {
  myToast.error("Couldn't send — retry?", () => retry());
});
```

Set the same thing with no JavaScript using `data-*` attributes on the script tag:

```html theme={null}
<script src="https://tryproduck.com/sdk/v1.js" data-project="pk_live_YOUR_KEY"
  data-launcher="none" data-confirmation="none" defer></script>
```

To call `config` before the script finishes loading, queue it with the same stub shown above for
`identify` — the widget replays it on boot.

<Note>
  The keyboard shortcut (⌘/Ctrl + Shift + Z) still opens the widget when `launcher` is `none` — it's
  an invisible trigger, not a visible surface.
</Note>

## Clean up on logout

Call `destroy` to remove the widget when a user's session ends. On shared devices, this
keeps the next user from seeing the previous one's identity.

```js theme={null}
window.produck("destroy");
```
