# Troubleshooting

The widget isn't showing, comments won't save, notifications aren't arriving — in the order the causes actually occur.

Source: https://docs.annot8.app/docs/troubleshooting



## The widget doesn't appear [#the-widget-doesnt-appear]

Work down this list. The first item accounts for most cases.

<Steps>
  <Step>
    ### The hostname matches no environment [#the-hostname-matches-no-environment]

    The widget refuses to load on a hostname you haven't authorised, and it does so
    silently.

    Go to **Project → Settings → Environments** and confirm a pattern covers the
    host you're on. For local development, add:

    ```
    localhost *.local 127.0.0.1
    ```

    Ports are ignored, so `localhost` covers `localhost:3000` and `localhost:5173`.
    If you're on a `.test` domain, a LAN IP, or a tunnel URL from ngrok or
    Cloudflare, add that pattern too.
  </Step>

  <Step>
    ### You're on a production host [#youre-on-a-production-host]

    By default the entire widget panel is hidden on production. Turn on **Show
    widget in production** in **Project → Settings → Features**, or test on a
    non-production environment.

    An environment counts as production if it's the project's default or is named
    "Production".
  </Step>

  <Step>
    ### The script didn't load [#the-script-didnt-load]

    In the console:

    ```js
    typeof window.Annot8 === "function";
    ```

    `false` means the tag never ran. Check the Network tab for `widget.js`, and
    check your CSP allows `https://www.annot8.app` in `script-src`.

    `true` with no launcher means the project or environment check rejected the
    page — go back to step 1.
  </Step>

  <Step>
    ### CSP is blocking the iframe [#csp-is-blocking-the-iframe]

    All widget UI runs in an iframe. Without `frame-src https://www.annot8.app` the
    loader runs and nothing appears. See
    [Installation → CSP](/docs/installation#content-security-policy).
  </Step>

  <Step>
    ### The values are wrong [#the-values-are-wrong]

    `data-project-id` and `data-convex-url` must be the ones from **your** project's
    Installation page. A key copied from another workspace fails the origin check.

    The loader also validates: a malformed project key, a non-HTTPS backend URL, or
    a URL carrying credentials is discarded rather than used.
  </Step>

  <Step>
    ### The tag is in the wrong place [#the-tag-is-in-the-wrong-place]

    It has to run on every route, not inside a page component that only mounts
    sometimes. In a React or Next.js app, put it in the root layout.
  </Step>
</Steps>

## The widget appears but comments won't save [#the-widget-appears-but-comments-wont-save]

* **Sign-in popup blocked.** Team members sign in through a popup. Allow popups
  for your site.
* **Guest limit reached.** On the Free plan, the fourth distinct guest reviewer
  is refused with a message in the widget. Upgrade, or have reviewers sign in.
* **Monthly thread cap reached.** The Free plan allows 50 threads per calendar
  month. Existing threads stay readable; new ones resume next month or on
  upgrade.
* **CSP blocking the backend.** `connect-src` needs
  `https://*.convex.cloud https://*.convex.site`.

## Screenshots are blank or missing [#screenshots-are-blank-or-missing]

* Very large or complex pages can exceed the 12-second render budget. The thread
  is still submitted, just without the image.
* Cross-origin images and iframes can't be rendered into the screenshot; they
  come out blank. That's a browser restriction, not a bug.
* Screenshots over 8 MB are rejected. This is rare and generally means an
  extremely large viewport.

## Screen recording isn't offered [#screen-recording-isnt-offered]

* It's a **Pro** feature.
* It needs browser support for `getDisplayMedia`, which most mobile browsers
  don't have.
* The browser prompts for permission; a previous denial is remembered and has to
  be cleared in site settings.

## Notifications aren't arriving [#notifications-arent-arriving]

**Personal email** — check your preferences in **Notifications**, check spam,
and confirm quiet hours aren't suppressing delivery.

**Integrations** — check, in order:

1. Is the integration toggled on for **this project**?
2. Does the integration's last-delivery status show an error?
3. Does **Test** succeed?
4. Is the credential still valid? Slack and Discord webhooks die with their
   channel; GitHub and GitLab tokens expire.
5. Is the subscription still active? Integrations stop on a lapsed plan.

**Browser push** — push is registered per device. Allowing it on your laptop
doesn't cover your phone.

## The live chat AI agent isn't replying [#the-live-chat-ai-agent-isnt-replying]

Nearly always the audience gate. Visitor-facing AI requires the project's
**audience** in **Settings → Configuration** to be **Business users aged 18+**,
*and* visitor AI enabled on the deployment. See
[AI features](/docs/ai/overview#visitor-facing-ai-is-gated).

Then check: is live chat enabled, is the AI assistant turned on, and is its
reply mode **Always** rather than **Offline** — because in Offline mode it only
steps in outside your team availability hours.

## An invitation is refused but the team looks small [#an-invitation-is-refused-but-the-team-looks-small]

Pending invitations occupy seats. Used seats = members + pending invites. Revoke
the stale ones, or add seats in **Billing**.

## Old feedback has disappeared [#old-feedback-has-disappeared]

Plan retention limits how far back the inbox reaches — 14 days on Free, 90 on
Pro. The inbox tells you how many open threads are hidden. Nothing was deleted;
upgrading brings them back.

## Analytics shows nothing [#analytics-shows-nothing]

Both conditions are required:

1. **Analytics** enabled in **Project → Settings → Features**.
2. `data-analytics-consent="true"` passed from the page, or `init` called with
   `analyticsConsent: true`.

`track` and `trackConversion` are silent no-ops until both hold.

## Still stuck [#still-stuck]

Email [support@annot8.app](mailto:support@annot8.app) with your project name,
the page URL, your browser, and anything in the console. If the widget loads but
misbehaves, the console output is usually the fastest route to an answer.
