# Troubleshooting

> The component does not appear, the domain is not allowed, the page's CSP blocks the loader, a tag name conflicts, or a change does not show yet. Each case with how to check it and how to fix it.

Start here when something does not work. The page never breaks when Taggor fails (the
[fallback](https://taggor.dev/docs/snippet.md#write-a-fallback) stays visible), so a problem usually looks like "my
component is not there". Find your case, run the check, apply the fix.

If a command or the API printed an error, open its page directly: every error has one at
`/docs/errors/<code>/` (the `docs_url` of the error points to it), and every build diagnostic has one at
`/docs/diagnostics/<code>/`. See [API and CLI errors](https://taggor.dev/docs/errors.md) and
[Build diagnostics](https://taggor.dev/docs/diagnostics.md).

## The component does not appear

Go down the list; the first line that does not hold is the cause.

| Check                                     | How                                                                                                                                                 | If it fails                                                                                                                                                                                                   |
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The snippet is on the page                | View the page source and look for the snippet that `node taggor.mjs sites snippet` prints (a `script` tag whose address ends in `/s/<site-key>.js`) | Paste it once per page, see [Install the snippet](https://taggor.dev/docs/snippet.md)                                                                                                                                             |
| The tag is written on the page            | The page has the component's tag, for example `<faq-accordion>`                                                                                     | Write the tag where the component should appear                                                                                                                                                               |
| The component is attached to the site     | `node taggor.mjs attach <component> --site <site>` (repeating it is safe)                                                                           | A component only reaches a page after it is attached to the site                                                                                                                                              |
| The site's environment delivers a version | `node taggor.mjs versions <component>` lists the channels and the version each points to                                                            | A `staging` site shows the version of the `staging` channel and a `production` site the version of `production`; an empty channel shows nothing. `publish` moves `staging`; only `promote` moves `production` |
| The page's domain is allowed              | Read the browser console                                                                                                                            | [The domain is not allowed](#the-domain-is-not-allowed)                                                                                                                                                       |
| Nothing blocks the loader                 | Look for a violation or a failed request in the console and the network tab                                                                         | [The page's CSP blocks the loader](#the-pages-csp-blocks-the-loader); ad blockers can also block the request                                                                                                  |
| The tag is free on the page               | `customElements.get("<tag>")` in the console                                                                                                        | [A tag name conflicts](#a-tag-name-conflicts)                                                                                                                                                                 |
| You are not looking at a cached copy      | Wait about two minutes after a publish, promote or rollback                                                                                         | [A change does not show yet](#a-change-does-not-show-yet)                                                                                                                                                     |

Taggor stays silent in the browser console on purpose when it mounts nothing (the page must stay
clean), with one exception: the allowed-domains warning below. A debug mode that explains every case is
planned but does not exist yet.

## The domain is not allowed

If the page's domain is not in the site's allowed domains, the loader mounts no component and prints one
warning in the console:

```text
taggor: this page's domain is not in the site's allowed domains, so no component was mounted.
```

The page itself keeps working, and the fallback inside each tag stays visible.

- **Add the domain to the site.** In the portal, edit the site and add the domain; from the CLI,
  `node taggor.mjs sites domains set --site <site key> --domain <hostname>` replaces the whole list (name
  every domain the site keeps), and `--domain` on `node taggor.mjs sites create` sets it for a new site. Write the hostname without scheme, port
  or path (`www.example.com`, not `https://www.example.com:8080`).
- **A plain entry matches that domain and its `www.` form only.** `example.com` does not cover
  `blog.example.com`; add `*.example.com`, which covers exactly one more label. A wildcard does not cover
  the bare domain: list both.
- **Local testing.** `localhost` is accepted in the list of a `staging` site. An empty list means "any
  page" only on a `staging` site; on a `production` site an empty list blocks everything.

The full table of cases is on [Allowed domains](https://taggor.dev/docs/edge/domains.md). The list is a guard against a
copied snippet, not access control: the loader and the bundles are public.

## The page's CSP blocks the loader

If your site sends a `Content-Security-Policy`, the browser refuses the snippet when the policy does not
allow it. The console shows a message such as `Refused to load the script … because it violates the
following Content-Security-Policy directive`. The page stays fine and the fallback is shown.

1. Give the snippet the `nonce` of the response, and allow the CDN origin of your snippet in
   `script-src`.
2. If you require Trusted Types, list the policy `taggor`.
3. Allow the CDN origin in `img-src` and `font-src` only if a component uses images or fonts, and in
   `connect-src` only if a component sends data.

The exact policy that works is on [Install the snippet](https://taggor.dev/docs/snippet.md#content-security-policy). To find
out which directive blocks, send the policy as `Content-Security-Policy-Report-Only` first and read the
violations: a `script-src-elem` violation on the CDN means the origin or the nonce is missing, a
`trusted-types` violation means `taggor` is not listed.

## A tag name conflicts

A component's tag (its Custom Element name) is its address on the page, and two things can collide.

**Two components of one site use the same tag.** The API refuses to attach the second one with
[`tag_conflict`](https://taggor.dev/docs/errors/tag_conflict.md) (HTTP 409). Detach one of the two (`node taggor.mjs detach
<component> --site <site>`) or publish one of them under another tag.

**The tag is not valid.** [`invalid_tag_name`](https://taggor.dev/docs/errors/invalid_tag_name.md) (HTTP 400): use lowercase
letters, digits and hyphens, with at least one hyphen (`my-form`). The prefix `taggor-` is reserved.

**Another script on the page already defined the tag.** The browser allows one definition per name. Taggor
never overwrites or redefines a tag: if the page already has `customElements.get("<tag>")`, the component
is not mounted and your page keeps the other script's element. Rename the tag of the component and publish
it again, or remove the other definition. A name with a prefix of your own (`acme-faq`) avoids most
collisions.

## A shadow or a focus outline is cut

Every component starts with `:host { display: block; contain: content }`, which cuts what an element
paints outside the component's own box. A button whose shadow ends in a straight line, or a focus ring
that is missing one side, is that.

- Leave room inside the component: padding on an inner wrapper, at least as large as the shadow.
- Or add `:host { contain: none }` to the component's styles, when the paint must leave the box (a
  dropdown, a tooltip, a shadow under a button that fills the component).

## A change does not show yet

The page loads the site's loader, which embeds the list of components and the version each one points to.
The browser or the CDN may keep that loader for 60 seconds, and the platform reads the site's
configuration with a cache of up to 60 seconds as well. So a publish, a `promote`, a `rollback`, a new
attach or a change of allowed domains can take up to about two minutes to reach a visitor.

- Wait two minutes, then reload the page.
- Check what the channel of the site's environment points to with `node taggor.mjs versions <component>`: if it is the version you
  expect, the platform is right and only the copy of the page is old.
- A version's code is immutable: when a component looks wrong after the channel moved, the new version is
  what you are seeing, not a stale file. Roll back with `node taggor.mjs rollback <component> --channel
<channel>`.

A rollback or a takedown is not instant for a visitor who already has the old loader, for the same two
minutes.
